Guest User

Untitled

a guest
Jul 18th, 2016
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.98 KB | None | 0 0
  1. --[[
  2. ミニパット (FC) HIO探索スクリプト
  3.  
  4. カーソルを初期位置から動かしていない状態で起動すること
  5.  
  6. ログはサブディレクトリ log/ 内に出力される(予め mkdir すること)
  7. --]]
  8.  
  9.  
  10. ----------------------------------------------------------------------
  11. -- util
  12. ----------------------------------------------------------------------
  13.  
  14. local function mem_read_u8(addr)
  15.     return memory.readbyte(addr)
  16. end
  17.  
  18. local function mem_write_u8(addr, value)
  19.     memory.writebyte(addr, value)
  20. end
  21.  
  22. local function mem_read_u16_le(addr)
  23.     local lo = mem_read_u8(addr)
  24.     local hi = mem_read_u8(addr+1)
  25.     return bit.bor(lo, bit.lshift(hi, 8))
  26. end
  27.  
  28. local function mem_write_u16_le(addr, value)
  29.     local lo = bit.band(value, 0xFF)
  30.     local hi = bit.band(bit.rshift(value, 8), 0xFF)
  31.     mem_write_u8(addr, lo)
  32.     mem_write_u8(addr+1, hi)
  33. end
  34.  
  35. local function play(input, n)
  36.     if n == nil then n = 1 end
  37.     for i = 1, n do
  38.         joypad.set(1, input)
  39.         emu.frameadvance()
  40.     end
  41. end
  42.  
  43.  
  44. ----------------------------------------------------------------------
  45. -- log
  46. ----------------------------------------------------------------------
  47.  
  48. local out = nil
  49.  
  50. local function out_init()
  51.     local path = os.date("log/%Y%m%d-%H%M%S.log")
  52.  
  53.     out = io.open(path, "w")
  54.  
  55.     return out and true or false
  56. end
  57.  
  58. local function out_fin()
  59.     if out then
  60.         out:close()
  61.         out = nil
  62.     end
  63. end
  64.  
  65. local function info(msg)
  66.     out:write(msg)
  67.     out:write("\n")
  68.     out:flush()
  69. end
  70.  
  71.  
  72. ----------------------------------------------------------------------
  73. -- game
  74. ----------------------------------------------------------------------
  75.  
  76. local function get_course()
  77.     return mem_read_u8(0x04FC)
  78. end
  79.  
  80. local function get_hole()
  81.     return mem_read_u8(0x04FD)
  82. end
  83.  
  84. local function get_ball_pos()
  85.     local x = mem_read_u16_le(0xAB)
  86.     local y = mem_read_u16_le(0xAD)
  87.     return { x, y }
  88. end
  89.  
  90. local function set_power(power)
  91.     mem_write_u8(0x054E, power)
  92. end
  93.  
  94. local function set_curve(curve)
  95.     mem_write_u8(0x054D, curve)
  96. end
  97.  
  98. local function get_cursor()
  99.     local x = mem_read_u16_le(0x9B)
  100.     local y = mem_read_u16_le(0x9D)
  101.     return { x, y }
  102. end
  103.  
  104. local function set_cursor(cursor)
  105.     mem_write_u16_le(0x9B, cursor[1])
  106.     mem_write_u16_le(0x9D, cursor[2])
  107. end
  108.  
  109. --[[
  110. local function miniputt_sgn(value)
  111.     if value > 0 then
  112.         return 1
  113.     elseif value < 0 then
  114.         return 0xFF
  115.     else
  116.         return 0
  117.     end
  118. end
  119.  
  120. local function set_vec(vec)
  121.     for i = 0, 1 do
  122.         mem_write_u8(0x8B + i, miniputt_sgn(vec[1+i]))
  123.         mem_write_u16_le(0x97 + 2*i, math.abs(vec[1+i]))
  124.     end
  125. end
  126. --]]
  127.  
  128.  
  129. ----------------------------------------------------------------------
  130. -- 探索部
  131. ----------------------------------------------------------------------
  132.  
  133. local function shoot(power, curve, vec)
  134.     -- カーソル位置に vec を加算
  135.     local cursor = get_cursor()
  136.     cursor[1] = cursor[1] + vec[1]
  137.     cursor[2] = cursor[2] + vec[2]
  138.     set_cursor(cursor)
  139.  
  140.     -- 書き換えたカーソル位置を反映させる
  141.     play({})
  142.  
  143.     -- パワー、カーブ設定用フック
  144.     memory.registerexec(0xD30C, function()
  145.         set_power(power)
  146.     end)
  147.     memory.registerexec(0xD364, function()
  148.         set_curve(curve)
  149.     end)
  150.  
  151.     -- ボールを打つ操作
  152.     play({ A = 1 }) -- スイング開始
  153.     play({}, 10)
  154.     play({ A = 1 }) -- パワー決定
  155.     play({}, 6)
  156.     play({ A = 1 }) -- カーブ決定
  157.  
  158.     memory.registerexec(0xD364, nil)
  159.     memory.registerexec(0xD30C, nil)
  160. end
  161.  
  162. local function is_success()
  163.     local result = false
  164.     local done = false
  165.  
  166.     -- カーソル座標が書き換えられたらカップインしなかったとみなす
  167.     -- FIXME: これだとやや待ち時間が長い
  168.     memory.registerwrite(0x9B, function()
  169.         done = true
  170.     end)
  171.  
  172.     while not done do
  173.         -- ポインタ $047E が $E0E1 を指していればカップインとみなす
  174.         -- (左下の絵がカップイン時のものになっているはず)
  175.         local ptr_047E = mem_read_u16_le(0x047E)
  176.         if ptr_047E == 0xE0E1 then
  177.             result = true
  178.             done = true
  179.         end
  180.  
  181.         play({})
  182.     end
  183.  
  184.     memory.registerwrite(0x9B, nil)
  185.  
  186.     return result
  187. end
  188.  
  189. local function power_is_valid(power)
  190.     return 0x9D <= power and power <= 0xD3 and power%2 == 1
  191. end
  192.  
  193. local function curve_is_valid(curve)
  194.     return 0x10 <= curve and curve <= 0x40 and curve%2 == 0
  195. end
  196.  
  197. -- あまりにカーソルが近すぎると打てない
  198. local function vec_is_valid(vec)
  199.     local abs_x = math.abs(vec[1])
  200.     local abs_y = math.abs(vec[2])
  201.  
  202.     return (abs_x > 2 or abs_y > 2) or (abs_x == 2 and abs_y == 2)
  203. end
  204.  
  205. local function print_result(power, curve, vec, result)
  206.     info(string.format(
  207.         "0x%02X\t0x%02X\t%d\t%d\t%d",
  208.         power, curve, vec[1], vec[2], result and 1 or 0
  209.     ))
  210. end
  211.  
  212. local function timestamp()
  213.     return os.date("%Y/%m/%d %H:%M:%S")
  214. end
  215.  
  216. local function search(power_range, curve_range, vecx_range, vecy_range)
  217.     assert(power_is_valid(power_range[1]) and power_is_valid(power_range[2]))
  218.     assert(curve_is_valid(curve_range[1]) and curve_is_valid(curve_range[2]))
  219.  
  220.     info(string.format("# SEARCH START (%s)", timestamp()))
  221.  
  222.     local ball_pos = get_ball_pos()
  223.     info(string.format("# hole: %d-%d", 1+get_course(), 1+get_hole()))
  224.     info(string.format("# ball: (%d,%d)", ball_pos[1], ball_pos[2]))
  225.     info("")
  226.  
  227.     info(string.format("# power: [0x%02X,0x%02X]", power_range[1], power_range[2]))
  228.     info(string.format("# curve: [0x%02X,0x%02X]", curve_range[1], curve_range[2]))
  229.     info(string.format("# vecx: [%d,%d]", vecx_range[1], vecx_range[2]))
  230.     info(string.format("# vecy: [%d,%d]", vecy_range[1], vecy_range[2]))
  231.     info("")
  232.  
  233.     local count = 0
  234.  
  235.     local state = savestate.object()
  236.     savestate.save(state)
  237.  
  238.     for vecx = vecx_range[1], vecx_range[2] do
  239.         for vecy = vecy_range[1], vecy_range[2] do
  240.             local vec = { vecx, vecy }
  241.             if vec_is_valid(vec) then
  242.                 for power = power_range[1], power_range[2], 2 do
  243.                     for curve = curve_range[1], curve_range[2], 2 do
  244.                         savestate.load(state)
  245.  
  246.                         shoot(power, curve, vec)
  247.                         local result = is_success()
  248.                         print_result(power, curve, vec, result)
  249.  
  250.                         count = count + 1
  251.                     end
  252.                 end
  253.             end
  254.         end
  255.     end
  256.  
  257.     info("")
  258.     info(string.format("# SEARCH END (%s) count=%d", timestamp(), count))
  259. end
  260.  
  261.  
  262. ----------------------------------------------------------------------
  263. -- main
  264. ----------------------------------------------------------------------
  265.  
  266. local function init()
  267.     if not out_init() then
  268.         print("Can't open file")
  269.         return false
  270.     end
  271.  
  272.     emu.speedmode("maximum")
  273.     --emu.setrenderplanes(false, false)
  274.  
  275.     return true
  276. end
  277.  
  278. local function fin()
  279.     --emu.setrenderplanes(true, true)
  280.     emu.speedmode("normal")
  281.  
  282.     out_fin()
  283. end
  284.  
  285. local function main()
  286.     if not init() then
  287.         print("init() failed")
  288.         return
  289.     end
  290.     emu.registerexit(fin)
  291.  
  292.     -- カーソルが範囲外だとボールが止まらなくなることがあるので注意
  293.  
  294.     search(
  295.         { 0x9D, 0x9D }, -- power
  296.         { 0x10, 0x10 }, -- curve
  297.         { -41, 50 }, -- vecx
  298.         { -50, 50 }  -- vecy
  299.     )
  300.     --[[
  301.     search(
  302.         { 0x9D, 0x9D }, -- power
  303.         { 0x10, 0x10 }, -- curve
  304.         { -2, 2 }, -- vecx
  305.         { -2, 2 }  -- vecy
  306.     )
  307.     --]]
  308.  
  309.     --[[
  310.     search(
  311.         { 0x9D, 0xD3 }, -- power
  312.         { 0x10, 0x40 }, -- curve
  313.         { -2, 2 }, -- vecx
  314.         { -2, 2 }  -- vecy
  315.     )
  316.     --]]
  317.  
  318.     -- "Stop" を押さなくてもログ出力は完了してほしい
  319.     fin()
  320.  
  321.     emu.pause()
  322. end
  323.  
  324. main()
Add Comment
Please, Sign In to add comment