Advertisement
Guest User

Beetle Mania bot

a guest
Mar 31st, 2012
560
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.29 KB | None | 0 0
  1. --x position of ith shell (0<=i<=69)
  2. function shellx(i)
  3.     x=memory.readbyte(0x404088+22*i)
  4.     return x
  5. end
  6.  
  7. --y position of ith shell
  8. function shelly(i)
  9.     y=memory.readbyte(0x40408B+22*i)
  10.     return y
  11. end
  12.  
  13. --Finds the middle of the path, given the desired position j
  14. function findmiddle(cango,i,j)
  15.     local k=j
  16.     while cango[i][k-2] do
  17.         k=k-2
  18.     end
  19.     min = k
  20.  
  21.     k=j
  22.     while cango[i][k+2] do
  23.         k=k+2
  24.     end
  25.     max = k
  26.  
  27.     middle=(min+max)/2
  28.     middle=2*math.floor(middle/2)
  29.     return middle
  30. end
  31.  
  32. function sign(x)
  33.     if x>0 then
  34.         return 1
  35.     elseif x<0 then
  36.         return -1
  37.     else
  38.         return 0
  39.     end
  40. end
  41.  
  42. function autorecover()
  43.     local lastpress=1
  44.     while memory.readbyte(0x8030e6)>0 do
  45.         if lastpress==1 then
  46.             joypad.set(1,{A=true})
  47.             emu.frameadvance()
  48.             lastpress=0
  49.         else
  50.             joypad.set(1,{B=true})
  51.             emu.frameadvance()
  52.             lastpress=1
  53.         end
  54.     end
  55. end
  56.  
  57. function lookahead()
  58.     emu.speedmode("maximum")
  59.     local state1=savestate.create()
  60.     savestate.save(state1)
  61.     local startframe=emu.framecount()
  62.     local dodge={{}}
  63.     local lastvals={{}}     --Last x and y coordinates of all shells
  64.     for i=0,69 do
  65.         lastvals[i]={-1,-1}
  66.     end
  67.     for i=1,1200 do     --Look 20 seconds into the future
  68.         for j=0,69 do       --Check all 70 shells
  69.             moved=not(shellx(j)==lastvals[j][1] and shelly(j)==lastvals
  70.  
  71. [j][2])     --Must check if shell moved since dead shells don't refresh
  72.             if moved and shelly(j)>195 and shelly(j)<250 then      
  73.  
  74. --If the shell hits the ground
  75.                 if not(dodge[i]) then
  76.                     dodge[i]={}
  77.                 end
  78.                 for k=shellx(j)-17,shellx(j)+17 do
  79.                     dodge[i][k]=true
  80.                 end
  81.             end
  82.             lastvals[j]={shellx(j),shelly(j)}
  83.         end
  84.         memory.writebyte(0x404000,1)
  85.         memory.writebyte(0x8030e6,0)        --invincibility
  86.         emu.frameadvance()
  87.     end
  88.     savestate.load(state1)
  89.     emu.speedmode("normal")
  90.     return dodge, startframe
  91. end
  92.  
  93.  
  94. function showpercolation(dodge,cango,x)
  95.     local i=next(dodge)
  96.     while dodge[i] do
  97.         local j=next(dodge[i])
  98.         while dodge[i][j] do
  99.             gui.pixel(j+7,200-i,"white")
  100.             j=next(dodge[i],j)
  101.         end
  102.         i=next(dodge,i)
  103.     end
  104.  
  105.     for i = 1,#cango-1 do
  106.         local j=next(cango[i])
  107.         for j=0,table.maxn(cango[i]) do
  108.             if cango[i][j] then
  109.                 gui.pixel(j+7,200-i,"magenta")
  110.             end
  111.         end
  112.     end
  113.  
  114.     for i = 1,#x do
  115.         gui.pixel(x[i]+7,200-i,"blue")
  116.     end
  117.  
  118.     emu.pause()
  119. end
  120.  
  121. function percolate(dodge)
  122.     cango={{}}
  123.     cango[1][memory.readbyte(0x404004)]=true
  124.    
  125.     i=2
  126.     while cango[i-1] and not(i>table.maxn(dodge)) do
  127.         for j=0,238 do      --Playing field is 238 units wide.  The
  128.  
  129. beetle can access odd values by going to 239, but these are excluded for simplicity.
  130.             --if not(dodge[i]) or not(dodge[i][j]) and cango[i-1][j]
  131.  
  132. then
  133.             if cango[i-1][j] then
  134.                 if not(cango[i]) then
  135.                     cango[i]={}
  136.                 end
  137.  
  138.                 cango[i][j-2]=not(dodge[i]) or not(dodge[i][j-2])  
  139.  
  140.     --Go left
  141.                 cango[i][j]=not(dodge[i]) or not(dodge[i][j])      
  142.  
  143. --Stay still
  144.                 cango[i][j+2]=not(dodge[i]) or not(dodge[i][j+2])  
  145.  
  146.     --Go right
  147.             end
  148.         end
  149.         i=i+1
  150.     end
  151.  
  152.     local j=0
  153.     local x={}
  154.     while not(cango[#cango-1][j]) do        --Exclude both nil and false
  155.         j=j+2
  156.     end
  157.     x[#cango-1]=findmiddle(cango,#cango-1,j)
  158.  
  159.     local xx=0
  160.     for i=2,#cango-1 do
  161.         if cango[#cango-i][x[#cango-i+1]-2] then
  162.             xx=x[#cango-i+1]-2
  163.         elseif cango[#cango-i][x[#cango-i+1]] then
  164.             xx=x[#cango-i+1]
  165.         elseif cango[#cango-i][x[#cango-i+1]+2] then
  166.             xx=x[#cango-i+1]+2
  167.         end
  168.         middle=findmiddle(cango,#cango-i,xx)
  169.         x[#cango-i]=x[#cango-i+1]+2*sign(middle-x[#cango-i+1])
  170.     end
  171.  
  172.     --showpercolation(dodge,cango,x)
  173.  
  174.     return x
  175. end
  176.  
  177. --Moves beetle according to x acquired from percolation
  178. function move(x,start,depth)
  179.     local press={}
  180.     for i=start,depth do
  181.         if x[i] and x[i+1] then
  182.             press={}
  183.             if x[i]<x[i+1] then
  184.                 press={right=true}
  185.             elseif x[i]>x[i+1] then
  186.                 press={left=true}
  187.             end
  188.             joypad.set(1,press)
  189.             emu.frameadvance()
  190.         end
  191.     end
  192.     --emu.pause()
  193. end
  194.  
  195. function copyvector(vector)
  196.     local vectorcopy={}
  197.     for k, v in pairs(vector) do
  198.         vectorcopy[k]=v
  199.     end
  200.     return vectorcopy
  201. end
  202.  
  203. function hdectodec(number)
  204.     local place={[0]=0}
  205.     local i=0
  206.     while not(number==0) do
  207.         place[i]=number%16
  208.         number = number-place[i]
  209.         number = number/16
  210.         i=i+1
  211.     end
  212.  
  213.     local output=0
  214.     for i=0,#place do
  215.         output=output+place[i]*10^i
  216.     end
  217.     return output
  218. end
  219.  
  220. --Flips the endianness and turns a vector of bytes into a single, large hexadecimal
  221.  
  222. value
  223. function flipendian(hexvector)
  224.     local L=#hexvector
  225.     local output=0
  226.     for i = 1,L do
  227.         output = output+hexvector[i]*256^(i-1)
  228.     end
  229.     return output
  230. end
  231.  
  232. function getscore()
  233.     score=memory.readbyterange(0x8030f0,4)
  234.     score=flipendian(score)
  235.     score=hdectodec(score)
  236.     return score
  237. end
  238.  
  239. function getinputs()
  240.     state2 = savestate.create()
  241.     savestate.save(state2)
  242.     local buttons={}
  243.     local i=1
  244.     while memory.readbyte(0x8030e6)==0 do
  245.         buttons[i]=joypad.get(1)
  246.         i=i+1
  247.         emu.frameadvance()
  248.     end
  249.     savestate.load(state2)
  250.     return buttons, state2
  251. end
  252.  
  253. function findbest2(buttons, state)
  254.     --emu.speedmode("maximum")
  255.     local scorestart=getscore()
  256.     local framestart=emu.framecount()
  257.     local bestrate=0
  258.     local besti=1
  259.     for i = 1,#buttons do
  260.         for j = 1,i do
  261.             local press=copyvector(buttons[j])
  262.             if i==j then
  263.                 press["B"]=true
  264.             end
  265.             joypad.set(1,press)
  266.             emu.frameadvance()
  267.         end
  268.         framecountdown=120      --120 frames (2 seconds) for the
  269.  
  270. first star to leave the field
  271.         score = getscore()
  272.         while framecountdown>0 do
  273.             memory.writebyte(0x8030e6,0)
  274.             if getscore()>score then        --If the score
  275.  
  276. increased
  277.                 framecountdown=60       --Reset the counter
  278.                 score=getscore()
  279.             else
  280.                 framecountdown=framecountdown-1
  281.             end
  282.             emu.frameadvance()
  283.         end
  284.  
  285.         local deltascore=score-scorestart
  286.         local time = emu.framecount()-framestart
  287.         local rate=deltascore/time
  288.         print(i, rate)
  289.         if rate>bestrate then
  290.             bestrate=rate
  291.             besti=i
  292.         end
  293.         savestate.load(state)
  294.     end
  295.     print(besti, bestrate)
  296.     --emu.speedmode("normal")
  297.     return besti
  298. end
  299.  
  300. function findbest(x)
  301.     emu.speedmode("maximum")
  302.     local state1=savestate.create()     --Return to this state after finding
  303.  
  304. the best
  305.     local state2=savestate.create()     --Save and load this state for
  306.  
  307. efficiency when checking depth
  308.     savestate.save(state1)
  309.     savestate.save(state2)
  310.     local scorestart=getscore()
  311.     local framestart=emu.framecount()
  312.     local bestrate=0
  313.     local besti=0
  314.     local doneflag=false
  315.  
  316.     for depth=1,#x-1 do
  317.         savestate.load(state2)
  318.         move(x,depth,depth)
  319.         savestate.save(state2)
  320.         joypad.set(1,{B=true})
  321.  
  322.         local framecountdown=120
  323.         local score=getscore()
  324.         while framecountdown>0 do
  325.             memory.writebyte(0x404000,1)        --Invincibility,
  326.  
  327. just for the purposes of checking score efficiently
  328.             if getscore()>score then        --If the score
  329.  
  330. increased
  331.                 framecountdown=60       --Reset the counter
  332.                 score=getscore()
  333.             else
  334.                 framecountdown=framecountdown-1
  335.             end
  336.             emu.frameadvance()
  337.         end
  338.  
  339.         if score==99999999 then     --If the score is maxed out
  340.             doneflag=true
  341.         end
  342.  
  343.         local deltascore=score-scorestart
  344.         local time = emu.framecount()-framestart
  345.         local rate=deltascore/time
  346.         print(depth, rate)
  347.         if rate>bestrate then
  348.             bestrate=rate
  349.             bestdepth=depth
  350.         end
  351.     end
  352.  
  353.     savestate.load(state1)
  354.     emu.speedmode("normal")
  355.  
  356.     return bestdepth, doneflag
  357. end
  358.  
  359. function makeitso(x,bestdepth,doneflag)
  360.     move(x,1,bestdepth)
  361.     joypad.set(1,{B=true})
  362.  
  363.     if not(doneflag) then
  364.         local framecountdown=120
  365.         local score=getscore()
  366.         while framecountdown>0 do
  367.             if getscore()>score then        --If the score
  368.  
  369. increased
  370.                 framecountdown=60       --Reset the counter
  371.                 score=getscore()
  372.             else
  373.                 framecountdown=framecountdown-1
  374.             end
  375.             emu.frameadvance()
  376.             if memory.readbyte(0x404000)==5 then
  377.                 autorecover()
  378.             end
  379.         end
  380.     end
  381.     if doneflag then
  382.         emu.frameadvance()
  383.         emu.pause()
  384.     end
  385. end
  386.  
  387. while true do
  388.     dodge=lookahead()
  389.     x=percolate(dodge)
  390.     bestdepth,doneflag=findbest(x)
  391.     makeitso(x,bestdepth,doneflag)
  392. end
  393.  
  394. --Byte i030E5 is the "damage" byte.  This is the number of times you have to press
  395.  
  396. A/B to recover.
  397. --If this byte exceeds 146 you will lose (can't recover in time).
  398. --Byte i030E6 is the "recovery" byte.  When this byte reaches 0, the beetle
  399.  
  400. recovers.
  401. --Byte s04088: shell 1's horizontal position.
  402. --Byte s0408B: shell 1's vertical position.
  403. --Byte s0409E: shell 2's horizontal position.
  404. --Byte s040A1: shell 2's vertical position.
  405. --Byte s04004: Beetle position.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement