added get_game_state
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Andre Henriques 2024-01-16 22:06:10 +00:00
parent 47b02d37ec
commit 1d2db555be
2 changed files with 89 additions and 56 deletions

View File

@ -228,9 +228,7 @@ defmodule Paxos do
safecast(proc, {:prepared, inst, ballot, state.instmap[inst].accepted_ballot, state.instmap[inst].accepted_value}); safecast(proc, {:prepared, inst, ballot, state.instmap[inst].accepted_ballot, state.instmap[inst].accepted_value});
set_instmap do set_instmap do
%{ map %{ map | ballot: ballot }
| ballot: ballot
}
end end
Ballot.compare(ballot, &>/2, state.instmap[inst].ballot) -> Ballot.compare(ballot, &>/2, state.instmap[inst].ballot) ->
@ -240,9 +238,7 @@ defmodule Paxos do
) )
set_instmap do set_instmap do
%{ map %{ map | ballot: ballot }
| ballot: ballot
}
end end
true -> true ->
@ -257,7 +253,7 @@ defmodule Paxos do
has_finished(state, inst) -> has_finished(state, inst) ->
state state
state.leader == state.name and Ballot.compare(state.instmap[inst].ballot, &==/2, ballot) -> state.leader == state.name and state.instmap[inst].ballot == ballot ->
if Map.has_key?(state.instmap, inst) and state.instmap[inst].pid_to_inform != nil do if Map.has_key?(state.instmap, inst) and state.instmap[inst].pid_to_inform != nil do
send(state.instmap[inst].pid_to_inform, {:abort, inst}) send(state.instmap[inst].pid_to_inform, {:abort, inst})
end end
@ -300,10 +296,9 @@ defmodule Paxos do
has_finished(state, inst) -> has_finished(state, inst) ->
state state
Ballot.compare(ballot, &==/2, state.instmap[inst].ballot) -> ballot == state.instmap[inst].ballot ->
set_instmap do set_instmap do
%{ %{ map
map
| prepared_values: map.prepared_values ++ [{accepted_ballot, accepted_value}] | prepared_values: map.prepared_values ++ [{accepted_ballot, accepted_value}]
} }
end end
@ -354,9 +349,7 @@ defmodule Paxos do
state.leader == state.name and state.instmap[inst].ballot == ballot -> state.leader == state.name and state.instmap[inst].ballot == ballot ->
set_instmap do set_instmap do
%{ map | %{ map | accepted: map.accepted + 1 }
accepted: map.accepted + 1
}
end end
accepted( state, inst) accepted( state, inst)

View File

