Итак, несколько вопросов, давайте их один за другим:
Первого: Как генерировать что-то другое, чем целые числа с функциями от System.Random (который является медленным генератором, но для вашего приложения, производительность не является жизненно важной). Существует несколько подходов, с вашим списком, вы должны написать функцию intToColor:
intToColor :: Int -> String
intToColor n = head . filter (\p -> snd p == n) $ [("Black",1),("Green",2),("Purple",3),("Red",4),("White",5),("Yellow",6)]
Не очень приятно. Хотя вы могли бы сделать лучше, если бы вы написали пару в (ключ, значение) порядок вместо так как есть немного поддержки «ассоциативного списка» в Data.List с функцией поиска:
intToColor n = fromJust . lookup n $ [(1,"Black"),(2,"Green"),(3,"Purple"),(4,"Red"),(5,"White"),(6,"Yellow")]
Или, конечно, вы могли бы просто забыть этот бизнес ключ Int от 1 до 6 в списке, так как списки уже проиндексированы Int:
intToColor n = ["Black","Green","Purple","Red","White","Yellow"] !! n
(обратите внимание, что эта функция немного отличается, так как intToColor 0 является «Black» в настоящее время а не intToColor 1, но это не очень важно с учетом вашей цели, если это действительно шокирует вас, вы можете написать «!!(П-1)», а)
Но поскольку ваши цвета не очень Струна и больше, как символы, вероятно, вы должны создать тип Цвета:
data Color = Black | Green | Purple | Red | White | Yellow deriving (Eq, Ord, Show, Read, Enum)
Так что теперь Black является значением типа Color, вы можете использовать его в любом месте вашей программы (и GHC будет протестовать, если вы напишете Blak), и благодаря магии автоматического деривации вы можете сравнить значения цвета или показать их или использовать toEnum для преобразования Int в цвет!
Итак, теперь вы можете написать:
randColorIO :: IO Color
randColorIO = do
n <- randomRIO (0,5)
return (toEnum n)
Второй, вы хотите сохранить значения (цвета) в кости в структуре данных и дать возможность сохранять одинаковые броски. Поэтому сначала вы должны запасти результаты нескольких бросков, учитывая максимальное количество одновременных бросков (5) и сложность ваших данных, простого списка достаточно и учитывая количество функций для обработки списков в Haskell, это хороший выбор ,
Так что вы хотите бросает несколько кубиков:
nThrows :: Int -> IO [Color]
nThrows 0 = return []
nThrows n = do
c <- randColorIO
rest <- nThrows (n-1)
return (c : rest)
Это хороший первый подход, это то, что вы делаете, более или менее, за исключением того, вы используете, если вместо сопоставления с образцом и у вас есть явный аккумуляторный аргумент (вы идете на хвостовую рекурсию?), на самом деле не лучше, кроме строгого аккумулятора (Int, а не списков).
Конечно, Haskell способствует функции высшего порядка, а не прямой рекурсии, так что давайте посмотрим комбинаторы, поиск "Int -> IO а -> IO [а]" с Hoogle дает:
replicateM :: Monad m => Int -> m a -> m [a]
что делает именно то, что вы хотите:
nThrows n = replicateM n randColorIO
(я не уверен, я бы даже написать это как функция, так как я нахожу явное выражение более ясным и почти короткий)
когда у ou имеют результаты бросков, вы должны проверить, какие из них идентичны, я предлагаю вам посмотреть сортировку, группу, карту и длину для достижения этой цели (преобразование списка результатов в список списка одинаковых результатов, а не самый эффективный структуры данных, но в этом масштабе наиболее подходящий выбор). Тогда сохранение цветов, которые вы получили несколько раз, - это вопрос использования фильтра.
Тогда вы должны написать некоторые функции для обработки взаимодействия и скоринга:
type Score = Int
yahtzee :: IO Score
yahtzeeStep :: Int -> [[Color]] -> IO [[Color]] -- recursive
scoring :: [[Color]] -> Score
Так что я рекомендую, чтобы сохранить и передавать [[цвет]] для отслеживает то, что откладывалось. Этого должно быть достаточно для ваших нужд.
Какие учебники вы используете для изучения Haskell? –