【发布时间】:2020-08-10 12:38:36
【问题描述】:
我感觉我从根本上误解了 Haskell 的编写方式。我的代码旨在作为游戏 Othello 的原始 AI 的评估函数。本质上,我希望我的代码在一个片段列表中循环,每个片段由一个由位置(Int,Int)和一个 Col(颜色,黑色或白色)组成的元组表示,并给出一个预期的移动来确定移动的好坏是。
我判断移动价值的方式基于几个因素:
- 棋盘上是否有一块与预定位置成直线的同色棋子?
- 如果前面的要求为真,那两块之间有多少相反颜色的块?
由于 Haskell 没有循环结构,我似乎需要递归地实现它,因此我的代码如下:
eval :: Position -> [(Position, Col)] -> Col -> GameState -> Int -> Int
eval move pieces moveColour gameState score = do
let moveX = fst move
let moveY = snd move
let piece = head(pieces)
let pieceColour = snd piece
let pieceX = fst fst piece
let pieceY = snd fst piece
if (moveColour == pieceColour) then
if (moveX == pieceX) then
if (moveY > pieceY) then
let newScore = score + (countOtherColour 0 moveY pieceY (pieces gameState) moveColour 0)
--recurse
if (tail(pieces) == []) then
return newScore
else
return eval move tail(pieces) moveColour gameState newScore
else
let newScore = score + (countOtherColour 0 pieceY moveY (pieces gameState) moveColour 0)
--recurse
if (tail(pieces) == []) then
return newScore
else
return eval move tail(pieces) moveColour gameState newScore
else
if (moveY == pieceY) then
if (moveX > pieceX) then
let newScore = score + (countOtherColour 1 moveX pieceX (pieces gameState) moveColour 0)
--recurse
if (tail(pieces) == []) then
return newScore
else
return eval move tail(pieces) moveColour gameState newScore
else
let newScore = score + (countOtherColour 1 pieceX moveX (pieces gameState) moveColour 0)
--recurse
if (tail(pieces) == []) then
return newScore
else
return eval move tail(pieces) moveColour gameState newScore
else
--recurse
if (tail(pieces) == []) then
return score
else
return eval move tail(pieces) moveColour gameState score
else
--recurse
if (tail(pieces) == []) then
return score
else
return eval move tail(pieces) moveColour gameState score
countOtherColour :: Int -> Int -> Int -> [(Position, Col)] -> Col -> Int -> Int
countOtherColour xyFlag upper lower pieces turnColour score = do
--if xyFlag == 0 it's y aligned if 1 it's x aligned
let piece = head(pieces)
let pieceColour = other (snd piece)
let x = fst fst piece
let y = snd fst piece
if (pieceColour == turnColour) then
if (xyFlag == 0) then
if (upper > x && x > lower) then
let newScore = score+1
--recurse
if (tail(pieces) == []) then
return newScore
else
return countOtherColour xyFlag upper lower tail(pieces) turnColour newScore
else
--recurse
if (tail(pieces) == []) then
return score
else
return countOtherColour xyFlag upper lower tail(pieces) turnColour score
else
if (upper > y && y > lower) then
let newScore = score+1
--recurse
if (tail(pieces) == []) then
return newScore
else
return countOtherColour xyFlag upper lower tail(pieces) turnColour newScore
else
--recurse
if (tail(pieces) == []) then
return score
else
return countOtherColour xyFlag upper lower tail(pieces) turnColour score
else
--recurse
if (tail(pieces) == []) then
return score
else
return countOtherColour xyFlag upper lower tail(pieces) turnColour score
但是,此代码无法编译。我在第一行收到“if”解析错误:
if (tail(pieces) == []) then
这让我相信,关于我构建这段代码的方式的基本原理是错误的。我想澄清一下,我不是寻找某人来为我解决实现,只是为了有人向我解释我的实现如何存在缺陷,以及我如何在其中实现递归的一般指南构建我的代码的正确方法。
如果您已经阅读了这么多,谢谢,我期待阅读您的回复。
【问题讨论】:
-
一条评论:您的代码似乎比必要的要冗长和复杂。这里有一些关于你可以做些什么来清理它的建议:(1)你有比必要更多的缩进。您不需要将
do块缩进那么远——只需两个或四个空格就足够了。 (2)你有很多重复;您可以尝试通过将所有重复的位移动到它们自己的函数中来减少这种重复。 -
@bradrn 感谢您的建议,我将对缩进进行排序,但我不确定您是否注意到,但取决于递归部分(具有重复的部分)的上下文递归必须以不同的方式调用。我不确定如何将它转移到它自己的函数中,同时保持根据上下文稍微改变调用方式的能力。
-
我确实注意到了。将其分离到另一个函数中并不重要:只需将变化的位作为参数提供给该函数,并每次使用不同的参数调用该函数。
标签: list if-statement haskell recursion iteration