@ -8,15 +8,16 @@ defmodule ServerMacros do
end end
ast2 = quote do ast2 = quote do
value -> value ->
Process.send_after(self(), value, 100) log("Got unexpected value: #{inspect(value)}")
unquote(function_name)(v) Process.send_after(self(), value, t + 2000)
unquote(function_name)(v, t)
end end
ast3 = ast1 ++ match_exp ++ ast2 ast3 = ast1 ++ match_exp ++ ast2
if after_exp != nil do if after_exp != nil do
quote do quote do
def unquote(function_name)(v) do def unquote(function_name)(v, t) do
var!(v) = v var!(v) = v
unquote(process_exp) unquote(process_exp)
receive do receive do
@ -28,11 +29,13 @@ defmodule ServerMacros do
end end
else else
quote do quote do
def unquote(function_name)(v) do def unquote(function_name)(v, t) do
var!(v) = v var!(v) = v
unquote(process_exp) unquote(process_exp)
receive do receive do
unquote(ast3) unquote(ast3)
after
t -> :timeout
end end
end end
end end
@ -63,7 +66,6 @@ defmodule ServerMacros do
ast2 = quote do ast2 = quote do
{:decision, v} -> {:decision, v} ->
var!(state) = apply_game(var!(state), v) var!(state) = apply_game(var!(state), v)
var!(res) = v
unquote(recal_do) unquote(recal_do)
v -> v ->
@ -88,7 +90,7 @@ defmodule Server do
require Utils require Utils
import Utils import Utils
create_log 2 create_log 3
def start(name, participants) do def start(name, participants) do
log("starting server") log("starting server")
@ -115,39 +117,74 @@ defmodule Server do
{state, game_id} = try_to_create_game(state, participants) {state, game_id} = try_to_create_game(state, participants)
safecast(pid_to_inform, {:start_game_ans, game_id}) safecast(pid_to_inform, {:start_game_ans, game_id})
state state
{:get_game_state, game_id, pid_to_inform} ->
get_game_state(state, game_id, pid_to_inform)
end end
def get_game_state(state, game_id, pid_to_inform, repeat \\ false) do
cond do
state.games[game_id] == :not_playing_in_game ->
safecast(pid_to_inform, {:game_state, game_id, :not_playing})
state
state.games[game_id] == nil ->
if repeat do
safecast(pid_to_inform, {:game_state, game_id, :game_does_not_exist})
state
else
state = qurey_status(state)
get_game_state(state, game_id, pid_to_inform, true)
end
true ->
state = qurey_status(state)
safecast(pid_to_inform, {:game_state, game_id, state.games[game_id].game_state, state.games[game_id].hand})
state
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)
log("#{inspect(latest)}")
new_game_id = if latest do latest else 0 end + 1 new_game_id = if latest do latest else 0 end + 1
log("#{inspect(new_game_id)}")
# TODO: randomize game state # TODO: randomize game state
new_game_state = [1, 1] new_game_state = [1, 1]
# TODO: randomize Initial hand value # TODO: randomize Initial hand value
hand = Enum.reduce(participants, %{}, fn p, acc -> Map.put(acc, p, 1) end) hand = Enum.reduce(participants, %{}, fn p, acc -> Map.put(acc, p, 1) end)
res = nil
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
{:decision, {:start_game, ^new_game_id, ^participants, ^new_game_state, ^hand}} -> {:decision, {:start_game, ^new_game_id, ^participants, ^new_game_state, ^hand}} ->
state = apply_game(state, {:start_game, new_game_id, participants, new_game_state, hand}) state = apply_game(state, {:start_game, new_game_id, participants, new_game_state, hand})
{state, new_game_id} {state, new_game_id}
else else
log("HERE #{inspect(res)}")
try_to_create_game(state, participants) try_to_create_game(state, participants)
end end
end end
#
# Utils
#
def qurey_status(state) do
v = Paxos.get_decision(state.paxos, state.instance, 100)
or_state v != nil do
state = apply_game(state, v)
qurey_status(state)
end
end
# #
# Apply Game States # Apply Game States
# #
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
if state.name in participants do cond do
state.games[game_id] ->
raise :game_already_exists
state.name in participants ->
%{state | %{state |
games: Map.put(state.games, game_id, %{ games: Map.put(state.games, game_id, %{
game_state: new_game_state, game_state: new_game_state,
@ -156,15 +193,15 @@ defmodule Server do
}), }),
instance: state.instance + 1 instance: state.instance + 1
} }
else true ->
%{state | %{state |
games: Map.put(state.games, game_id, :not_playing_in_it), games: Map.put(state.games, game_id, :not_playing_in_game),
instance: state.instance + 1, instance: state.instance + 1,
} }
end end
end end
def apply_game(state, _), 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
@ -174,28 +211,31 @@ defmodule Server do
{:start_game_ans, game_id} -> {:start_game_ans, game_id} ->
log("Started a game #{game_id}") log("Started a game #{game_id}")
{:start_game, game_id} {:start_game, game_id}
after
1000 -> :timeout
end
def start_game_loop() do
receive do
{:start_game_ans, game_id} ->
log("Started a game #{game_id}")
{:start_game, game_id}
v ->
Process.send_after(self(), v, 1000)
start_game_loop()
after
1000 -> :timeout
end
end end
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) start_game_loop(nil, 1000)
end end
create_loop :get_game_state do
{:game_state, ^v, :not_playing} ->
IO.puts("Not Playing in that game")
:not_playing
{:game_state, ^v, game_state, hand} ->
IO.puts("Got game state, #{inspect(game_state)}, hand: #{inspect(hand)}")
{game_state, hand}
{:game_state, ^v, :game_does_not_exist} ->
IO.puts("Got game does not exist")
nil
end
def get_game_state(name, game_id) do
safecast(name, {:get_game_state, game_id, self()})
get_game_state_loop(game_id, 1000)
end
############ ############
# Debug # Debug
############ ############