Created
May 3, 2016 02:18
-
-
Save gamako/4949d485d58d9c9ffb8be79bf089976c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# EvenMinusOdd 偶数引く奇数 | |
# ダイスゲーム百科 P12より | |
# | |
# - 参加人数は何人でも | |
# - 参加人数x10のカウンターを中央に置く | |
# | |
# 手番のプレイヤーは次のことを行う | |
# 1. サイコロを6個ふる | |
# 2. 偶数の目の合計から奇数の目の合計を引いた合計を得点とする | |
# 3. 中央のカウンターから、プレイヤーが得点の数だけとる。マイナスの場合は戻す | |
# 4. 中央のカウンターが0になったら終了。その時点でのカウンターの数が最も多かったプレイヤーが勝者。 | |
# | |
# 以下のコマンドで実行できる | |
# % elixirc dice1.exs | |
defmodule EvenMinusOdd do | |
# Integer.is_odd/1, Integer.is_even/1 を使うために、モジュールの読み込み | |
require Integer | |
# サイコロの一投を表す関数 | |
def dice do | |
Enum.random(1..6) | |
end | |
# 1ターンを表す関数 | |
# 引数deceFには、ダイスの目を返す関数を与える | |
def turn(centerCounter, playerCounter, diceF \\ &EvenMinusOdd.dice/0) do | |
dices = Enum.map(1..6, fn _ -> diceF.() end) | |
oddSum = Enum.filter(dices, &Integer.is_odd/1) |> Enum.sum | |
evenSum = Enum.filter(dices, &Integer.is_even/1) |> Enum.sum | |
score = (evenSum - oddSum) |> max(-playerCounter) |> min(centerCounter) | |
{centerCounter - score, playerCounter + score} | |
end | |
# ゲームの状態を表す構造体 | |
defmodule State do | |
defstruct center: 0, players: [] | |
end | |
# リストの末尾を取得するメソッド | |
# 標準にあってもよさそうなのだけど、ないので作った | |
def last l do | |
Enum.reduce l, fn x, _ -> x end | |
end | |
# ゲームの進行 | |
# 各ターンのState構造体を作成していく | |
def game_(state) do | |
# 人数ぶんのRange,Stream.cycle/1で繰り返すことで、各プレイヤーのターンが順番にまわってくるのを表現する | |
0..Enum.count(state.players)-1 | |
|> Stream.cycle() | |
# それぞれのターンで行うことを、新しいstateを作っていくことで実現している | |
|> Stream.transform(state, fn index, %{center: currentCenter, players: currentPlayers} = currentState -> | |
case currentCenter do | |
# 中央のカウンターが0になっていたら終了 | |
# 0になったときに終わるのではなく、0になって次にここまで来たところで終了判定に落ちる | |
0 -> {:halt, currentState} | |
# ターン毎の処理 | |
_ -> | |
turnPlayersCount = Enum.at(currentPlayers, index) | |
{nextCenterCounter, nextPlayerCounter} = turn(currentCenter, turnPlayersCount) | |
a = %State{ | |
center: nextCenterCounter, | |
players: List.update_at(currentPlayers, index, fn _ -> nextPlayerCounter end) | |
} | |
{[a], a} | |
end | |
end) | |
end | |
# player配列から勝者を探す | |
def findWinner(players) do | |
maxCount = Enum.max(players) | |
winners = Enum.with_index(players) |> Enum.filter(fn {v, _} -> v == maxCount end) |> Enum.map(fn {v, i} -> i end) | |
end | |
# ゲーム開始 | |
# 引数に人数をとる | |
# turnFには、ターンごとの処理関数を与えられる(テスト用) | |
def game(playerNumber, turnF \\ &EvenMinusOdd.turn/2) do | |
players = Stream.repeatedly(fn -> 0 end) |> Enum.take(playerNumber) | |
s = %State{center: playerNumber * 10, players: players} | |
result = game_(s) |> last | |
IO.inspect(result) | |
winners = findWinner(result.players) | |
IO.puts("winner is " <> inspect(winners)) | |
end | |
end | |
EvenMinusOdd.game(10) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment