Skip to content

Instantly share code, notes, and snippets.

@taotao54321
Created January 16, 2019 14:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save taotao54321/a3fc363203831742b32f8eb0cced886e to your computer and use it in GitHub Desktop.
Save taotao54321/a3fc363203831742b32f8eb0cced886e to your computer and use it in GitHub Desktop.
内藤九段将棋秘伝 (FC) 思考トレース for FCEUX
--[[
内藤九段将棋秘伝 (FC) 思考トレース for FCEUX
ログはサブディレクトリ trace/ 内に出力される(予め mkdir すること)
--]]
----------------------------------------------------------------------
-- util
----------------------------------------------------------------------
local function mem_read_u8(addr)
return memory.readbyte(addr)
end
local out = nil
local function trace_init()
local path = os.date("trace/%Y%m%d-%H%M%S.log")
out = io.open(path, "w")
assert(out)
return out
end
local function trace_fin()
if out then
out:close()
out = nil
end
end
local function print(s)
if s ~= nil then
out:write(s)
end
out:write("\n")
end
----------------------------------------------------------------------
-- game
----------------------------------------------------------------------
-- sq: マス目 [12,108]
-- pt: 駒種 [1,15] ただし 11 は無効
-- pcp: PLAYER駒 [1,15] ただし 11 は無効
-- pcc: COM駒 [16,30] ただし 26 は無効
-- dropp: PLAYERが駒を打つ手の移動元マス目 [213,219] ((駒種)+211)
-- dropc: COMが駒を打つ手の移動元マス目 [201,207] (209-(駒種))
local function sq2xy(sq)
local x = sq % 11
local y = math.floor(sq / 11)
return x, y
end
local function xy2sq(x, y)
return x + 11*y
end
local function sq_is_ok(sq)
local x, y = sq2xy(sq)
return 1 <= x and x <= 9 and 1 <= y and y <= 9
end
local function pt_is_ok(pt)
return 1 <= pt and pt <= 15 and pt ~= 11
end
local function pt_unpromote(pt)
if 9 <= pt and pt <= 15 and pt ~= 11 then
pt = pt - 7
end
return pt
end
local function pcp2pt(pcp)
return pcp
end
local function pcp_is_ok(pcp)
return pt_is_ok(pcp2pt(pcp))
end
local function pcc2pt(pcc)
return pcc - 15
end
local function pcc_is_ok(pcc)
return pt_is_ok(pcc2pt(pcc))
end
local function dropp_is_ok(dropp)
return 213 <= dropp and dropp <= 219
end
local function dropp2pt(dropp)
return dropp - 211
end
local function dropc_is_ok(dropc)
return 201 <= dropc and dropc <= 207
end
local function dropc2pt(dropc)
return 209 - dropc
end
local function board_player()
local board = {}
for i = 1, 121 do
board[i] = mem_read_u8(0x03A9 + i-1)
end
return board
end
local function board_com()
local board = {}
for i = 1, 121 do
board[i] = mem_read_u8(0x049B + i-1)
end
return board
end
local function hand_player()
local hand = {}
for i = 1, 7 do
hand[i] = mem_read_u8(0x058D + i-1)
end
return hand
end
local function hand_com()
local hand = {}
for i = 1, 7 do
hand[i] = mem_read_u8(0x0594 + i-1)
end
return hand
end
local function effect_player()
local eff = {}
for i = 1, 121 do
eff[i] = mem_read_u8(0x0422 + i-1)
end
return eff
end
local function effect_com()
local eff = {}
for i = 1, 121 do
eff[i] = mem_read_u8(0x0514 + i-1)
end
return eff
end
local function move_player()
local is_promote = mem_read_u8(0x05BF) ~= 0
local src = mem_read_u8(0x05A2)
local dst = mem_read_u8(0x05A1)
local board = board_player()
local pt = pcp2pt(board[dst+1])
if is_promote then
pt = pt_unpromote(pt)
end
local is_drop = dropp_is_ok(src)
if is_drop then
assert(dropp2pt(src) == pt)
assert(not is_promote)
end
return src, dst, pt, is_drop, is_promote
end
local function move_cand()
local is_promote = mem_read_u8(0x0279) ~= 0
local src = mem_read_u8(0x0277)
local dst = mem_read_u8(0x0276)
local pt = pcc2pt(mem_read_u8(0x5F))
local is_drop = dropc_is_ok(src)
if is_drop then
assert(dropc2pt(src) == pt)
assert(not is_promote)
end
return src, dst, pt, is_drop, is_promote
end
local function move_best()
local is_promote = mem_read_u8(0x028C) ~= 0
local src = mem_read_u8(0x0285)
local dst = mem_read_u8(0x0284)
local board = board_com()
local pt = pcc2pt(board[dst+1])
if is_promote then
pt = pt_unpromote(pt)
end
local is_drop = dropc_is_ok(src)
if is_drop then
assert(dropc2pt(src) == pt)
assert(not is_promote)
end
return src, dst, pt, is_drop, is_promote
end
local KANDIGIT = {
"一", "二", "三", "四", "五", "六", "七", "八", "九",
}
local PT_NAME = {
"玉",
"飛",
"角",
"金",
"銀",
"桂",
"香",
"歩",
"竜",
"馬",
nil,
"全",
"圭",
"杏",
"と",
}
local function sq_str(sq)
local file, rank = sq2xy(sq)
file = 10 - file -- 将棋の表記法に合わせる
return string.format("%d%d", file, rank)
end
local function hand_str(hand)
local res = ""
for i,n in ipairs(hand) do
local pt = i + 1
if n > 0 then
res = res .. string.format("%s%d ", PT_NAME[pt], n)
end
end
return res
end
local function position_str(boardp, boardc, handp, handc)
local res = ""
local append = function(s)
res = res .. s .. "\n"
end
append("▽持駒: " .. hand_str(handc))
append(" 9 8 7 6 5 4 3 2 1")
append("┌──┬──┬──┬──┬──┬──┬──┬──┬──┐")
for y = 1, 9 do
local line = "│"
for x = 1, 9 do
local sq = xy2sq(x,y)
local pcp = boardp[sq+1]
local pcc = boardc[sq+1]
if pcp_is_ok(pcp) and pcc == 0 then
line = line .. "▲" .. PT_NAME[pcp2pt(pcp)]
elseif pcp == 0 and pcc_is_ok(pcc) then
line = line .. "▽" .. PT_NAME[pcc2pt(pcc)]
elseif pcp == 0 and pcc == 0 then
line = line .. "__"
else
assert(false)
end
line = line .. "│"
end
line = line .. KANDIGIT[y]
append(line)
if y ~= 9 then
append("├──┼──┼──┼──┼──┼──┼──┼──┼──┤")
end
end
append("└──┴──┴──┴──┴──┴──┴──┴──┴──┘")
append("▲持駒: " .. hand_str(handp))
return res
end
local function effect_str(effp, effc)
local res = ""
local append = function(s)
res = res .. s .. "\n"
end
append(" 9 8 7 6 5 4 3 2 1")
append("┌──┬──┬──┬──┬──┬──┬──┬──┬──┐")
for y = 1, 9 do
local line = "│"
for x = 1, 9 do
local sq = xy2sq(x,y)
line = line .. string.format("%d,%d ", effp[sq+1], effc[sq+1])
line = line .. "│"
end
line = line .. KANDIGIT[y]
append(line)
if y ~= 9 then
append("├──┼──┼──┼──┼──┼──┼──┼──┼──┤")
end
end
append("└──┴──┴──┴──┴──┴──┴──┴──┴──┘")
return res
end
local function move_str(src, dst, pt, is_drop, is_promote)
local dst_file, dst_rank = sq2xy(dst)
dst_file = 10 - dst_file -- 将棋の表記法に合わせる
if is_drop then
return string.format("%d%d%s打", dst_file, dst_rank, PT_NAME[pt])
else
local src_file, src_rank = sq2xy(src)
src_file = 10 - src_file
local spromo = is_promote and "成" or ""
return string.format("%d%d%s%s (%d%d)",
dst_file, dst_rank, PT_NAME[pt], spromo,
src_file, src_rank)
end
end
local function U8VAR(name, addr)
return function()
return string.format("%s: %d", name, mem_read_u8(addr))
end
end
local VARS = {
adv_score = U8VAR("adv_score", 0x0272),
adv_sq = function()
local sq = mem_read_u8(0x0273)
local s = sq_is_ok(sq) and sq_str(sq) or "NONE"
return string.format("adv_sq: %d (%s)", sq, s)
end,
best_adv_score = U8VAR("best_adv_score", 0x0286),
best_adv_sq = function()
local sq = mem_read_u8(0x0287)
local s = sq_is_ok(sq) and sq_str(sq) or "NONE"
return string.format("best_adv_sq: %d (%s)", sq, s)
end,
best_disadv_score = U8VAR("best_disadv_score", 0x0288),
best_disadv_sq = function()
local sq = mem_read_u8(0x0289)
local s = sq_is_ok(sq) and sq_str(sq) or "NONE"
return string.format("best_disadv_sq: %d (%s)", sq, s)
end,
best_score = U8VAR("best_score", 0x028A),
cand_offer = U8VAR("cand_offer", 0x027C),
cand_score = U8VAR("cand_score", 0x0278),
dangling_pawn_lance = U8VAR("dangling_pawn_lance", 0x05DF),
disadv_score = U8VAR("disadv_score", 0x0274),
disadv_sq = function()
local sq = mem_read_u8(0x0275)
local s = sq_is_ok(sq) and sq_str(sq) or "NONE"
return string.format("disadv_sq: %d (%s)", sq, s)
end,
effect = function()
return effect_str(effect_player(), effect_com())
end,
formation = U8VAR("formation", 0x05BE),
mate_player = U8VAR("mate_player", 0x05DD),
move_best = function()
local src, dst, pt, is_drop, is_promote = move_best()
return string.format("move_best: %s", move_str(src, dst, pt, is_drop, is_promote))
end,
move_cand = function()
local src, dst, pt, is_drop, is_promote = move_cand()
return string.format("move_cand: %s", move_str(src, dst, pt, is_drop, is_promote))
end,
move_player = function()
local src, dst, pt, is_drop, is_promote = move_player()
return string.format("move_player: %s", move_str(src, dst, pt, is_drop, is_promote))
end,
num_dragon_player = U8VAR("num_dragon_player", 0x05E8),
num_loose_com = U8VAR("num_loose_com", 0x0297),
num_move2 = U8VAR("num_move2", 0x05C1),
num_promoted_com = U8VAR("num_promoted_com", 0x0293),
player_offer = U8VAR("player_offer", 0x05DE),
position = function()
return position_str(board_player(), board_com(), hand_player(), hand_com())
end,
progress = U8VAR("progress", 0x028E),
root_adv_score = U8VAR("root_adv_score", 0x0280),
root_disadv_score = U8VAR("root_disadv_score", 0x0282),
root_rbp_com = U8VAR("root_rbp_com", 0x05EA),
root_power_com = U8VAR("root_power_com", 0x05E4),
root_power_player = U8VAR("root_power_player", 0x05E7),
safety_far_com = U8VAR("safety_far_com", 0x0295),
surround_com = U8VAR("surround_com", 0x05E5),
threat_far_com = U8VAR("threat_far_com", 0x0296),
threat_far_player = U8VAR("threat_far_player", 0x0299),
threat_near_com = U8VAR("threat_near_com", 0x05EB),
zzz_02A4 = U8VAR("$02A4", 0x02A4),
zzz_02A6 = U8VAR("$02A6 (best $02A4)", 0x02A6),
zzz_05E0 = U8VAR("$05E0", 0x05E0),
zzz_05E2 = U8VAR("$05E2 (best $05E0)", 0x05E2),
}
local function dump(name)
print(VARS[name]())
end
----------------------------------------------------------------------
-- hook
----------------------------------------------------------------------
local HOOKS = {
{
addr = 0xDD07,
func = function()
print("==== 思考開始 ====")
dump("num_move2")
dump("progress")
dump("formation")
dump("move_player")
print()
dump("position")
dump("effect")
end,
},
{
addr = 0xF00A,
func = function()
print("---- ルート局面評価完了 ----")
dump("num_dragon_player")
dump("root_rbp_com")
dump("root_power_player")
dump("root_power_com")
dump("root_adv_score")
dump("root_disadv_score")
dump("player_offer")
end,
},
{
addr = 0xF282,
func = function()
print()
dump("move_cand")
dump("cand_score")
dump("cand_offer")
dump("adv_sq")
dump("adv_score")
dump("disadv_sq")
dump("disadv_score")
dump("num_promoted_com")
dump("num_loose_com")
dump("dangling_pawn_lance")
dump("safety_far_com")
dump("threat_far_player")
dump("threat_far_com")
dump("threat_near_com")
dump("surround_com")
dump("zzz_02A4")
dump("zzz_05E0")
print()
end,
},
{
addr = 0xF2AB,
func = function()
print("打ち歩詰めなので却下")
end,
},
{
addr = 0xF2C2,
func = function()
print("$F2C2: --$05E0")
dump("zzz_05E0")
end,
},
{
addr = 0xF2D8,
func = function()
print("タダ捨てなので却下")
end,
},
{
addr = 0xF2E3,
func = function()
print("player_offer == 2 なので cand_score += 2")
dump("cand_score")
end,
},
{
addr = 0xF2EE,
func = function()
print("垂れ歩/垂れ香あり。$05E0 += 4")
dump("zzz_05E0")
end,
},
{
addr = 0xF31F,
func = function()
print("最大駒損マスがCOM玉から遠い。$05E0 -= disadv_score")
dump("zzz_05E0")
end,
},
{
addr = 0xF674,
func = function()
print("---- 候補手評価完了 ----")
dump("mate_player")
dump("cand_score")
dump("adv_sq")
dump("adv_score")
dump("disadv_sq")
dump("disadv_score")
dump("zzz_02A4")
dump("zzz_05E0")
end,
},
{
addr = 0xF768,
func = function()
print("---- 最善手更新 ----")
dump("move_best")
dump("best_score")
dump("best_adv_sq")
dump("best_adv_score")
dump("best_disadv_sq")
dump("best_disadv_score")
dump("zzz_02A6")
dump("zzz_05E2")
end
},
}
----------------------------------------------------------------------
-- main
----------------------------------------------------------------------
local function main()
trace_init()
emu.registerexit(trace_fin)
for _, hook in ipairs(HOOKS) do
memory.registerexec(hook.addr, hook.func)
end
end
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment