Skip to content

Instantly share code, notes, and snippets.

@gamako
Created May 3, 2016 02:18
Show Gist options
  • Save gamako/4949d485d58d9c9ffb8be79bf089976c to your computer and use it in GitHub Desktop.
Save gamako/4949d485d58d9c9ffb8be79bf089976c to your computer and use it in GitHub Desktop.
# 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