This commit is contained in:
parent
25c0503504
commit
2a8dfb787e
@ -11,10 +11,7 @@ defmodule Utils do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def alter_name(name, part) do
|
def alter_name(name, part), do: :"#{name}#{part}"
|
||||||
String.to_atom(Atom.to_string(name) <> part)
|
|
||||||
end
|
|
||||||
|
|
||||||
def beb_broadcast(m, dest), do: for(p <- dest, do: safecast(p, m))
|
def beb_broadcast(m, dest), do: for(p <- dest, do: safecast(p, m))
|
||||||
|
|
||||||
def register_name(name, pid, link \\ true) do
|
def register_name(name, pid, link \\ true) do
|
||||||
@ -46,7 +43,7 @@ defmodule Utils do
|
|||||||
IO.puts(msg)
|
IO.puts(msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defmacro or_state(val, do: expr) do
|
defmacro or_state(val, do: expr) do
|
||||||
quote do
|
quote do
|
||||||
case unquote(val) do
|
case unquote(val) do
|
||||||
|
242
lib/server.ex
242
lib/server.ex
@ -1,6 +1,6 @@
|
|||||||
defmodule ServerMacros do
|
defmodule ServerMacros do
|
||||||
|
|
||||||
def create_create_loop(name, do: match_exp, else: process_exp, after: after_exp) do
|
def create_create_loop(name, do: match_exp, else: process_exp) do
|
||||||
function_name = :"#{name}_loop"
|
function_name = :"#{name}_loop"
|
||||||
|
|
||||||
ast1 = quote do
|
ast1 = quote do
|
||||||
@ -8,21 +8,14 @@ defmodule ServerMacros do
|
|||||||
end
|
end
|
||||||
ast2 = quote do
|
ast2 = quote do
|
||||||
value ->
|
value ->
|
||||||
log("Got unexpected value: #{inspect(value)}")
|
# TODO check spelling
|
||||||
Process.send_after(self(), value, t + 2000)
|
log("Disreguarding: #{inspect(value)}")
|
||||||
|
# Process.send_after(self(), value, t + 2000)
|
||||||
unquote(function_name)(v, t)
|
unquote(function_name)(v, t)
|
||||||
end
|
end
|
||||||
|
|
||||||
ast3 = ast1 ++ match_exp ++ ast2
|
ast3 = ast1 ++ match_exp ++ ast2
|
||||||
|
|
||||||
after_exp = if after_exp == nil do
|
|
||||||
quote do
|
|
||||||
t -> :timeout
|
|
||||||
end
|
|
||||||
else
|
|
||||||
after_exp
|
|
||||||
end
|
|
||||||
|
|
||||||
quote do
|
quote do
|
||||||
def unquote(function_name)(v, t) do
|
def unquote(function_name)(v, t) do
|
||||||
var!(v) = v
|
var!(v) = v
|
||||||
@ -30,22 +23,18 @@ defmodule ServerMacros do
|
|||||||
receive do
|
receive do
|
||||||
unquote(ast3)
|
unquote(ast3)
|
||||||
after
|
after
|
||||||
unquote(after_exp)
|
t -> :timeout
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_create_loop(name, do: exp, else: else_exp) do
|
def create_create_loop(name, do: exp, else: else_exp) do
|
||||||
create_create_loop(name, do: exp, else: else_exp, after: nil)
|
create_create_loop(name, do: exp, else: else_exp)
|
||||||
end
|
|
||||||
|
|
||||||
def create_create_loop(name, do: exp, after: after_exp) do
|
|
||||||
create_create_loop(name, do: exp, else: nil, after: after_exp)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_create_loop(name, do: exp) do
|
def create_create_loop(name, do: exp) do
|
||||||
create_create_loop(name, do: exp, else: nil, after: nil)
|
create_create_loop(name, do: exp, else: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
defmacro create_loop(name, clauses) do
|
defmacro create_loop(name, clauses) do
|
||||||
@ -140,7 +129,7 @@ defmodule Server do
|
|||||||
state = qurey_status(state)
|
state = qurey_status(state)
|
||||||
game = state.games[game_id]
|
game = state.games[game_id]
|
||||||
cond do
|
cond do
|
||||||
is_finished(game, game_id) ->
|
is_finished(state, game_id) ->
|
||||||
{_, score} = state.games[game_id]
|
{_, score} = state.games[game_id]
|
||||||
safecast(pid_to_inform, {:make_move, game_id, :game_finished, score})
|
safecast(pid_to_inform, {:make_move, game_id, :game_finished, score})
|
||||||
state
|
state
|
||||||
@ -155,8 +144,7 @@ defmodule Server do
|
|||||||
|
|
||||||
def try_to_play(state, game_id, move, pid_to_inform) do
|
def try_to_play(state, game_id, move, pid_to_inform) do
|
||||||
name = state.name
|
name = state.name
|
||||||
# TODO create new hand
|
new_hand = get_hand_for_game_state(state.games[game_id].game_state)
|
||||||
new_hand = 2
|
|
||||||
try_propose {:make_move, game_id, name, move, new_hand}
|
try_propose {:make_move, game_id, name, move, new_hand}
|
||||||
do
|
do
|
||||||
{:decision, {:make_move, ^game_id, ^name, ^move, ^new_hand}} ->
|
{:decision, {:make_move, ^game_id, ^name, ^move, ^new_hand}} ->
|
||||||
@ -206,20 +194,36 @@ defmodule Server do
|
|||||||
|
|
||||||
true ->
|
true ->
|
||||||
state = qurey_status(state)
|
state = qurey_status(state)
|
||||||
safecast(pid_to_inform, {:game_state, game_id, state.games[game_id].game_state, state.games[game_id].hand[state.name]})
|
if is_finished(state, game_id) do
|
||||||
|
{_, score} = state.games[game_id]
|
||||||
|
safecast(pid_to_inform, {:game_state, game_id, :game_finished, score})
|
||||||
|
else
|
||||||
|
game = state.games[game_id]
|
||||||
|
safecast(pid_to_inform, {:game_state, game_id, game.game_state, game.hand[state.name]})
|
||||||
|
end
|
||||||
state
|
state
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_hand_for_game_state(game_state) do
|
||||||
|
r1 = Enum.random(0..100)
|
||||||
|
if r1 <= 10 do
|
||||||
|
:+
|
||||||
|
else
|
||||||
|
mx = game_state |> Enum.filter(fn m -> m != :+ end) |> Enum.max()
|
||||||
|
mn = max(mx - 20, 1)
|
||||||
|
mx = max(mx - 2, 4)
|
||||||
|
Enum.random(mn..mx)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def try_to_create_game(state, participants) do
|
def try_to_create_game(state, participants) do
|
||||||
game_ids = Map.keys(state.games)
|
game_ids = Map.keys(state.games)
|
||||||
latest = Enum.at(Enum.sort(game_ids), length(game_ids) - 1)
|
latest = Enum.at(Enum.sort(game_ids), length(game_ids) - 1)
|
||||||
new_game_id = if latest do latest else 0 end + 1
|
new_game_id = if latest do latest else 0 end + 1
|
||||||
|
|
||||||
# TODO: randomize game state
|
new_game_state = Enum.to_list(0..Enum.random(3..8)) |> Enum.map(fn _ -> Enum.random(1..4) end)
|
||||||
new_game_state = [1, 1]
|
hand = Enum.reduce(participants, %{}, fn p, acc -> Map.put(acc, p, get_hand_for_game_state(new_game_state)) end)
|
||||||
# TODO: randomize Initial hand value
|
|
||||||
hand = Enum.reduce(participants, %{}, fn p, acc -> Map.put(acc, p, 1) end)
|
|
||||||
|
|
||||||
try_propose {:start_game, new_game_id, participants, new_game_state, hand}
|
try_propose {:start_game, new_game_id, participants, new_game_state, hand}
|
||||||
do
|
do
|
||||||
@ -252,7 +256,7 @@ defmodule Server do
|
|||||||
|
|
||||||
def set_modifed(state, game, val \\ false) do
|
def set_modifed(state, game, val \\ false) do
|
||||||
or_state not is_finished(state, game) do
|
or_state not is_finished(state, game) do
|
||||||
%{state | games: Map.put(state.games, game, %{state.games | modified: val})}
|
%{state | games: Map.put(state.games, game, %{state.games[game] | modified: val})}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -260,34 +264,174 @@ defmodule Server do
|
|||||||
# Apply Game States
|
# Apply Game States
|
||||||
#
|
#
|
||||||
|
|
||||||
|
def get_index(indexed_game_state, spos, index) do
|
||||||
|
index = spos + index
|
||||||
|
len = length(indexed_game_state)
|
||||||
|
cond do
|
||||||
|
index < 0 ->
|
||||||
|
len - 1
|
||||||
|
index >= len ->
|
||||||
|
rem(index, len)
|
||||||
|
true ->
|
||||||
|
index
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def simplify_game_state_pluses([], indexed_game_state), do: {false, indexed_game_state}
|
||||||
|
def simplify_game_state_pluses([{:+, i} | tl], indexed_game_state) do
|
||||||
|
before_i = get_index(indexed_game_state, i, -1)
|
||||||
|
after_i = get_index(indexed_game_state, i, 1)
|
||||||
|
|
||||||
|
if before_i != after_i do
|
||||||
|
{b, b_i} = Enum.at(indexed_game_state, before_i)
|
||||||
|
{a, a_i} = Enum.at(indexed_game_state, after_i)
|
||||||
|
|
||||||
|
if b == a do
|
||||||
|
case b do
|
||||||
|
:+ -> simplify_game_state_pluses(tl, indexed_game_state)
|
||||||
|
n ->
|
||||||
|
list =
|
||||||
|
indexed_game_state |>
|
||||||
|
Enum.map(fn {x, ti} -> if ti == i, do: {{:merged, n + 1}, i}, else: {x, ti} end) |>
|
||||||
|
Enum.filter(fn {x, ti} -> cond do
|
||||||
|
b_i == ti -> false
|
||||||
|
a_i == ti -> false
|
||||||
|
true -> true
|
||||||
|
end
|
||||||
|
end) |>
|
||||||
|
reindex()
|
||||||
|
{true, expand_merge(list)}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
simplify_game_state_pluses(tl, indexed_game_state)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
simplify_game_state_pluses(tl, indexed_game_state)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_merged(item) do
|
||||||
|
case item do
|
||||||
|
{:merged, _} -> true
|
||||||
|
_ -> false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def expand_merge(indexed_game_state) do
|
||||||
|
{{:merged, n}, i} = indexed_game_state |> Enum.find(fn {x, _} -> is_merged(x) end)
|
||||||
|
|
||||||
|
b_i = get_index(indexed_game_state, i, - 1)
|
||||||
|
a_i = get_index(indexed_game_state, i, + 1)
|
||||||
|
|
||||||
|
if b_i != a_i do
|
||||||
|
{b, b_i} = Enum.at(indexed_game_state, b_i)
|
||||||
|
{a, a_i} = Enum.at(indexed_game_state, a_i)
|
||||||
|
if a == b do
|
||||||
|
case b do
|
||||||
|
:+ -> indexed_game_state
|
||||||
|
{:merged, _} -> indexed_game_state
|
||||||
|
_ ->
|
||||||
|
indexed_game_state |>
|
||||||
|
Enum.map(fn {x, ti} -> if ti == i, do: {{:merged, n + 1}, i}, else: {x, ti} end) |>
|
||||||
|
Enum.filter(fn {x, ti} -> cond do
|
||||||
|
b_i == ti -> false
|
||||||
|
a_i == ti -> false
|
||||||
|
true -> true
|
||||||
|
end
|
||||||
|
end) |>
|
||||||
|
reindex() |>
|
||||||
|
expand_merge()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
indexed_game_state
|
||||||
|
end
|
||||||
|
else
|
||||||
|
indexed_game_state
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def reindex(list, flat \\ true) do
|
||||||
|
list = if flat do
|
||||||
|
list |> Enum.map(fn {n, _} -> n end)
|
||||||
|
else
|
||||||
|
list
|
||||||
|
end
|
||||||
|
|
||||||
|
[list, 0..(length(list) - 1)] |> Enum.zip()
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_merged([], rec, _), do: rec
|
||||||
|
|
||||||
|
def remove_merged([{:merged, n} | tl], rec, add) do
|
||||||
|
if add do
|
||||||
|
remove_merged(tl, rec ++ [n], false)
|
||||||
|
else
|
||||||
|
remove_merged(tl, rec, false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_merged([n | tl], rec, add), do:
|
||||||
|
remove_merged(tl, rec ++ [n], add)
|
||||||
|
|
||||||
|
def remove_merged(list) do
|
||||||
|
log("#{inspect(list)}")
|
||||||
|
remove_merged(list, [], true)
|
||||||
|
end
|
||||||
|
|
||||||
def simplify_game_state(game_state) do
|
def simplify_game_state(game_state) do
|
||||||
# TODO actualy do this
|
log("game_state: #{inspect(game_state)}")
|
||||||
game_state
|
indexed_game_state =
|
||||||
|
game_state |>
|
||||||
|
reindex(false)
|
||||||
|
|
||||||
|
{repeat, indexed_game_state} =
|
||||||
|
indexed_game_state |>
|
||||||
|
Enum.filter(fn x -> case x do
|
||||||
|
{:+, _} -> true
|
||||||
|
_ -> false
|
||||||
|
end
|
||||||
|
end) |>
|
||||||
|
simplify_game_state_pluses(indexed_game_state)
|
||||||
|
|
||||||
|
log("game_state2: #{inspect(indexed_game_state)}")
|
||||||
|
|
||||||
|
if repeat do
|
||||||
|
indexed_game_state |>
|
||||||
|
Enum.map(fn {v, _} -> v end) |>
|
||||||
|
remove_merged() |>
|
||||||
|
simplify_game_state()
|
||||||
|
else
|
||||||
|
indexed_game_state |> Enum.map(fn {v, _} -> v end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply_game(state, {:make_move, game_id, player_name, pos_move, new_hand}) do
|
def apply_game(state, {:make_move, game_id, player_name, pos_move, new_hand}) do
|
||||||
game = state.games[game_id]
|
game = state.games[game_id]
|
||||||
case game do
|
case game do
|
||||||
{:finished, _} ->
|
{:finished, _} ->
|
||||||
raise :game_already_finished
|
raise "Game already finished"
|
||||||
:not_playing_in_game ->
|
:not_playing_in_game ->
|
||||||
%{state | instance: state.instance + 1 }
|
%{state | instance: state.instance + 1 }
|
||||||
game ->
|
game ->
|
||||||
game_state = game.game_state
|
game_state = game.game_state
|
||||||
{b, e} = Enum.split(game_state, pos_move)
|
{b, e} = Enum.split(game_state, pos_move)
|
||||||
game_state = b ++ [ game.hand[player_name] ] ++ e
|
game_state = b ++ [ game.hand[player_name] ] ++ e
|
||||||
game_state = simplefy_game_state(game_state)
|
game_state = simplify_game_state(game_state)
|
||||||
hand = Map.put(game.hand, player_name, new_hand)
|
hand = Map.put(game.hand, player_name, new_hand)
|
||||||
game = %{game| hand: hand, game_state: game_state }
|
game = %{game| hand: hand, game_state: game_state }
|
||||||
# TODO decide if it's ending state
|
|
||||||
%{state| games: Map.put(state.games, game_id, game)}
|
if length(game.game_state) > 15 do
|
||||||
|
%{state| games: Map.put(state.games, game_id, {:finished, Enum.sum(game.game_state)}), instance: state.instance + 1}
|
||||||
|
else
|
||||||
|
%{state| games: Map.put(state.games, game_id, game), instance: state.instance + 1}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply_game(state, {:start_game, game_id, participants, new_game_state, hand}) do
|
def apply_game(state, {:start_game, game_id, participants, new_game_state, hand}) do
|
||||||
cond do
|
cond do
|
||||||
state.games[game_id] ->
|
state.games[game_id] ->
|
||||||
raise :game_already_exists
|
raise "Game Already Exists"
|
||||||
state.name in participants ->
|
state.name in participants ->
|
||||||
%{state |
|
%{state |
|
||||||
games: Map.put(state.games, game_id, %{
|
games: Map.put(state.games, game_id, %{
|
||||||
@ -306,7 +450,7 @@ defmodule Server do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply_game(_, _), do: raise :do_not_know_how_to_apply_game_state
|
def apply_game(_, _), do: raise "Do not know how to apply game state"
|
||||||
|
|
||||||
############
|
############
|
||||||
# Interface
|
# Interface
|
||||||
@ -320,47 +464,53 @@ defmodule Server do
|
|||||||
|
|
||||||
def start_game(name, participants) do
|
def start_game(name, participants) do
|
||||||
safecast(name, {:start_game, participants, self()})
|
safecast(name, {:start_game, participants, self()})
|
||||||
start_game_loop(nil, 1000)
|
start_game_loop(nil, 10000)
|
||||||
end
|
end
|
||||||
|
|
||||||
create_loop :get_game_state do
|
create_loop :get_game_state do
|
||||||
{:game_state, ^v, :not_playing} ->
|
{:game_state, ^v, :not_playing} ->
|
||||||
IO.puts("Not Playing in that game")
|
log("Not Playing in that game")
|
||||||
{:not_playing}
|
{:not_playing}
|
||||||
{:game_state, ^v, game_state, hand} ->
|
{:game_state, ^v, game_state, hand} ->
|
||||||
IO.puts("Got game state, #{inspect(game_state)}, hand: #{inspect(hand)}")
|
log("Got game state, #{inspect(game_state)}, hand: #{inspect(hand)}")
|
||||||
{:state, game_state, hand}
|
{:state, game_state, hand}
|
||||||
|
{:game_state, ^v, :not_playing} ->
|
||||||
|
log("Not Playing in that game")
|
||||||
|
{:not_playing}
|
||||||
|
{:game_state, ^v, :game_finished, score} ->
|
||||||
|
log("Game finsihed, #{score}")
|
||||||
|
{:game_finished, score}
|
||||||
{:game_state, ^v, :game_does_not_exist} ->
|
{:game_state, ^v, :game_does_not_exist} ->
|
||||||
IO.puts("Got game does not exist")
|
log("Got game does not exist")
|
||||||
{:not_exists}
|
{:not_exists}
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_game_state(name, game_id) do
|
def get_game_state(name, game_id) do
|
||||||
safecast(name, {:get_game_state, game_id, self()})
|
safecast(name, {:get_game_state, game_id, self()})
|
||||||
get_game_state_loop(game_id, 1000)
|
get_game_state_loop(game_id, 10000)
|
||||||
end
|
end
|
||||||
|
|
||||||
create_loop :make_move do
|
create_loop :make_move do
|
||||||
{:make_move, ^v, :game_does_not_exist} ->
|
{:make_move, ^v, :game_does_not_exist} ->
|
||||||
IO.puts("Got game does not exist")
|
log("Got game does not exist")
|
||||||
{:not_exists}
|
{:not_exists}
|
||||||
{:make_move, ^v, :not_playing} ->
|
{:make_move, ^v, :not_playing} ->
|
||||||
IO.puts("Not Playing in that game")
|
log("Not Playing in that game")
|
||||||
{:not_playing}
|
{:not_playing}
|
||||||
{:make_move, ^v, :game_finished, score} ->
|
{:make_move, ^v, :game_finished, score} ->
|
||||||
IO.puts("Game finsihed, #{score}")
|
log("Game finsihed, #{score}")
|
||||||
{:game_finished, score}
|
{:game_finished, score}
|
||||||
{:make_move, ^v, :player_moved_before, game_state, hand} ->
|
{:make_move, ^v, :player_moved_before, game_state, hand} ->
|
||||||
IO.puts("Player moved_before, #{inspect(game_state)} #{inspect(hand)}")
|
log("Player moved_before, #{inspect(game_state)} #{inspect(hand)}")
|
||||||
{:player_moved_before, game_state, hand}
|
{:player_moved_before, game_state, hand}
|
||||||
{:make_move, ^v, game_state, hand} ->
|
{:make_move, ^v, game_state, hand} ->
|
||||||
IO.puts("Got game state, #{inspect(game_state)}, hand: #{inspect(hand)}")
|
log("Got game state, #{inspect(game_state)}, hand: #{inspect(hand)}")
|
||||||
{:state, game_state, hand}
|
{:state, game_state, hand}
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_move(name, game_id, move) do
|
def make_move(name, game_id, move) do
|
||||||
safecast(name, {:make_move, game_id, move, self()})
|
safecast(name, {:make_move, game_id, move, self()})
|
||||||
make_move_loop(game_id, 1000)
|
make_move_loop(game_id, 10000)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user