module Main (main) where
newGame :: Game
newGame = "........."
printGame
:: Game
-> IO ()printGame game = do
isEmpty x y game =
if 0 <= x && x < 3 && 0 <= y && y < 3 then
let p = y * 3 + x in
(game!!p) == '.'
else
False
getPlayerInputs
:: Game
-> IO (Int, Int)getPlayerInputs game = do
if isEmpty x y game then
else
getPlayerInputs game -- 再帰ループ
getComputerInputs
:: Game
-> IO (Int, Int)getComputerInputs game = do
let (inputs:_) = [ (x, y) | x <- [0, 1, 2], y <- [0, 1, 2], isEmpty x y game]
putByPlayer
:: Int -> Int -> Game
-> Game
putByPlayer x y game =
let p = y * 3 + x in
let front
= take p game
in let back
= drop (p
+ 1) game
in front ++ "o" ++ back
putByComputer
:: Int -> Int -> Game
-> Game
putByComputer x y game =
let p = y * 3 + x in
let front
= take p game
in let back
= drop (p
+ 1) game
in front ++ "x" ++ back
isPlayerWinner
:: Game
-> BoolisPlayerWinner game =
case game of
('o':'o':'o': _ : _ : _ : _ : _ : _ :_) -> True
( _ : _ : _ :'o':'o':'o': _ : _ : _ :_) -> True
( _ : _ : _ : _ : _ : _ :'o':'o':'o':_) -> True
('o': _ : _ :'o': _ : _ :'o': _ : _ :_) -> True
( _ :'o': _ : _ :'o': _ : _ :'o': _ :_) -> True
( _ : _ :'o': _ : _ :'o': _ : _ :'o':_) -> True
('o': _ : _ : _ :'o': _ : _ : _ :'o':_) -> True
( _ : _ :'o': _ :'o': _ :'o': _ : _ :_) -> True
_ -> False
isComputerWinner
:: Game
-> BoolisComputerWinner game =
case game of
('x':'x':'x': _ : _ : _ : _ : _ : _ :_) -> True
( _ : _ : _ :'x':'x':'x': _ : _ : _ :_) -> True
( _ : _ : _ : _ : _ : _ :'x':'x':'x':_) -> True
('x': _ : _ :'x': _ : _ :'x': _ : _ :_) -> True
( _ :'x': _ : _ :'x': _ : _ :'x': _ :_) -> True
( _ : _ :'x': _ : _ :'x': _ : _ :'x':_) -> True
('x': _ : _ : _ :'x': _ : _ : _ :'x':_) -> True
( _ : _ :'x': _ :'x': _ :'x': _ : _ :_) -> True
_ -> False
isDrawn game
= all (/='.') game
-> (Game
-> IO (Int, Int)) -- get~Inputs -> (Int -> Int -> Game
-> Game
) -- putBy~ -> (Game
-> Bool) -- is~Winner -> Game
playTurn name getInputs putBy isWinner game1 = do
(x, y) <- getInputs game1
let game2 = putBy x y game1
printGame game2
if isWinner game2 then do
else if isDrawn game2 then do
else do
playPlayersTurn
:: Game
-> IO (Game
, Bool)playPlayersTurn game = do
playTurn "Player"
getPlayerInputs
putByPlayer
isPlayerWinner
game
playComputersTurn
:: Game
-> IO (Game
, Bool)playComputersTurn game = do
playTurn "Computer"
getComputerInputs
putByComputer
isComputerWinner
game
playGame
:: (Game
-> IO (Game
, Bool)) -- current playTurn -> (Game
-> IO (Game
, Bool)) -- next PlayTurn -> Game
playGame current next game1 = do
(game2, endgame) <- current game1
if endgame then do
else do
playGame next current game2 -- 交換して再帰ループ
main = do
let game = newGame
printGame game
playGame playPlayersTurn
playComputersTurn
game
bW9kdWxlIE1haW4gKG1haW4pIHdoZXJlCgp0eXBlIEdhbWUgPSBTdHJpbmcKCm5ld0dhbWUgOjogR2FtZQpuZXdHYW1lID0gIi4uLi4uLi4uLiIKCnByaW50R2FtZSA6OiBHYW1lIC0+IElPICgpCnByaW50R2FtZSBnYW1lID0gZG8KICAgIHB1dFN0ckxuICIgIDAxMiIKICAgIHB1dFN0ckxuICgiMCAiICsrICh0YWtlIDMgZ2FtZSkpCiAgICBwdXRTdHJMbiAoIjEgIiArKyAodGFrZSAzIChkcm9wIDMgZ2FtZSkpKQogICAgcHV0U3RyTG4gKCIyICIgKysgKHRha2UgMyAoZHJvcCA2IGdhbWUpKSkKCmlzRW1wdHkgOjogSW50IC0+IEludCAtPiBHYW1lIC0+IEJvb2wKaXNFbXB0eSB4IHkgZ2FtZSA9CiAgICBpZiAwIDw9IHggJiYgeCA8IDMgJiYgMCA8PSB5ICYmIHkgPCAzIHRoZW4KICAgICAgICBsZXQgcCA9IHkgKiAzICsgeCBpbgogICAgICAgIChnYW1lISFwKSA9PSAnLicKICAgIGVsc2UKICAgICAgICBGYWxzZQoKZ2V0UGxheWVySW5wdXRzIDo6IEdhbWUgLT4gSU8gKEludCwgSW50KQpnZXRQbGF5ZXJJbnB1dHMgZ2FtZSA9IGRvCiAgICBwdXRTdHJMbiAieCB5ID8iCiAgICBsaW5lIDwtIGdldExpbmUKICAgIGxldCBpbnB1dHMgPSB3b3JkcyBsaW5lCiAgICBsZXQgeCA9IHJlYWQgKGlucHV0cyEhMCkKICAgIGxldCB5ID0gcmVhZCAoaW5wdXRzISExKQogICAgaWYgaXNFbXB0eSB4IHkgZ2FtZSB0aGVuCiAgICAgICAgcmV0dXJuICh4LCB5KQogICAgZWxzZQogICAgICAgIGdldFBsYXllcklucHV0cyBnYW1lIC0tIOWGjeW4sOODq+ODvOODlwoKZ2V0Q29tcHV0ZXJJbnB1dHMgOjogR2FtZSAtPiBJTyAoSW50LCBJbnQpCmdldENvbXB1dGVySW5wdXRzIGdhbWUgPSBkbwogICAgbGV0IChpbnB1dHM6XykgPSBbICh4LCB5KSB8IHggPC0gWzAsIDEsIDJdLCB5IDwtIFswLCAxLCAyXSwgaXNFbXB0eSB4IHkgZ2FtZV0KICAgIHJldHVybiBpbnB1dHMKCnB1dEJ5UGxheWVyIDo6IEludCAtPiBJbnQgLT4gR2FtZSAtPiBHYW1lCnB1dEJ5UGxheWVyIHggeSBnYW1lID0KICAgIGxldCBwID0geSAqIDMgKyB4IGluCiAgICBsZXQgZnJvbnQgPSB0YWtlIHAgZ2FtZSBpbgogICAgbGV0IGJhY2sgPSBkcm9wIChwICsgMSkgZ2FtZSBpbgogICAgZnJvbnQgKysgIm8iICsrIGJhY2sKCnB1dEJ5Q29tcHV0ZXIgOjogSW50IC0+IEludCAtPiBHYW1lIC0+IEdhbWUKcHV0QnlDb21wdXRlciB4IHkgZ2FtZSA9CiAgICBsZXQgcCA9IHkgKiAzICsgeCBpbgogICAgbGV0IGZyb250ID0gdGFrZSBwIGdhbWUgaW4KICAgIGxldCBiYWNrID0gZHJvcCAocCArIDEpIGdhbWUgaW4KICAgIGZyb250ICsrICJ4IiArKyBiYWNrCgppc1BsYXllcldpbm5lciA6OiBHYW1lIC0+IEJvb2wKaXNQbGF5ZXJXaW5uZXIgZ2FtZSA9CiAgICBjYXNlIGdhbWUgb2YgCiAgICAoJ28nOidvJzonbyc6IF8gOiBfIDogXyA6IF8gOiBfIDogXyA6XykgLT4gVHJ1ZQogICAgKCBfIDogXyA6IF8gOidvJzonbyc6J28nOiBfIDogXyA6IF8gOl8pIC0+IFRydWUKICAgICggXyA6IF8gOiBfIDogXyA6IF8gOiBfIDonbyc6J28nOidvJzpfKSAtPiBUcnVlCiAgICAoJ28nOiBfIDogXyA6J28nOiBfIDogXyA6J28nOiBfIDogXyA6XykgLT4gVHJ1ZQogICAgKCBfIDonbyc6IF8gOiBfIDonbyc6IF8gOiBfIDonbyc6IF8gOl8pIC0+IFRydWUKICAgICggXyA6IF8gOidvJzogXyA6IF8gOidvJzogXyA6IF8gOidvJzpfKSAtPiBUcnVlCiAgICAoJ28nOiBfIDogXyA6IF8gOidvJzogXyA6IF8gOiBfIDonbyc6XykgLT4gVHJ1ZQogICAgKCBfIDogXyA6J28nOiBfIDonbyc6IF8gOidvJzogXyA6IF8gOl8pIC0+IFRydWUKICAgIF8gLT4gRmFsc2UKCmlzQ29tcHV0ZXJXaW5uZXIgOjogR2FtZSAtPiBCb29sCmlzQ29tcHV0ZXJXaW5uZXIgZ2FtZSA9CiAgICBjYXNlIGdhbWUgb2YgCiAgICAoJ3gnOid4JzoneCc6IF8gOiBfIDogXyA6IF8gOiBfIDogXyA6XykgLT4gVHJ1ZQogICAgKCBfIDogXyA6IF8gOid4JzoneCc6J3gnOiBfIDogXyA6IF8gOl8pIC0+IFRydWUKICAgICggXyA6IF8gOiBfIDogXyA6IF8gOiBfIDoneCc6J3gnOid4JzpfKSAtPiBUcnVlCiAgICAoJ3gnOiBfIDogXyA6J3gnOiBfIDogXyA6J3gnOiBfIDogXyA6XykgLT4gVHJ1ZQogICAgKCBfIDoneCc6IF8gOiBfIDoneCc6IF8gOiBfIDoneCc6IF8gOl8pIC0+IFRydWUKICAgICggXyA6IF8gOid4JzogXyA6IF8gOid4JzogXyA6IF8gOid4JzpfKSAtPiBUcnVlCiAgICAoJ3gnOiBfIDogXyA6IF8gOid4JzogXyA6IF8gOiBfIDoneCc6XykgLT4gVHJ1ZQogICAgKCBfIDogXyA6J3gnOiBfIDoneCc6IF8gOid4JzogXyA6IF8gOl8pIC0+IFRydWUKICAgIF8gLT4gRmFsc2UKCmlzRHJhd24gOjogR2FtZSAtPiBCb29sCmlzRHJhd24gZ2FtZSA9IGFsbCAoLz0nLicpIGdhbWUKCnBsYXlUdXJuIDo6IFN0cmluZyAtLSBuYW1lCiAgICAgICAgIC0+IChHYW1lIC0+IElPIChJbnQsIEludCkpIC0tIGdldH5JbnB1dHMKICAgICAgICAgLT4gKEludCAtPiBJbnQgLT4gR2FtZSAtPiBHYW1lKSAtLSBwdXRCeX4KICAgICAgICAgLT4gKEdhbWUgLT4gQm9vbCkgLS0gaXN+V2lubmVyCiAgICAgICAgIC0+IEdhbWUKICAgICAgICAgLT4gSU8gKEdhbWUsIEJvb2wpCnBsYXlUdXJuIG5hbWUgZ2V0SW5wdXRzIHB1dEJ5IGlzV2lubmVyIGdhbWUxID0gZG8KICAgIHB1dFN0ckxuIChuYW1lICsrICIncyB0dXJuIikKICAgICh4LCB5KSA8LSBnZXRJbnB1dHMgZ2FtZTEKICAgIHB1dFN0ckxuICgicHV0ICgiICsrIChzaG93IHgpICsrICIsICIgKysgKHNob3cgeSkgKysgIikiKQogICAgbGV0IGdhbWUyID0gcHV0QnkgeCB5IGdhbWUxCiAgICBwcmludEdhbWUgZ2FtZTIKICAgIGlmIGlzV2lubmVyIGdhbWUyIHRoZW4gZG8KICAgICAgICBwdXRTdHJMbiAobmFtZSArKyAiIHdvbiIpCiAgICAgICAgcmV0dXJuIChnYW1lMiwgVHJ1ZSkKICAgIGVsc2UgaWYgaXNEcmF3biBnYW1lMiB0aGVuIGRvCiAgICAgICAgcHV0U3RyTG4gIkdhbWUgd2FzIGRyYXduIgogICAgICAgIHJldHVybiAoZ2FtZTIsIFRydWUpCiAgICBlbHNlIGRvCiAgICAgICAgcmV0dXJuIChnYW1lMiwgRmFsc2UpCgpwbGF5UGxheWVyc1R1cm4gOjogR2FtZSAtPiBJTyAoR2FtZSwgQm9vbCkKcGxheVBsYXllcnNUdXJuIGdhbWUgPSBkbwogICAgcGxheVR1cm4gIlBsYXllciIKICAgICAgICAgICAgIGdldFBsYXllcklucHV0cwogICAgICAgICAgICAgcHV0QnlQbGF5ZXIKICAgICAgICAgICAgIGlzUGxheWVyV2lubmVyCiAgICAgICAgICAgICBnYW1lCgpwbGF5Q29tcHV0ZXJzVHVybiA6OiBHYW1lIC0+IElPIChHYW1lLCBCb29sKQpwbGF5Q29tcHV0ZXJzVHVybiBnYW1lID0gZG8KICAgIHBsYXlUdXJuICJDb21wdXRlciIKICAgICAgICAgICAgIGdldENvbXB1dGVySW5wdXRzCiAgICAgICAgICAgICBwdXRCeUNvbXB1dGVyCiAgICAgICAgICAgICBpc0NvbXB1dGVyV2lubmVyCiAgICAgICAgICAgICBnYW1lCgpwbGF5R2FtZSA6OiAoR2FtZSAtPiBJTyAoR2FtZSwgQm9vbCkpIC0tIGN1cnJlbnQgcGxheVR1cm4KICAgICAgICAgLT4gKEdhbWUgLT4gSU8gKEdhbWUsIEJvb2wpKSAtLSBuZXh0IFBsYXlUdXJuCiAgICAgICAgIC0+IEdhbWUKICAgICAgICAgLT4gSU8gKCkKcGxheUdhbWUgY3VycmVudCBuZXh0IGdhbWUxID0gZG8KICAgIChnYW1lMiwgZW5kZ2FtZSkgPC0gY3VycmVudCBnYW1lMQogICAgaWYgZW5kZ2FtZSB0aGVuIGRvCiAgICAgICAgcmV0dXJuICgpCiAgICBlbHNlIGRvCiAgICAgICAgcGxheUdhbWUgbmV4dCBjdXJyZW50IGdhbWUyIC0tIOS6pOaPm+OBl+OBpuWGjeW4sOODq+ODvOODlwoKbWFpbiA6OiBJTyAoKQptYWluID0gZG8KICAgIGxldCBnYW1lID0gbmV3R2FtZQogICAgcHJpbnRHYW1lIGdhbWUKICAgIHBsYXlHYW1lIHBsYXlQbGF5ZXJzVHVybgogICAgICAgICAgICAgcGxheUNvbXB1dGVyc1R1cm4KICAgICAgICAgICAgIGdhbWUK