这是一种典型的公正游戏。两名玩家轮流挑选从1到n标记的棍棒,每当1号棍被挑选时,游戏就结束了。规则很简单:PlayerA倒数到5并选择相应的棒; PlayerA最多可以计算2并选择相应的棒。该程序试图找到一个初始点,以便最后一次选择No.1棒。
我尝试遍历列表并找到哪个初始位置会给出令人满意的结果,但似乎返回值不对。代码有什么问题??
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;
答案 0 :(得分:0)
以下是一些建议:
n_list
很容易实现为List.tabulate (stick, fn i => i + 1)
。length
而不是size
。考虑记住留下的木棒数量,因此不需要重新计算长度。 E.g。
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