0 / 0 / 0
Регистрация: 16.09.2012
Сообщений: 8
1

Упражнение про IO (игра в кости)

01.08.2013, 22:34. Показов 2341. Ответов 6
Метки нет (Все метки)

С помощью стандартных функций для генерации случайных чисел напишите программу, которая проводит состязание по игре в кости. Программа принимает аргументом суммарное число очков необходимых для победы. Двое игроков бросают по очереди кости побеждает тот, кто первым наберёт заданную сумму.

Сделайте так чтобы результаты выводились постепенно. С каждым нажатием на Enter вы подбрасываете кости (два шестигранных кубика). После каждого раунда программа выводит промежуточные результаты.

(упражнение из этой книжки: http://anton-k.github.io/ru-ha... /home.html)


Функция, которая делает этот цикл, принимает несколько обычных (без IO в типе) значений и возвращает IO () и должна вызывать себя, но я не понимаю, как применить функцию a -> b -> m c к значениям типов m a и m b. Есть ли аналог оператора =<< для функций нескольких аргументов?
Или эта задача решается вообще по-другому?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
01.08.2013, 22:34
Ответы с готовыми решениями:

Игра в кости
Здравствуйте, не могли бы вы написать простенькую программу? Просто в C++ не шарю, а к зачету нужно...

Игра в кости
Помогите, пожалуйста, с заданием, не совсем могу разобраться как его делать( Разработать “игру в...

Игра кости
Помогите пожалуйста. #include &lt;stdio.h&gt; #include &lt;time.h&gt; #include &lt;stdlib.h&gt; #include...

Игра в кости
Написать программу, которая имитирует игру в кости. Игроки (2 человека) кидают по 2 кубика...

6
Эксперт по математике/физике
4163 / 2066 / 424
Регистрация: 19.07.2009
Сообщений: 3,125
Записей в блоге: 24
01.08.2013, 23:01 2
Haskell
1
2
3
4
bind2 f x y = do
  xv <- x
  vy <- y
  f x y
Это очень похоже на liftM2:
Haskell
1
bind2 f x y = join $ liftM2 f x y
Можете показать Ваши наработки? Так будет проще беседовать, потому как мы узнаем, каким образом Вы подходите к решению задачи и какие средства используете. Это не обязательно должен быть рабочий код, хотя это желательно.
0
Эксперт С++
5827 / 3478 / 358
Регистрация: 08.02.2010
Сообщений: 7,448
02.08.2013, 01:53 3
Цитата Сообщение от ЯНикита Посмотреть сообщение
Или эта задача решается вообще по-другому?
Если применять функцию типа (a -> b -> c), а не (a -> b -> m c), то задачу можно решить с помощью той же функции liftM2 либо с помощью аппликативных функторов.
0
0 / 0 / 0
Регистрация: 16.09.2012
Сообщений: 8
02.08.2013, 02:26  [ТС] 4
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import Random
import Control.Monad
 
randomInt :: (Random a, Integral a) => a -> IO a
randomInt n = randomIO >>= return . flip mod n
 
data Hod = Fst | Snd 
  deriving(Enum, Eq)
 
ifthenelse::Bool -> a -> a -> a
ifthenelse True a b = a
ifthenelse False a b = b
 
iter::IO Int -> IO Int -> IO Int -> Hod -> IO () {-iter принимает количество очков, необходимое для победы, счёт первого игрока, счёт второго игрока и текущего игрока-}
iter a b c d = getChar >> liftM3 ifthenelse
                                 (liftM2 (>=) b a)
                                 putStrLn "первый игрок выиграл"
                                 (liftM3 ifthenelse
                                         (liftM2 (>=) c a) 
                                         putStrLn "второй игрок выиграл"
                                         (iter a
                                              (if d == Fst 
                                               then (liftM2 (+)) b (randomInt 6)
                                               else b)
                                              (if d == Fst 
                                               then c 
                                               else (liftM2 (+)) c (randomInt 6))
                                              (succ d)))
Мне очень не нравится этот код, но я не понимаю, почему он не работает. Функцию ifthenelse пришлось ввести, потому что если сравнить два значения типа IO Int, получится IO Bool, которое нельзя использовать в обычном if. Я думаю, в правильном решении такая функция принимает значения без IO в типе, но я не понимаю, как это делать.
Про приведённый код ghc говорит так:

Couldn't match expected type `t -> a1' against inferred type `Int'
In the second argument of `liftM2', namely `b'
In the second argument of `liftM3', namely `(liftM2 (>=) b a)'
In the second argument of `(>>)', namely
`liftM3
ifthenelse
(liftM2 (>=) b a)
putStrLn
"Fst w"
(liftM3
ifthenelse
(liftM2 (>=) c a)
putStrLn
"Snd w"
(iter
a
(if d == Fst then (liftM2 (+)) b (randomInt 6) else b)
(if d == Fst then c else (liftM2 (+)) c (randomInt 6))
(succ d)))'

Добавлено через 2 минуты
В этой функции прибавляется случайное число, поэтому её результат не может быть без IO в типе.
0
Эксперт С++
5827 / 3478 / 358
Регистрация: 08.02.2010
Сообщений: 7,448
02.08.2013, 02:54 5
Следует отделять чистые функции от функций с побочными эффектами, когда это возможно:

Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import System.Random
 
data Player = Player { score :: Int, name :: String }
mkPlayer :: String -> Player
mkPlayer name = Player { score = 0, name = name }
 
game :: [Int] -> Int -> Player -> Player -> Player
game rands threshold p1 p2
     | score p1 >= threshold = p1
     | score p2 >= threshold = p2
     | otherwise            = game (tail rands) threshold p2 p1 { score = score p1 + head rands }
 
diceRoll :: Int -> Int
diceRoll x = 1 + x `mod` 6
 
main :: IO ()
main = do
  stdGen <- newStdGen
  let winner = game (map diceRoll (randoms stdGen)) 99 (mkPlayer "John") (mkPlayer "Peter")
  putStrLn $ name winner ++ " won with score " ++ show (score winner)
1
0 / 0 / 0
Регистрация: 16.09.2012
Сообщений: 8
03.08.2013, 18:25  [ТС] 6
Я понимаю, что код должен быть чистым, когда это возможно, но в этой задаче программа должна выводить промежуточные результаты после нажатия клавиши. Можно сделать функцию game :: [Int] -> Int -> Player -> Player -> IO Player и выводить результаты прямо в ней? Или она должна возвращать список промежуточных результатов и быть чистой?

А вообще, всё получилось, спасибо. Только у меня функция game не чистая.
0
Эксперт С++
5827 / 3478 / 358
Регистрация: 08.02.2010
Сообщений: 7,448
03.08.2013, 20:55 7
Цитата Сообщение от ЯНикита Посмотреть сообщение
Можно сделать функцию game :: [Int] -> Int -> Player -> Player -> IO Player и выводить результаты прямо в ней? Или она должна возвращать список промежуточных результатов и быть чистой?
Можно сделать и так, и так. Расскажу про второй вариант.

По сути, у нас в игре есть состояние — это номер хода, есть лог действий, есть неизменяемое состояние — это количество очков для победы. Под эти сущности подходят монады State, Writer и Reader, которые комбинируется с помощью Monad Transformers.

Код достаточно сложен для первого понимания, бОльшую часть в нём занимают описания структур данных и вспомогательных функций, логика же игры осталась неизменной.

Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import System.Random
 
import Control.Monad.Identity
import Control.Monad.Writer
import Control.Monad.State
import Control.Monad.Reader
 
import Text.Printf
 
data Player = Player { score :: Int, name :: String }
 
mkPlayer :: String -> Player
mkPlayer name = Player { score = 0, name = name }
 
data GameState = GameState { currTurn :: Player, prevTurn :: Player, rolls :: [Int], turn :: Int }
 
mkGameState :: String -> String -> [Int] -> GameState
mkGameState p1 p2 rs = GameState { currTurn  = mkPlayer p1
                                 , prevTurn  = mkPlayer p2
                                 , rolls     = rs
                                 , turn      = 1
                                 }
 
type Game = ReaderT Int (StateT GameState (WriterT [String] Identity)) ()
 
execGame :: GameState -> Int -> [String]
execGame state threshold = runIdentity (execWriterT (execStateT (runReaderT game threshold) state))
 
nextTurn :: GameState -> GameState
nextTurn state = state { currTurn = prevTurn state
                       , prevTurn = currTurn' { score = newScore }
                       , rolls    = tail (rolls state)
                       , turn     = turn state + 1
                       }
    where currTurn' = currTurn state
          newScore  = score currTurn' + head (rolls state)
 
game :: Game
game = do
  threshold <- ask
  turn <- gets turn
  curr <- gets currTurn
  prev <- gets prevTurn
  tell [printf "Turn %d. %s - %d, %s - %d." turn (name curr) (score curr) (name prev) (score prev)]
  if score prev > threshold
  then tell [printf "%s wins with score %d." (name prev) (score prev)]
  else do
    modify nextTurn
    game
 
diceRoll :: Int -> Int
diceRoll x = 1 + x `mod` 6
 
main :: IO ()
main = do
  stdGen <- newStdGen
  mapM_ putStrLn $ execGame (mkGameState "John" "Peter" (map diceRoll (randoms stdGen))) 99
Использование монад в данном случае необязательно, можно было бы переписать мой предыдущий пример так, чтобы функция game возвращала не Player, а список промежуточных результатов.

Грязную версию game с Monad Transformers можно получить из предыдущей, заменив WriterT [String] Identity на IO, а tell на putStrLn. Соответственно придется внести изменения в execGame.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
03.08.2013, 20:55
Помогаю со студенческими работами здесь

Игра в кости
Написать игру в которой имитируется бросание кубиков игроком. Игра должна представлять собой...

Игра в кости C++
Написать программу, которая имитирует игру в кости. Игроки (2 человека) кидают по 2...

Игра в кости
НУжно написать на C++ игру в кости,консольную,с использованием генератора случайных чисел. т.е...

Игра в кости
всем привет. я недели 3 учусь писать на с++. в моей программе почему то переменная int дает...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru