Sml 使用相互递归求解组合博弈
这是一场典型的不偏不倚的比赛。两名玩家轮流拾取标记为1到n的棍子,只要拾取了1号棍子,游戏就结束了。规则很简单:PlayerA倒计时到5,然后选择相应的棍子;普拉耶拉数到2,然后拿起相应的棍子。程序试图找到一个初始点,以便最后拾取1号杆 我试图在列表上循环,找出哪个初始位置会给出令人满意的结果,但返回的值似乎不正确。代码有什么问题Sml 使用相互递归求解组合博弈,sml,combinatorics,game-theory,Sml,Combinatorics,Game Theory,这是一场典型的不偏不倚的比赛。两名玩家轮流拾取标记为1到n的棍子,只要拾取了1号棍子,游戏就结束了。规则很简单:PlayerA倒计时到5,然后选择相应的棍子;普拉耶拉数到2,然后拿起相应的棍子。程序试图找到一个初始点,以便最后拾取1号杆 我试图在列表上循环,找出哪个初始位置会给出令人满意的结果,但返回的值似乎不正确。代码有什么问题 fun play(stick) = let val stick_list = n_list(stick) (*n_list(8) will ge
fun play(stick) =
let
val stick_list = n_list(stick)
(*n_list(8) will generate an int list [1,2,3,4,5,6,7,8]*)
fun playerA(x::nil, n) = x
| playerA(stick_list, n) =
let
val pos = (n + (5 mod size(stick_list))) mod size(stick_list)
in
playerB(delete(stick_list, pos), pos)
end
and playerB(x::nil, n) = x
| playerB(stick_list, n) =
let
val pos = (n + (~2 mod size(stick_list))) mod size(stick_list)
in
playerA(delete(stick_list, pos), pos)
end
fun search(n) = if playerA(stick_list, n - 1) = 1 then n + 1 else search(n - 1)
in
search(stick - 1)
end;
以下是一些建议: n_list很容易实现为list.tablate stick,fn i=>i+1。 在处理列表时使用长度而不是大小。 考虑记住剩下的棍子数,这样就不需要重新计算长度。例如
fun play nSticks =
let val allSticks = List.tabulate (nSticks, fn i => i + 1)
fun playerA ([stick], _, n) = stick
| playerA (sticks, sticksLeft, n) =
let val pos = (n + (5 mod sticksLeft)) mod sticksLeft
in
playerB (delete (sticks, pos), sticksLeft - 1, pos)
end
...
除非这是一个相互递归的练习,否则如果您将两个玩家函数合并为一个,您似乎可以避免多次重复,例如
datatype Player = PlayerA | PlayerB
fun player (_, stick::_, 0) = stick
| player (player, sticks, sticksLeft, pos) = ...
let val (newPos, otherPlayer) =
case player of
PlayerA => ((n + 5) mod sticksLeft, PlayerB)
| PlayerB => ((sticksLeft + n - 2) mod sticksLeft, PlayerA)
val newSticks = delete (sticks, pos)
in player (otherPlayer, newSticks, sticksLeft - 1, newPos) end
但这不是真正的问题。我想你的意思是,这不是问题的主要症结所在。您需要能够解释代码的实际错误,而不是无法获得预期的反馈。有了它,您不仅能够以简洁的方式表达代码中的错误,您的测试的读者将确切地知道预期的结果,而且编写测试的过程将让您洞察可能出现的错误。