diff options
author | Alex AUVOLAT <alex.auvolat@ens.fr> | 2014-11-09 22:04:48 +0100 |
---|---|---|
committer | Alex AUVOLAT <alex.auvolat@ens.fr> | 2014-11-09 22:04:48 +0100 |
commit | 415c2c5529e7d33f6ec1236e607ee1f62509de4b (patch) | |
tree | f7d113a749ec944263780e171c8a941a7f8239aa /judge/core.ml | |
parent | e17b538a1a541cb83794f044027c6fc2bc7e0aae (diff) | |
download | CompetIA-415c2c5529e7d33f6ec1236e607ee1f62509de4b.tar.gz CompetIA-415c2c5529e7d33f6ec1236e607ee1f62509de4b.zip |
Implement a part of the judge UI; add dummy game & player for testing purposes.
Diffstat (limited to 'judge/core.ml')
-rw-r--r-- | judge/core.ml | 117 |
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 |