aboutsummaryrefslogtreecommitdiff
path: root/judge/core.ml
diff options
context:
space:
mode:
authorAlex AUVOLAT <alex.auvolat@ens.fr>2014-11-10 09:56:13 +0100
committerAlex AUVOLAT <alex.auvolat@ens.fr>2014-11-10 09:56:13 +0100
commitd343fcb803e955504b0d6b5c9c852620886c2994 (patch)
tree0b60abd9a3c9036ccf45da491b10d7d64ce71321 /judge/core.ml
parent5fecbfb6532487efc711eb1a9763535db720a291 (diff)
downloadCompetIA-d343fcb803e955504b0d6b5c9c852620886c2994.tar.gz
CompetIA-d343fcb803e955504b0d6b5c9c852620886c2994.zip
RETAB!
Diffstat (limited to 'judge/core.ml')
-rw-r--r--judge/core.ml632
1 files changed, 316 insertions, 316 deletions
diff --git a/judge/core.ml b/judge/core.ml
index 259bc1e..8ffdc47 100644
--- a/judge/core.ml
+++ b/judge/core.ml
@@ -8,53 +8,53 @@ type player = P1 | P2
let other_player = function P1 -> P2 | P2 -> P1
type game_status =
- | TurnOf of player
- | Won of player
- | Tie
- | Eliminated of player
+ | TurnOf of player
+ | Won of player
+ | Tie
+ | Eliminated of player
type player_proc_status =
- | Loading
- | StandBy of float (* temps restant sur toute la partie *)
- | Thinking of (float * float) (* temps restant ; heure de début de réflexion *)
- | Saving
- | Dead
+ | Loading
+ | StandBy of float (* temps restant sur toute la partie *)
+ | Thinking of (float * float) (* temps restant ; heure de début de réflexion *)
+ | Saving
+ | Dead
module type GAME = sig
- type game (* immutable structure *)
+ type game (* immutable structure *)
- val name : string (* ex: Morpion récursif *)
- val id : string (* ex: morpion_rec *)
+ val name : string (* ex: Morpion récursif *)
+ val id : string (* ex: morpion_rec *)
- val new_game : game
+ val new_game : game
- val play : game -> player -> string -> game
- val s : game -> game_status
+ val play : game -> player -> string -> game
+ val s : game -> game_status
- val display_game : game -> (string * string) -> unit
+ val display_game : game -> (string * string) -> unit
end
module type CORE = sig
- module G : GAME
+ module G : GAME
- type game
- val p1 : game -> player_proc_status
- val p2 : game -> player_proc_status
- val pn : game -> string * string
- val s : game -> game_status
- val g : game -> G.game
- val hist : game -> G.game list (* head: same as g g *)
+ type game
+ val p1 : game -> player_proc_status
+ val p2 : game -> player_proc_status
+ val pn : game -> string * string
+ val s : game -> game_status
+ val g : game -> G.game
+ val hist : game -> G.game list (* head: same as g g *)
- val init : unit -> unit
- val finish : unit -> unit
+ val init : unit -> unit
+ val finish : unit -> unit
- val handle_events : unit -> unit (* is anything happening ? *)
+ val handle_events : unit -> unit (* is anything happening ? *)
- val add_rounds : unit -> unit (* adds one game of everyone against everyone *)
+ val add_rounds : unit -> unit (* adds one game of everyone against everyone *)
- val ql : unit -> int
- val scores : unit -> (string * int) list
- val games : unit -> game list
+ val ql : unit -> int
+ val scores : unit -> (string * int) list
+ val games : unit -> game list
end
@@ -63,289 +63,289 @@ end
(* ****************************************** *)
module Core (G: GAME) : CORE = struct
- module G : GAME = G
-
- exception Eliminated_ex of string
-
- type player = {
- name: string;
- binary: string;
- dir: string;
- log_out: file_descr;
- mutable score: int;
- mutable running: player_proc option;
- }
-
- and player_proc = {
- pid: int;
- p: player;
- i: in_channel;
- o: out_channel;
- mutable s: player_proc_status;
- }
- let send_m pp m =
- output_string pp.o (encode m ^ "\n");
- flush pp.o
-
- type game = {
- mutable hist: G.game list;
- p1: player_proc;
- p2: player_proc;
- mutable s: game_status;
- }
- let p1 g = g.p1.s
- let p2 g = g.p2.s
- let pn g = (g.p1.p.name, g.p2.p.name)
- let s g = g.s
- let g g = List.hd g.hist
- let hist g = g.hist
-
- let players = Hashtbl.create 12
- let planned_games = ref []
- let r_games = ref []
-
- let ql () = List.length !planned_games
-
- (* program paremeters *)
- let par_games = ref 2 (* default: launch two simultaneous games *)
- let game_time = ref 30.0 (* default: 30 sec for each player *)
- let pt_win = ref 3 (* default: on win, score += 3 *)
- let pt_tie = ref 1 (* default: on tie, score += 1 *)
- let pt_lose = ref 0 (* default: on lose, score does not change *)
- let pt_elim = ref (-1) (* default: on eliminated, score -= 1 *)
-
- let scores () =
- Hashtbl.fold (fun _ p l -> (p.name, p.score)::l) players []
- let games () = !r_games
-
- let init () =
- (* 1. PARSE ARGUMENTS *)
- let game_dir = ref "" in
- let args = [
- "-p", Arg.Set_int par_games, "How many games to run in parallel (2)";
- "-s", Arg.Set_float game_time,
- "Time (seconds) allotted to each player for a game (30)";
- "-w", Arg.Set_int pt_win, "Points granted on win (+3)";
- "-t", Arg.Set_int pt_tie, "Points granted on tie (+1)";
- "-l", Arg.Set_int pt_lose, "Points granted on lose (0)";
- "-e", Arg.Set_int pt_elim, "Points granted on eliminated (-1)";
-
- ] in
- Arg.parse args (fun s -> game_dir := s)
- "Usage: judge <game_directory>";
- if !game_dir = "" then begin
- Format.eprintf "Error: no game directory specified.@.";
- exit 1
- end;
- if Filename.is_relative !game_dir then
- game_dir := Filename.concat (Unix.getcwd()) !game_dir;
- let date =
- let d = Unix.gmtime (Unix.gettimeofday ()) in
- Format.sprintf "%04d%02d%02d%02d%02d" (d.tm_year+1900) (d.tm_mon+1) d.tm_mday d.tm_hour d.tm_min
- in
-
- (* 2. REDIRECT STDOUT TO LOG FILE *)
- let log_file = Filename.concat !game_dir (date^".log") in
- Format.printf "Juge for '%s' starting up...@." G.name;
- Format.printf "Redirecting standard output to '%s'.@." log_file;
- flush Pervasives.stdout;
- begin try
- let log_out = Unix.openfile log_file [O_APPEND; O_CREAT; O_WRONLY] 0o644 in
- dup2 log_out Unix.stdout
- with _ ->
- Format.eprintf "Could not open log output file.@.";
- exit 1
- end;
- Format.printf "Juge for '%s' starting up...@." G.name;
- Format.printf "Session: %s@." date;
-
- (* 3. LOAD PLAYER LIST *)
- Format.printf "Loading player list...@.";
- let fd = try opendir !game_dir with _ ->
- Format.printf "Could not open directory %s for listing.@." !game_dir;
- exit 1
- in
- let rec rd () =
- try let s = readdir fd in
- begin try
- let dir = Filename.concat !game_dir s in
- let b = Filename.concat dir "player" in
- let st = Unix.stat b in
- if (st.st_kind = S_REG || st.st_kind = S_LNK)
- && (st.st_perm land 0o100 <> 0) then begin
- Format.printf "- %s@." s;
- (* open log output for player *)
- let p_log_file = Filename.concat dir "stderr.log" in
- let p_log_out = Unix.openfile p_log_file [O_APPEND; O_CREAT; O_WRONLY] 0o644 in
- let f = Format.formatter_of_out_channel (out_channel_of_descr p_log_out) in
- Format.fprintf f "---- Begin session %s@." date;
- Hashtbl.add players s
- { name = s;
- binary = b;
- dir;
- log_out = p_log_out;
- score = 0;
- running = None; }
- end
- with _ -> () end;
- rd()
- with End_of_file -> ()
- in rd (); closedir fd
-
- let finish () =
- (* TODO :
- - save scores
- - kill all child processes and wait for them
- *)
- ()
-
- let add_rounds () =
- Hashtbl.iter
- (fun p _ -> Hashtbl.iter
- (fun q _ -> if p <> q then planned_games := (p, q)::!planned_games)
- players)
- players
-
- let handle_events () =
- (* 1. IF NOT ENOUGH MATCHES ARE RUNING, LAUNCH ONE *)
- let matches_in_progress = List.length
- (List.filter
- (fun g -> match g.p1.s, g.p2.s with Dead, Dead -> false | _ -> true)
- !r_games)
- in
- let launch_match p1 p2 =
- Format.printf "Launching match: %s vs. %s@." p1 p2;
-
- let open_c p =
- let f = Format.formatter_of_out_channel (out_channel_of_descr p.log_out) in
- Format.fprintf f "--- Begin game (%s vs. %s)@." p1 p2;
- let (j2p_i, j2p_o) = pipe () in
- let (p2j_i, p2j_o) = pipe () in
- let pid = fork() in
- if pid = 0 then begin
- chdir p.dir;
- dup2 j2p_i stdin;
- dup2 p2j_o stdout;
- dup2 p.log_out stderr;
- execvp p.binary [| p.binary |];
- end;
- Format.printf "- %s: pid %d@." p.name pid;
- let pl = { pid; p;
- i = in_channel_of_descr p2j_i;
- o = out_channel_of_descr j2p_o;
- s = Loading } in
- p.running <- Some pl;
- send_m pl (Hello G.id);
- pl
- in
- let p1 = open_c (Hashtbl.find players p1) in
- let p2 = open_c (Hashtbl.find players p2) in
- let g = G.new_game in
- let g = { p1; p2; hist = [g]; s = G.s g } in
- r_games := g::(!r_games)
- in
- let can_launch, cannot_launch = List.partition
- (fun (p1, p2) ->
- (Hashtbl.find players p1).running = None
- && (Hashtbl.find players p2).running = None)
- !planned_games
- in
- begin match can_launch with
- | (p1, p2)::q when matches_in_progress < !par_games ->
- launch_match p1 p2;
- planned_games := q @ cannot_launch
- | _ -> ()
- end;
- (* 2. LOOK IF ANYBODY IS TELLING US SOMETHING - IF SO, REACT
- (wait max. 0.01 sec) *)
- let in_fd = List.fold_left
- (fun l g ->
- let l = match g.p1.s with
- | Dead -> l
- | _ -> (Unix.descr_of_in_channel g.p1.i)::l
- in match g.p2.s with
- | Dead -> l
- | _ -> (Unix.descr_of_in_channel g.p2.i)::l)
- [] !r_games
- in
- let in_fd, _, _ =
- try select in_fd [] [] 0.01
- with
- Unix_error (EINTR, _, _) -> [], [], []
- in
- let do_fd fd =
- let g = List.find
- (fun g -> fd = Unix.descr_of_in_channel g.p1.i
- || fd = Unix.descr_of_in_channel g.p2.i)
- !r_games
- in
- let pi = if Unix.descr_of_in_channel g.p1.i = fd then P1 else P2 in
- let p = match pi with P1 -> g.p1 | P2 -> g.p2 in
- let op = match pi with P1 -> g.p2 | P2 -> g.p1 in
- begin try match decode (input_line p.i), p.s with
- | Hello x, Loading when x = G.id ->
- p.s <- StandBy !game_time;
- | Play act, Thinking (time, beg_r) ->
- let end_r = Unix.gettimeofday () in
- let new_g = G.play (List.hd g.hist) pi act in
- let new_s = G.s new_g in
- send_m p OK;
- send_m op (Play act);
- g.s <- new_s;
- g.hist <- new_g::g.hist;
- let finished = match new_s with
- | Tie ->
- send_m p Tie;
- send_m op Tie;
- Format.printf "%s vs. %s: tie!@." g.p1.p.name g.p2.p.name;
- p.p.score <- p.p.score + !pt_tie;
- op.p.score <- op.p.score + !pt_tie;
- true
- | Won x ->
- let (w, l) = if x = P1 then (g.p1, g.p2) else (g.p2, g.p1) in
- send_m w YouWin;
- send_m l YouLose;
- Format.printf "%s vs. %s: %s wins!@." g.p1.p.name g.p2.p.name w.p.name;
- w.p.score <- w.p.score + !pt_win;
- l.p.score <- l.p.score + !pt_lose;
- true
- | TurnOf _ -> false
- | Eliminated _ -> raise (Eliminated_ex ("invalid move: " ^ act))
- in
- if finished then begin
- p.s <- Saving;
- op.s <- Saving;
- end else begin
- p.s <- StandBy (time -. (end_r -. beg_r));
- end
- | FairEnough, Saving ->
- kill p.pid Sys.sigterm;
- p.s <- Dead;
- p.p.running <- None;
- | bad_m, _ -> raise (Eliminated_ex ("unexpected message: '" ^ encode bad_m ^ "'"))
- | exception Invalid_message m -> raise (Eliminated_ex ("invalid message: '" ^ m ^"'"))
- | exception _ -> raise (Eliminated_ex "exception when reading message")
- with
- | Eliminated_ex r ->
- send_m p Eliminated;
- send_m op YouWin;
- (* since process is not respecting the protocol, we cannot assume
- it is doing anything reasonable, so we kill it... *)
- kill p.pid Sys.sigterm;
- Format.printf "%s vs. %s: %s eliminated (%s)!@." g.p1.p.name g.p2.p.name p.p.name r;
- p.s <- Dead;
- p.p.running <- None;
- p.p.score <- p.p.score + !pt_elim;
- op.s <- Saving;
- g.s <- Eliminated pi
- end;
- begin match g.s, g.p1.s, g.p2.s, g.p1, g.p2 with
- | TurnOf P1, StandBy t, StandBy _, p, _
- | TurnOf P2, StandBy _, StandBy t, _, p ->
- send_m p (YourTurn t);
- p.s <- Thinking (t, Unix.gettimeofday());
- | _ -> ()
- end
- in List.iter do_fd in_fd
-
+ module G : GAME = G
+
+ exception Eliminated_ex of string
+
+ type player = {
+ name: string;
+ binary: string;
+ dir: string;
+ log_out: file_descr;
+ mutable score: int;
+ mutable running: player_proc option;
+ }
+
+ and player_proc = {
+ pid: int;
+ p: player;
+ i: in_channel;
+ o: out_channel;
+ mutable s: player_proc_status;
+ }
+ let send_m pp m =
+ output_string pp.o (encode m ^ "\n");
+ flush pp.o
+
+ type game = {
+ mutable hist: G.game list;
+ p1: player_proc;
+ p2: player_proc;
+ mutable s: game_status;
+ }
+ let p1 g = g.p1.s
+ let p2 g = g.p2.s
+ let pn g = (g.p1.p.name, g.p2.p.name)
+ let s g = g.s
+ let g g = List.hd g.hist
+ let hist g = g.hist
+
+ let players = Hashtbl.create 12
+ let planned_games = ref []
+ let r_games = ref []
+
+ let ql () = List.length !planned_games
+
+ (* program paremeters *)
+ let par_games = ref 2 (* default: launch two simultaneous games *)
+ let game_time = ref 30.0 (* default: 30 sec for each player *)
+ let pt_win = ref 3 (* default: on win, score += 3 *)
+ let pt_tie = ref 1 (* default: on tie, score += 1 *)
+ let pt_lose = ref 0 (* default: on lose, score does not change *)
+ let pt_elim = ref (-1) (* default: on eliminated, score -= 1 *)
+
+ let scores () =
+ Hashtbl.fold (fun _ p l -> (p.name, p.score)::l) players []
+ let games () = !r_games
+
+ let init () =
+ (* 1. PARSE ARGUMENTS *)
+ let game_dir = ref "" in
+ let args = [
+ "-p", Arg.Set_int par_games, "How many games to run in parallel (2)";
+ "-s", Arg.Set_float game_time,
+ "Time (seconds) allotted to each player for a game (30)";
+ "-w", Arg.Set_int pt_win, "Points granted on win (+3)";
+ "-t", Arg.Set_int pt_tie, "Points granted on tie (+1)";
+ "-l", Arg.Set_int pt_lose, "Points granted on lose (0)";
+ "-e", Arg.Set_int pt_elim, "Points granted on eliminated (-1)";
+
+ ] in
+ Arg.parse args (fun s -> game_dir := s)
+ "Usage: judge <game_directory>";
+ if !game_dir = "" then begin
+ Format.eprintf "Error: no game directory specified.@.";
+ exit 1
+ end;
+ if Filename.is_relative !game_dir then
+ game_dir := Filename.concat (Unix.getcwd()) !game_dir;
+ let date =
+ let d = Unix.gmtime (Unix.gettimeofday ()) in
+ Format.sprintf "%04d%02d%02d%02d%02d" (d.tm_year+1900) (d.tm_mon+1) d.tm_mday d.tm_hour d.tm_min
+ in
+
+ (* 2. REDIRECT STDOUT TO LOG FILE *)
+ let log_file = Filename.concat !game_dir (date^".log") in
+ Format.printf "Juge for '%s' starting up...@." G.name;
+ Format.printf "Redirecting standard output to '%s'.@." log_file;
+ flush Pervasives.stdout;
+ begin try
+ let log_out = Unix.openfile log_file [O_APPEND; O_CREAT; O_WRONLY] 0o644 in
+ dup2 log_out Unix.stdout
+ with _ ->
+ Format.eprintf "Could not open log output file.@.";
+ exit 1
+ end;
+ Format.printf "Juge for '%s' starting up...@." G.name;
+ Format.printf "Session: %s@." date;
+
+ (* 3. LOAD PLAYER LIST *)
+ Format.printf "Loading player list...@.";
+ let fd = try opendir !game_dir with _ ->
+ Format.printf "Could not open directory %s for listing.@." !game_dir;
+ exit 1
+ in
+ let rec rd () =
+ try let s = readdir fd in
+ begin try
+ let dir = Filename.concat !game_dir s in
+ let b = Filename.concat dir "player" in
+ let st = Unix.stat b in
+ if (st.st_kind = S_REG || st.st_kind = S_LNK)
+ && (st.st_perm land 0o100 <> 0) then begin
+ Format.printf "- %s@." s;
+ (* open log output for player *)
+ let p_log_file = Filename.concat dir "stderr.log" in
+ let p_log_out = Unix.openfile p_log_file [O_APPEND; O_CREAT; O_WRONLY] 0o644 in
+ let f = Format.formatter_of_out_channel (out_channel_of_descr p_log_out) in
+ Format.fprintf f "---- Begin session %s@." date;
+ Hashtbl.add players s
+ { name = s;
+ binary = b;
+ dir;
+ log_out = p_log_out;
+ score = 0;
+ running = None; }
+ end
+ with _ -> () end;
+ rd()
+ with End_of_file -> ()
+ in rd (); closedir fd
+
+ let finish () =
+ (* TODO :
+ - save scores
+ - kill all child processes and wait for them
+ *)
+ ()
+
+ let add_rounds () =
+ Hashtbl.iter
+ (fun p _ -> Hashtbl.iter
+ (fun q _ -> if p <> q then planned_games := (p, q)::!planned_games)
+ players)
+ players
+
+ let handle_events () =
+ (* 1. IF NOT ENOUGH MATCHES ARE RUNING, LAUNCH ONE *)
+ let matches_in_progress = List.length
+ (List.filter
+ (fun g -> match g.p1.s, g.p2.s with Dead, Dead -> false | _ -> true)
+ !r_games)
+ in
+ let launch_match p1 p2 =
+ Format.printf "Launching match: %s vs. %s@." p1 p2;
+
+ let open_c p =
+ let f = Format.formatter_of_out_channel (out_channel_of_descr p.log_out) in
+ Format.fprintf f "--- Begin game (%s vs. %s)@." p1 p2;
+ let (j2p_i, j2p_o) = pipe () in
+ let (p2j_i, p2j_o) = pipe () in
+ let pid = fork() in
+ if pid = 0 then begin
+ chdir p.dir;
+ dup2 j2p_i stdin;
+ dup2 p2j_o stdout;
+ dup2 p.log_out stderr;
+ execvp p.binary [| p.binary |];
+ end;
+ Format.printf "- %s: pid %d@." p.name pid;
+ let pl = { pid; p;
+ i = in_channel_of_descr p2j_i;
+ o = out_channel_of_descr j2p_o;
+ s = Loading } in
+ p.running <- Some pl;
+ send_m pl (Hello G.id);
+ pl
+ in
+ let p1 = open_c (Hashtbl.find players p1) in
+ let p2 = open_c (Hashtbl.find players p2) in
+ let g = G.new_game in
+ let g = { p1; p2; hist = [g]; s = G.s g } in
+ r_games := g::(!r_games)
+ in
+ let can_launch, cannot_launch = List.partition
+ (fun (p1, p2) ->
+ (Hashtbl.find players p1).running = None
+ && (Hashtbl.find players p2).running = None)
+ !planned_games
+ in
+ begin match can_launch with
+ | (p1, p2)::q when matches_in_progress < !par_games ->
+ launch_match p1 p2;
+ planned_games := q @ cannot_launch
+ | _ -> ()
+ end;
+ (* 2. LOOK IF ANYBODY IS TELLING US SOMETHING - IF SO, REACT
+ (wait max. 0.01 sec) *)
+ let in_fd = List.fold_left
+ (fun l g ->
+ let l = match g.p1.s with
+ | Dead -> l
+ | _ -> (Unix.descr_of_in_channel g.p1.i)::l
+ in match g.p2.s with
+ | Dead -> l
+ | _ -> (Unix.descr_of_in_channel g.p2.i)::l)
+ [] !r_games
+ in
+ let in_fd, _, _ =
+ try select in_fd [] [] 0.01
+ with
+ Unix_error (EINTR, _, _) -> [], [], []
+ in
+ let do_fd fd =
+ let g = List.find
+ (fun g -> fd = Unix.descr_of_in_channel g.p1.i
+ || fd = Unix.descr_of_in_channel g.p2.i)
+ !r_games
+ in
+ let pi = if Unix.descr_of_in_channel g.p1.i = fd then P1 else P2 in
+ let p = match pi with P1 -> g.p1 | P2 -> g.p2 in
+ let op = match pi with P1 -> g.p2 | P2 -> g.p1 in
+ begin try match decode (input_line p.i), p.s with
+ | Hello x, Loading when x = G.id ->
+ p.s <- StandBy !game_time;
+ | Play act, Thinking (time, beg_r) ->
+ let end_r = Unix.gettimeofday () in
+ let new_g = G.play (List.hd g.hist) pi act in
+ let new_s = G.s new_g in
+ send_m p OK;
+ send_m op (Play act);
+ g.s <- new_s;
+ g.hist <- new_g::g.hist;
+ let finished = match new_s with
+ | Tie ->
+ send_m p Tie;
+ send_m op Tie;
+ Format.printf "%s vs. %s: tie!@." g.p1.p.name g.p2.p.name;
+ p.p.score <- p.p.score + !pt_tie;
+ op.p.score <- op.p.score + !pt_tie;
+ true
+ | Won x ->
+ let (w, l) = if x = P1 then (g.p1, g.p2) else (g.p2, g.p1) in
+ send_m w YouWin;
+ send_m l YouLose;
+ Format.printf "%s vs. %s: %s wins!@." g.p1.p.name g.p2.p.name w.p.name;
+ w.p.score <- w.p.score + !pt_win;
+ l.p.score <- l.p.score + !pt_lose;
+ true
+ | TurnOf _ -> false
+ | Eliminated _ -> raise (Eliminated_ex ("invalid move: " ^ act))
+ in
+ if finished then begin
+ p.s <- Saving;
+ op.s <- Saving;
+ end else begin
+ p.s <- StandBy (time -. (end_r -. beg_r));
+ end
+ | FairEnough, Saving ->
+ kill p.pid Sys.sigterm;
+ p.s <- Dead;
+ p.p.running <- None;
+ | bad_m, _ -> raise (Eliminated_ex ("unexpected message: '" ^ encode bad_m ^ "'"))
+ | exception Invalid_message m -> raise (Eliminated_ex ("invalid message: '" ^ m ^"'"))
+ | exception _ -> raise (Eliminated_ex "exception when reading message")
+ with
+ | Eliminated_ex r ->
+ send_m p Eliminated;
+ send_m op YouWin;
+ (* since process is not respecting the protocol, we cannot assume
+ it is doing anything reasonable, so we kill it... *)
+ kill p.pid Sys.sigterm;
+ Format.printf "%s vs. %s: %s eliminated (%s)!@." g.p1.p.name g.p2.p.name p.p.name r;
+ p.s <- Dead;
+ p.p.running <- None;
+ p.p.score <- p.p.score + !pt_elim;
+ op.s <- Saving;
+ g.s <- Eliminated pi
+ end;
+ begin match g.s, g.p1.s, g.p2.s, g.p1, g.p2 with
+ | TurnOf P1, StandBy t, StandBy _, p, _
+ | TurnOf P2, StandBy _, StandBy t, _, p ->
+ send_m p (YourTurn t);
+ p.s <- Thinking (t, Unix.gettimeofday());
+ | _ -> ()
+ end
+ in List.iter do_fd in_fd
+
end