Created
January 16, 2019 14:37
-
-
Save taotao54321/a3fc363203831742b32f8eb0cced886e to your computer and use it in GitHub Desktop.
内藤九段将棋秘伝 (FC) 思考トレース for FCEUX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
内藤九段将棋秘伝 (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