Вот код:
Вот мое мнение:
Давайте сначала определим правильных типов данных:
data Player = Black | White deriving (Eq, Show)
data Position = Position Int Int deriving (Eq, Show)
data Move = Move { position :: Position, player :: Player } deriving (Eq, Show)
Теперь фактическая функция просто подсчитывает количество строк, которые могут претендовать на выигрыш
hasWon :: Player -> [Move] -> Bool
hasWon p ms = (length $ winningLines p ms) > 0
Генерация выигрышных линий - это одно большое понимание:
winningLines p ms = [(x,y,z) | x <- ms,
y <- ms,
z <- ms,
oneLine (position x) (position y) (position z),
samePlayer (player x) (player y) (player z),
x /= y,
y /= z,
x /= z
]
samePlayer px py pz = px == py && py == pz
oneLine (Position x1 y1) (Position x2 y2) (Position x3 y3) = sameRow || sameCol
where
sameRow = (y1 == y2 && y2 == y3)
sameCol = (x1 == x2 && x2 == x3)
И, наконец, некоторое тестирование:
moves = [
Move (Position 1 1) White,
Move (Position 2 1) White,
Move (Position 3 1) White
]
main :: IO ()
main = do
print $ hasWon White moves
print $ winningLines White moves
Решение использует только основы, поэтому вы должны быть в состоянии понять его довольно легко и добавить свои собственные исправления;в нем по-прежнему отсутствуют диагонали (их легко добавить), и он считает все строки 6 раз (потому что он учитывает все перестановки; его легко исправить с помощью экземпляра Ord
для позиции и только с учетом "отсортированной тройки").
Конечно, это не единственный способ сделать это;одна из примечательных альтернатив - поместить его в массив на месте, а затем найти решение итеративно.Я думаю, что декларативный стиль в стиле Пролог просто лучше подходит для Haskell.