aboutsummaryrefslogtreecommitdiff
path: root/judge/core.ml
diff options
context:
space:
mode:
Diffstat (limited to 'judge/core.ml')
-rw-r--r--judge/core.ml117
1 files changed, 68 insertions, 49 deletions
diff --git a/judge/core.ml b/judge/core.ml
index 70e2bd4..4411937 100644
--- a/judge/core.ml
+++ b/judge/core.ml
@@ -5,6 +5,7 @@ open Protocol
(* Description of data structures *)
type player = P1 | P2
+let other_player = function P1 -> P2 | P2 -> P1
type game_status =
| TurnOf of player
@@ -12,11 +13,6 @@ type game_status =
| Tie
| Eliminated of player
-type game_proc_status =
- | Initializing of game_status
- | Running of game_status
- | Finished of game_status
-
type player_proc_status =
| Loading
| StandBy of float (* temps restant sur toute la partie *)
@@ -41,7 +37,8 @@ module type CORE = sig
type game
val p1 : game -> player_proc_status
val p2 : game -> player_proc_status
- val s : game -> game_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 *)
@@ -52,6 +49,7 @@ module type CORE = sig
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
@@ -61,7 +59,7 @@ end
(* BEGIN IMPLEMENTATION *)
(* ****************************************** *)
-module C (G: GAME) : CORE = struct
+module Core (G: GAME) : CORE = struct
module G : GAME = G
exception Eliminated_ex of string
@@ -72,9 +70,10 @@ module C (G: GAME) : CORE = struct
dir: string;
log_out: file_descr;
mutable score: int;
+ mutable running: player_proc option;
}
- type player_proc = {
+ and player_proc = {
pid: int;
p: player;
i: in_channel;
@@ -89,18 +88,21 @@ module C (G: GAME) : CORE = struct
mutable hist: G.game list;
p1: player_proc;
p2: player_proc;
- mutable s: game_proc_status;
+ 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 = Queue.create ()
+ 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 *)
@@ -132,9 +134,11 @@ module C (G: GAME) : CORE = struct
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.time ()) in
- Format.sprintf "%04d%02d%02d%02d%02d" d.tm_year d.tm_mon d.tm_mday d.tm_hour d.tm_min
+ 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 *)
@@ -160,7 +164,7 @@ module C (G: GAME) : CORE = struct
in
let rec rd () =
try let s = readdir fd in
- try
+ begin try
let dir = Filename.concat !game_dir s in
let b = Filename.concat dir "player" in
let st = Unix.stat b in
@@ -177,12 +181,13 @@ module C (G: GAME) : CORE = struct
binary = b;
dir;
log_out = p_log_out;
- score = 0; }
+ score = 0;
+ running = None; }
end
- with _ -> ();
+ with _ -> () end;
rd()
with End_of_file -> ()
- in rd ()
+ in rd (); closedir fd
let finish () =
(* TODO :
@@ -194,18 +199,18 @@ module C (G: GAME) : CORE = struct
let add_rounds () =
Hashtbl.iter
(fun p _ -> Hashtbl.iter
- (fun q _ -> if p <> q then Queue.push (p, q) planned_games)
+ (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 *)
- while (List.length
- (List.filter (fun g -> match g.s with Finished _ -> false | _ -> true)
- !r_games)) < !par_games
- && Queue.length planned_games > 0
- do
- let p1, p2 = Queue.pop planned_games in
+ 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 =
@@ -219,38 +224,52 @@ module C (G: GAME) : CORE = struct
dup2 j2p_i stdin;
dup2 p2j_o stdout;
dup2 p.log_out stderr;
- execv p.binary [| p.binary |];
+ 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, s = G.new_game in
- let g = { p1; p2; hist = [g]; s = Initializing s } in
+ let g = { p1; p2; hist = [g]; s } in
r_games := g::(!r_games)
- done;
-
+ 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 -> match g.s with
- | Finished _ -> l
- | _ ->
- 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)
+ (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, _, _ = select in_fd [] [] 0.01 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
@@ -264,21 +283,21 @@ module C (G: GAME) : CORE = struct
| Hello x, Loading when x = G.id ->
p.s <- StandBy !game_time;
begin match g.s, g.p1.s, g.p2.s, g.p1, g.p2 with
- | Initializing (TurnOf P1), StandBy t, StandBy _, p, _
- | Initializing (TurnOf P2), StandBy _, StandBy t, _, p ->
+ | TurnOf P1, StandBy t, StandBy _, p, _
+ | TurnOf P2, StandBy _, StandBy t, _, p ->
send_m p (YourTurn t);
- p.s <- Thinking (t, Unix.time());
- g.s <- Running (TurnOf P1)
+ p.s <- Thinking (t, Unix.gettimeofday());
| _ -> ()
end
| Play act, Thinking (time, beg_r) ->
- let end_r = Unix.time () in
+ let end_r = Unix.gettimeofday () in
let new_g, new_s = G.turn (List.hd g.hist) pi act in
begin match new_s with
| Eliminated _ -> raise (Eliminated_ex ("invalid move: " ^ act)) | _ -> ()
end;
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 ->
@@ -302,19 +321,18 @@ module C (G: GAME) : CORE = struct
if finished then begin
p.s <- Saving;
op.s <- Saving;
- g.s <- Finished new_s
end else begin
p.s <- StandBy (time -. (end_r -. beg_r));
- g.s <- Running new_s;
match op.s with
| StandBy t ->
send_m op (YourTurn t);
- op.s <- Thinking (t, Unix.time())
+ op.s <- Thinking (t, Unix.gettimeofday ())
| _ -> assert false
end
| FairEnough, Saving ->
- kill p.pid 15; (* 15 : sigterm *)
- p.s <- Dead
+ 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")
@@ -324,12 +342,13 @@ module C (G: GAME) : CORE = struct
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 15;
+ 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 <- Finished (Eliminated pi)
+ g.s <- Eliminated pi
end;
in List.iter do_fd in_fd