[Toss-devel-svn] SF.net SVN: toss:[1657] trunk/Toss
Status: Beta
Brought to you by:
lukaszkaiser
From: <luk...@us...> - 2012-02-01 10:17:29
|
Revision: 1657 http://toss.svn.sourceforge.net/toss/?rev=1657&view=rev Author: lukstafi Date: 2012-02-01 10:17:21 +0000 (Wed, 01 Feb 2012) Log Message: ----------- Standalone variant of JavaScript interface. Modified Paths: -------------- trunk/Toss/Formula/Aux.ml trunk/Toss/Formula/Aux.mli trunk/Toss/Formula/AuxIO.ml trunk/Toss/Formula/BoolFormula.ml trunk/Toss/Learn/LearnGameTest.ml trunk/Toss/Makefile trunk/Toss/Play/GameTree.ml trunk/Toss/Play/Move.mli trunk/Toss/Play/Play.ml trunk/Toss/Play/Play.mli trunk/Toss/Solver/RealQuantElim/OrderedPoly.ml trunk/Toss/Solver/RealQuantElim/OrderedPoly.mli trunk/Toss/Solver/RealQuantElim/Poly.ml trunk/Toss/Solver/RealQuantElim/SignTable.ml trunk/Toss/Solver/Structure.ml trunk/Toss/WebClient/Main.js trunk/Toss/WebClient/Play.js trunk/Toss/WebClient/State.js trunk/Toss/www/reference/reference.tex Added Paths: ----------- trunk/Toss/Server/GameSelection.ml trunk/Toss/Server/JsHandler.ml trunk/Toss/Solver/RealQuantElim/N.ml trunk/Toss/WebClient/JsHandler.js trunk/Toss/WebClient/Local.js trunk/Toss/WebClient/local.html trunk/Toss/www/reference/TossComponents.dot Modified: trunk/Toss/Formula/Aux.ml =================================================================== --- trunk/Toss/Formula/Aux.ml 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Formula/Aux.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -2,10 +2,12 @@ structures and standard library-like definitions. *) let gettimeofday () = - IFDEF NOUNIX - THEN 1. - ELSE Unix.gettimeofday () - ENDIF + IFDEF JAVASCRIPT THEN ( + let t = Js.to_float ((jsnew Js.date_now ())##getTime()) in + t /. 1000. (* t is in milliseconds *) + ) ELSE ( + Unix.gettimeofday () + ) ENDIF exception Timeout of string @@ -739,3 +741,34 @@ Gc.minor_heap_size = 160*1024; (* 4*std, opt ~= L2 cache/proc *) Gc.major_heap_increment = 8*124*1024 (* 8*std ok *) } + +(* Replacements for basic Str functions. *) + +(* [split_regexp ~regexp:r s] splits [s] into substrings, taking as + delimiters the substrings that match [r], and returns the list of + substrings. For instance, [split ~regexp:"[ \t]+" s] splits [s] + into blank-separated words. An occurrence of the delimiter at the + beginning and at the end of the string is ignored. *) +let split_regexp ~regexp s = + IFDEF JAVASCRIPT THEN ( + let js_s = Js.string s in + let js_regex = jsnew Js.regExp (Js.string regexp) in + let res = js_s##split_regExp (js_regex) in + let res = Js.to_array (Js.str_array res) in + Array.to_list (Array.map Js.to_string res) + ) ELSE ( + Str.split (Str.regexp regexp) s + ) ENDIF + +(* [replace_regexp ~regexp ~templ s] returns a string identical to + [s], except that all substrings of [s] that match [regexp] have + been replaced by [templ]. *) +let replace_regexp ~regexp ~templ s = + IFDEF JAVASCRIPT THEN ( + let js_s = Js.string s in + let js_regex = jsnew Js.regExp (Js.string regexp) in + let res = js_s##replace (js_regex, Js.string templ) in + Js.to_string res + ) ELSE ( + Str.global_replace (Str.regexp regexp) templ s + ) ENDIF Modified: trunk/Toss/Formula/Aux.mli =================================================================== --- trunk/Toss/Formula/Aux.mli 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Formula/Aux.mli 2012-02-01 10:17:21 UTC (rev 1657) @@ -355,3 +355,17 @@ (** Set more agressive Gc values optimized for heavier computations. *) val set_optimized_gc : unit -> unit + +(** Replacements for basic Str functions. *) + +(** [split_regexp ~regexp:r s] splits [s] into substrings, taking as + delimiters the substrings that match [r], and returns the list of + substrings. For instance, [split ~regexp:"[ \t]+" s] splits [s] + into blank-separated words. An occurrence of the delimiter at the + beginning and at the end of the string is ignored. *) +val split_regexp : regexp:string -> string -> string list + +(** [replace_regexp ~regexp ~templ s] returns a string identical to [s], + except that all substrings of [s] that match [regexp] have been + replaced by [templ]. *) +val replace_regexp : regexp:string -> templ:string -> string -> string Modified: trunk/Toss/Formula/AuxIO.ml =================================================================== --- trunk/Toss/Formula/AuxIO.ml 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Formula/AuxIO.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -14,12 +14,15 @@ if test_fname then f () let run_test_if_target target_name tests = - let f () = ignore (OUnit.run_test_tt ~verbose:true tests) in - (* So that the tests are not run twice while building TossTest. *) - run_if_target target_name f + IFDEF JAVASCRIPT THEN ( + failwith "JavaScript unit testing not implemented yet" + ) ELSE ( + let f () = ignore (OUnit.run_test_tt ~verbose:true tests) in + (* So that the tests are not run twice while building TossTest. *) + run_if_target target_name f + ) ENDIF - let rec input_file file = let buf = Buffer.create 256 in (try @@ -33,9 +36,14 @@ close_in f; res let list_dir dirname = - let files, dir_handle = (ref [], Unix.opendir dirname) in - let rec add () = files := (Unix.readdir dir_handle) :: !files; add () in - try add () with End_of_file -> Unix.closedir dir_handle; !files + IFDEF JAVASCRIPT THEN ( + failwith "JavaScript file manipulation not implemented yet" + ) ELSE ( + let files, dir_handle = (ref [], Unix.opendir dirname) in + let rec add () = + files := (Unix.readdir dir_handle) :: !files; add () in + try add () with End_of_file -> Unix.closedir dir_handle; !files + ) ENDIF let rec input_http_message file = let buf = Buffer.create 256 in @@ -76,29 +84,38 @@ exception Host_not_found let get_inet_addr addr_s = - try - Unix.inet_addr_of_string addr_s - with Failure _ -> + IFDEF JAVASCRIPT THEN ( + failwith "JavaScript TCP/IP manipulation not implemented yet" + ) ELSE ( try - let addr_arr = (Unix.gethostbyname addr_s).Unix.h_addr_list in - if Array.length addr_arr < 1 then raise Host_not_found else - addr_arr.(0) - with Not_found -> raise Host_not_found + Unix.inet_addr_of_string addr_s + with Failure _ -> + try + let addr_arr = (Unix.gethostbyname addr_s).Unix.h_addr_list in + if Array.length addr_arr < 1 then raise Host_not_found else + addr_arr.(0) + with Not_found -> raise Host_not_found + ) ENDIF let toss_call (client_port, client_addr_s) f_in x = - try - let client_addr = get_inet_addr client_addr_s in - let client_sock = Unix.ADDR_INET (client_addr, client_port) in - let (cl_in_ch, cl_out_ch) = Unix.open_connection client_sock in - output_string cl_out_ch "COMP\n"; - flush cl_out_ch; - let f a = try `Res (f_in a) with exn -> `Exn exn in - Marshal.to_channel cl_out_ch (f, x) [Marshal.Closures]; - flush cl_out_ch; - (fun () -> - let res = Marshal.from_channel cl_in_ch in - Unix.shutdown_connection cl_in_ch; - match res with `Res r -> r | `Exn e -> raise e) - with Unix.Unix_error (e, f, s) -> - Printf.printf "Toss call failed: %s; %s %s\n%!" (Unix.error_message e) f s; - (fun () -> f_in x) + IFDEF JAVASCRIPT THEN ( + failwith "JavaScript TCP/IP manipulation not implemented yet" + ) ELSE ( + try + let client_addr = get_inet_addr client_addr_s in + let client_sock = Unix.ADDR_INET (client_addr, client_port) in + let (cl_in_ch, cl_out_ch) = Unix.open_connection client_sock in + output_string cl_out_ch "COMP\n"; + flush cl_out_ch; + let f a = try `Res (f_in a) with exn -> `Exn exn in + Marshal.to_channel cl_out_ch (f, x) [Marshal.Closures]; + flush cl_out_ch; + (fun () -> + let res = Marshal.from_channel cl_in_ch in + Unix.shutdown_connection cl_in_ch; + match res with `Res r -> r | `Exn e -> raise e) + with Unix.Unix_error (e, f, s) -> + Printf.printf "Toss call failed: %s; %s %s\n%!" + (Unix.error_message e) f s; + (fun () -> f_in x) + ) ENDIF Modified: trunk/Toss/Formula/BoolFormula.ml =================================================================== --- trunk/Toss/Formula/BoolFormula.ml 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Formula/BoolFormula.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -945,7 +945,7 @@ !clause in let list_int line = - let split = Str.split (Str.regexp "[ \t]+") line in + let split = Aux.split_regexp ~regexp:"[ \t]+" line in List.rev (List.tl (List.rev_map (fun s -> int_of_string s) (List.tl split))) in Modified: trunk/Toss/Learn/LearnGameTest.ml =================================================================== --- trunk/Toss/Learn/LearnGameTest.ml 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Learn/LearnGameTest.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -84,7 +84,8 @@ let get_strucs s = let split_list ?(bound=None) pat s = let r = Str.regexp_string pat in - match bound with None-> Str.split r s | Some b-> Str.bounded_split r s b in + match bound with None-> Str.split r s + | Some b-> Str.bounded_split r s b in let cl = String.index s '\n' in let pref, st_s = String.sub s 0 cl, String.sub s cl ((String.length s)-cl) in let strucstr s = pref ^ " \n\"" ^ s ^ "\n\"" in Modified: trunk/Toss/Makefile =================================================================== --- trunk/Toss/Makefile 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Makefile 2012-02-01 10:17:21 UTC (rev 1657) @@ -3,9 +3,13 @@ TossServer: Server/Server.native cp _build/Server/Server.native TossServer -js_of_ocaml_test.js: js_of_ocaml_test.byte - js_of_ocaml js_of_ocaml_test.byte +WebClient/JsHandler.js: Server/JsHandler.byte + js_of_ocaml _build/$< + cp _build/Server/JsHandler.js WebClient/JsHandler.js +%.js: %.byte + js_of_ocaml _build/$< + RELEASE=0.6 Release: TossServer doc rm -f *~ Formula/*~ Solver/*~ Arena/*~ Play/*~ GGP/*~ \ @@ -41,7 +45,7 @@ OCB_LIB=-libs str,nums,unix,oUnit,sqlite3 OCB_LIBJS=-libs str,js_of_ocaml OCB_PP=-pp "camlp4o -I /usr/local/lib/ocaml/3.12.0 ../caml_extensions/pa_let_try.cmo pa_macro.cmo js_of_ocaml/pa_js.cmo" -OCB_PPJS=-pp "camlp4o -I /usr/local/lib/ocaml/3.12.0 ../caml_extensions/pa_let_try.cmo pa_macro.cmo -DNOREALQE -DNOUNIX js_of_ocaml/pa_js.cmo" +OCB_PPJS=-pp "camlp4o -I /usr/local/lib/ocaml/3.12.0 ../caml_extensions/pa_let_try.cmo pa_macro.cmo -DJAVASCRIPT js_of_ocaml/pa_js.cmo" OCAMLBUILD=ocamlbuild -log build.log -j 8 -menhir ../menhir_conf $(OCB_PP) \ $(OCB_LIB) $(OCB_CFLAG) $(OCB_LFLAG) OCAMLBUILDJS=ocamlbuild -log build.log -j 8 -menhir ../menhir_conf $(OCB_PPJS) \ Modified: trunk/Toss/Play/GameTree.ml =================================================================== --- trunk/Toss/Play/GameTree.ml 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Play/GameTree.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -39,7 +39,7 @@ player state.Arena.cur_loc state.Arena.time in let res = "\n" ^ msg ^ head_s ^ struc_s ^ "\n" ^ info_s in let prefix = if depth=0 then "" else (String.make depth '|') ^ " " in - Str.global_replace (Str.regexp "\n") ("\n" ^ prefix) res in + Aux.replace_regexp ~regexp:"\n" ~templ:("\n" ^ prefix) res in if upto < 0 then " Cut;" else match tree with | Terminal (state, player, info) -> Modified: trunk/Toss/Play/Move.mli =================================================================== --- trunk/Toss/Play/Move.mli 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Play/Move.mli 2012-02-01 10:17:21 UTC (rev 1657) @@ -12,12 +12,18 @@ TODO: fixed for now. *) val cGRID_SIZE : int -(** Generate moves available from a state, as an array, in fixed order. *) +(** Generate moves available from a state, as an array, in fixed + order. Does not check postconditions. *) val gen_moves : int -> (string * ContinuousRule.rule) list -> Structure.structure -> Arena.player_loc -> Arena.move array +(** Given moves available from a state, keep those for which + postconditions pass, and return the respective resulting game states. *) val gen_models : (string * ContinuousRule.rule) list -> Arena.game_state -> float -> Arena.move array -> Arena.move array * Arena.game_state array +(** Get moves and resulting game states, like {!Move.gen_models}, but for + all rules the players can apply in the given game state. Returns + the player together with a move. *) val list_moves : Arena.game -> Arena.game_state -> (int * Arena.move * Arena.game_state) array Modified: trunk/Toss/Play/Play.ml =================================================================== --- trunk/Toss/Play/Play.ml 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Play/Play.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -6,9 +6,9 @@ let set_debug_level i = debug_level := i let timeout = ref 0. -let set_timeout t = timeout := Unix.gettimeofday() +. t +let set_timeout t = timeout := Aux.gettimeofday() +. t let cancel_timeout () = timeout := 0. -let timed_out () = !timeout > 1. && Unix.gettimeofday() +. 0.01 > !timeout +let timed_out () = !timeout > 1. && Aux.gettimeofday() +. 0.01 > !timeout (* ------------ MAXIMAX BY DEPTH ------------- *) @@ -63,9 +63,11 @@ | Aux.Timeout msg -> if !debug_level > 0 then Printf.printf "Timeout %f (%s)%!" - (Unix.gettimeofday() -. !timeout) msg; + (Aux.gettimeofday() -. !timeout) msg; (t, mvs) +let latest_gametree_size = ref 0 + (* Maximax unfold upto depth and choose move. *) let maximax_unfold_choose ?(check_stable=3) count game state heur = let ab = Heuristic.is_constant_sum heur in (* TODO: payoffs as well! *) @@ -75,6 +77,7 @@ let t = init game state (fun _ _ _ -> 0) heur in try let (u, mvs) = unfold_maximax_upto ~ab count game heur (t, []) in + latest_gametree_size := GameTree.size u; let nbr_to_check = min (2*check_stable + 1) (List.length mvs / 3) in let last_mvs = Aux.take_n (max 1 nbr_to_check) mvs in if !debug_level = 2 then Modified: trunk/Toss/Play/Play.mli =================================================================== --- trunk/Toss/Play/Play.mli 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Play/Play.mli 2012-02-01 10:17:21 UTC (rev 1657) @@ -23,3 +23,7 @@ val maximax_unfold_choose : ?check_stable:int -> int -> Arena.game -> Arena.game_state -> Formula.real_expr array array -> (Arena.move * Arena.game_state) list + +(** Size of the game-tree produced by the latest call of + {!Play.maximax_unfold_choose}. *) +val latest_gametree_size : int ref Added: trunk/Toss/Server/GameSelection.ml =================================================================== --- trunk/Toss/Server/GameSelection.ml (rev 0) +++ trunk/Toss/Server/GameSelection.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -0,0 +1,654 @@ +type game_state_data = { + heuristic : Formula.real_expr array array; (** heuristic *) + game_state : (Arena.game * Arena.game_state); (** game and state *) + playclock : int; (** playclock *) + game_str : string; (** game representation *) +} + +let compute_heuristic advr (game, state) = + let pat_arr = Array.of_list game.Arena.patterns in + let pl_heur l = + let len = List.length l.Arena.heur in + if len = 0 || len > Array.length pat_arr then raise Not_found else + let add_pat (i, h) pw = + let pat = Formula.Times (Formula.Const pw, pat_arr.(i)) in + (i+1, Formula.Plus (pat, h)) in + snd (List.fold_left add_pat (0, Formula.Const 0.) l.Arena.heur) in + try + let res = Array.map (fun a-> Array.map pl_heur a) game.Arena.graph in + res + with Not_found -> + Heuristic.default_heuristic ~struc:state.Arena.struc ?advr game + +let compile_game_data game_str = + let (game, game_state as game_with_state) = + ArenaParser.parse_game_state Lexer.lex (Lexing.from_string game_str) in + let adv_ratio = + try Some (float_of_string (List.assoc "adv_ratio" game.Arena.data)) + with Not_found -> None in + {heuristic = compute_heuristic adv_ratio game_with_state; + game_state = game_with_state; + playclock = 30; (* game clock from where? *) + game_str = game_str; + } + +(* Maximum call stack size exceeded in JS (pbbly parsing Chess) +let chess_str = +*) + +let connect4_str = ("PLAYERS 1, 2 +DATA r1: circle, r2: line, adv_ratio: 4, depth: 6 +REL Row4 (x, y, z, v) = R(x, y) and R(y, z) and R(z, v) +REL Col4 (x, y, z, v) = C(x, y) and C(y, z) and C(z, v) +REL DiagA4 (x, y, z, v) = DiagA(x, y) and DiagA(y, z) and DiagA(z, v) +REL DiagB4 (x, y, z, v) = DiagB(x, y) and DiagB(y, z) and DiagB(z, v) +REL Conn4 (x, y, z, v) = + Row4(x,y,z,v) or Col4(x,y,z,v) or DiagA4(x,y,z,v) or DiagB4(x,y,z,v) +REL WinQ() = + ex x,y,z,v (Q(x) and Q(y) and Q(z) and Q(v) and Conn4(x, y, z, v)) +REL WinP() = + ex x,y,z,v (P(x) and P(y) and P(z) and P(v) and Conn4(x, y, z, v)) +REL EmptyUnder (x) = ex y (C(y, x) and not P(y) and not Q(y)) +RULE Cross: + [a | P:1 {} | - ] -> [a | P (a) | - ] emb Q, P + pre not EmptyUnder (a) and not WinQ() +RULE Circle: + [a | Q:1 {} | - ] -> [a | Q (a) | - ] emb Q, P + pre not EmptyUnder (a) and not WinP() +LOC 0 { + PLAYER 1 { + PAYOFF :(WinP()) - :(WinQ()) + MOVES [Cross -> 1] + } + PLAYER 2 { + PAYOFF :(WinQ()) - :(WinP()) + } +} +LOC 1 { + PLAYER 1 { + PAYOFF :(WinP()) - :(WinQ()) + } + PLAYER 2 { + PAYOFF :(WinQ()) - :(WinP()) + MOVES [Circle -> 0] + } +} +MODEL [ | P:1 {}; Q:1 {} | ] \" + ... ... ... + ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... + ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... + ... ... ... + ... ... ... ... + ... ... ... ... +\" with DiagA (x, y) = ex u (R(x, u) and C(u, y)) ; + DiagB (x, y) = ex u (R(x, u) and C(y, u)) +") + +let pawn_whopping_str = (" +PLAYERS 1, 2 +DATA depth: 4, adv_ratio: 2 +REL DiagW (x, y) = ex z (C(x, z) and (R(y, z) or R(z, y))) +REL DiagB (x, y) = ex z (C(z, x) and (R(y, z) or R(z, y))) +REL IsFirst(x) = not ex z C(z, x) +REL IsSecond(x) = ex y (C(y, x) and IsFirst(y)) +REL IsEight(x) = not ex z C(x, z) +REL IsSeventh(x) = ex y (C(x, y) and IsEight(y)) +REL WhiteEnds() = (ex x (wP(x) and not ex y C(x, y))) or (not ex z bP(z)) +REL BlackEnds() = (ex x (bP(x) and not ex y C(y, x))) or (not ex z wP(z)) +RULE WhiteBeat: + [ a, b | wP { a }; bP { b } | - ] -> [ a, b | wP { b } | - ] emb wP, bP + pre DiagW(a, b) and not BlackEnds() +RULE WhiteMove: + [ | bP:1 {}; R:2 {} | ] \" + + . + + wP +\" -> [ | bP:1 {}; R:2 {} | ] \" + + wP + + . +\" emb wP, bP pre not BlackEnds() +RULE WhiteMoveTwo: + [ | bP:1 {}; R:2 {} | ] \" + + . + + . + + wP +\" -> [ | bP:1 {}; R:2 {} | ] \" + + wP + + . + + . +\" emb wP, bP pre IsSecond(a1) and not BlackEnds() +RULE WhiteRightPassant: + [ | | ] \" + ... + ?..-bP + ... + ? ... + ... + wP.bP +\" -> [ | | ] \" + ... + ?... + ... + ? wP. + ... + .... +\" emb wP, bP pre not BlackEnds() +RULE WhiteLeftPassant: + [ | | ] \" + ... + -bP? + ... + . ?.. + ... + bP.wP +\" -> [ | | ] \" + ... + ...? + ... + wP ?.. + ... + .... +\" emb wP, bP pre not BlackEnds() +RULE BlackBeat: + [ a, b | bP { a }; wP { b } | - ] -> [ a, b | bP { b } | - ] emb wP, bP + pre DiagB(a, b) and not WhiteEnds() +RULE BlackMove: + [ | R:2 {}; wP:1 {} | ] \" + + bP + + . +\" -> [ | R:2 {}; wP:1 {} | ] \" + + . + + bP +\" emb wP, bP pre not WhiteEnds() +RULE BlackMoveTwo: + [ | R:2 {}; wP:1 {} | ] \" + + bP + + . + + . +\" -> [ | R:2 {}; wP:1 {} | ] \" + + . + + . + + bP +\" emb wP, bP pre IsSeventh(a3) and not WhiteEnds() +RULE BlackRightPassant: + [ | | ] \" + ... + bP.wP + ... + ? ... + ... + ?..-wP +\" -> [ | | ] \" + ... + .... + ... + ? bP. + ... + ?... +\" emb wP, bP pre not WhiteEnds() +RULE BlackLeftPassant: + [ | | ] \" + ... + wP.bP + ... + . ?.. + ... + -wP? +\" -> [ | | ] \" + ... + .... + ... + bP ?.. + ... + ...? +\" emb wP, bP pre not WhiteEnds() +LOC 0 { + PLAYER 1 { + PAYOFF :(WhiteEnds()) - :(BlackEnds()) + MOVES + [WhiteBeat -> 1]; [WhiteMove -> 1]; [WhiteMoveTwo -> 1]; + [WhiteRightPassant -> 1]; [WhiteLeftPassant -> 1] + } + PLAYER 2 { PAYOFF :(BlackEnds()) - :(WhiteEnds()) } +} +LOC 1 { + PLAYER 1 { PAYOFF :(WhiteEnds()) - :(BlackEnds()) } + PLAYER 2 { + PAYOFF :(BlackEnds()) - :(WhiteEnds()) + MOVES + [BlackBeat -> 0]; [BlackMove -> 0]; [BlackMoveTwo -> 0]; + [BlackRightPassant -> 0]; [BlackLeftPassant -> 0] + } +} +MODEL [ | | ] \" + ... ... ... ... + ... ... ... ... + ... ... ... ... + bP.bP bP.bP bP.bP bP.bP + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + wP wP.wP wP.wP wP.wP wP. + ... ... ... ... + ... ... ... ... +\" +") + +let breakthrough_str = (" +PLAYERS 1, 2 +DATA depth: 2, adv_ratio: 2 +REL DiagW (x, y) = ex z (C(x, z) and (R(y, z) or R(z, y))) +REL DiagB (x, y) = ex z (C(z, x) and (R(y, z) or R(z, y))) +RULE WhiteDiag: + [ a, b | W { a }; _opt_B { b } | - ] + -> + [ a, b | W { b } | - ] + emb W, B pre DiagW(a, b) and not ex x (B(x) and not ex y C(y, x)) +RULE WhiteStraight: + [ | B:1 {}; R:2 {} | ] \" + + . + + W +\" -> [ | B:1 {}; R:2 {} | + ] \" + + W + + . +\" emb W, B pre not ex x (B(x) and not ex y C(y, x)) +RULE BlackDiag: + [ a, b | B { a }; _opt_W { b } | - ] + -> + [ a, b | B { b } | - ] + emb W, B pre DiagB(a, b) and not ex x (W(x) and not ex y C(x, y)) +RULE BlackStraight: + [ | R:2 {}; W:1 {} | ] \" + + B + + . +\" -> [ | R:2 {}; W:1 {} | + ] \" + + . + + B +\" emb W, B pre not ex x (W(x) and not ex y C(x, y)) +LOC 0 { + PLAYER 1 { + PAYOFF + :(ex x (W(x) and not ex y C(x, y))) - :(ex x (B(x) and not ex y C(y, x))) + MOVES + [WhiteDiag -> 1]; [WhiteStraight -> 1] + } + PLAYER 2 { + PAYOFF + :(ex x (B(x) and not ex y C(y, x))) - :(ex x (W(x) and not ex y C(x, y))) + } +} +LOC 1 { + PLAYER 1 { + PAYOFF + :(ex x (W(x) and not ex y C(x, y))) - :(ex x (B(x) and not ex y C(y, x))) + } + PLAYER 2 { + PAYOFF + :(ex x (B(x) and not ex y C(y, x))) - :(ex x (W(x) and not ex y C(x, y))) + MOVES + [BlackDiag -> 0]; [BlackStraight -> 0] + } +} +MODEL [ | | ] \" + ... ... ... ... + B B..B B..B B..B B.. + ... ... ... ... + B..B B..B B..B B..B + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + W W..W W..W W..W W.. + ... ... ... ... + W..W W..W W..W W..W +\" +") + +let checkers_str = (" +PLAYERS 1, 2 +DATA depth: 4, adv_ratio: 2 +REL IsFirst(x) = not ex z C(z, x) +REL IsEight(x) = not ex z C(x, z) +REL w(x) = W(x) or Wq(x) +REL b(x) = B(x) or Bq(x) +REL DiagWa (x, y) = ex z (C(x, z) and R(y, z)) +REL DiagBa (x, y) = ex z (C(z, x) and R(z, y)) +REL DiagWb (x, y) = ex z (C(x, z) and R(z, y)) +REL DiagBb (x, y) = ex z (C(z, x) and R(y, z)) +REL AnyDiag (x, y) = + DiagWa (x, y) or DiagWb (x, y) or DiagBa (x, y) or DiagBb (x, y) +REL DiagW2 (x, y, z) = + (DiagWa (x, y) and DiagWa (y, z)) or (DiagWb (x, y) and DiagWb (y, z)) +REL DiagB2 (x, y, z) = + (DiagBa (x, y) and DiagBa (y, z)) or (DiagBb (x, y) and DiagBb (y, z)) +REL Diag2 (x, y, z) = DiagW2 (x, y, z) or DiagB2 (x, y, z) +REL BeatsW (x, y) = ex z (b(z) and not b(y) and not w(y) and DiagW2 (x, z, y)) +REL BeatsWX (x, y) = ex z (b(z) and not b(y) and not w(y) and Diag2 (x, z, y)) +REL BeatsB (x, y) = ex z (w(z) and not b(y) and not w(y) and DiagB2 (x, z, y)) +REL BeatsBX (x, y) = ex z (w(z) and not b(y) and not w(y) and Diag2 (x, z, y)) +REL BJumps() = ex x, y ((B(x) and BeatsB (x, y)) or (Bq(x) and BeatsBX (x, y))) +REL WJumps() = ex x, y ((W(x) and BeatsW (x, y)) or (Wq(x) and BeatsWX (x, y))) +RULE RedMove: + [ a, b | W { a } | - ] -> [ a, b | W { b } | - ] emb w, b + pre (not IsEight(b)) and (DiagWa(a, b) or DiagWb(a, b)) and not WJumps() +RULE WhiteMove: + [ a, b | B { a } | - ] -> [ a, b | B { b } | - ] emb w, b + pre (not IsFirst(b)) and (DiagBa(a, b) or DiagBb(a, b)) and not BJumps() +RULE RedPromote: + [ a, b | W { a } | - ] -> [ a, b | Wq { b } | - ] emb w, b + pre (IsEight(b)) and (DiagWa(a, b) or DiagWb(a, b)) and not WJumps() +RULE WhitePromote: + [ a, b | B { a } | - ] -> [ a, b | Bq { b } | - ] emb w, b + pre (IsFirst(b)) and (DiagBa(a, b) or DiagBb(a, b)) and not BJumps() +RULE RedQMove: + [ a, b | Wq { a } | - ] -> [ a, b | Wq { b } | - ] emb w, b + pre AnyDiag (a, b) and not WJumps() +RULE WhiteQMove: + [ a, b | Bq { a } | - ] -> [ a, b | Bq { b } | - ] emb w, b + pre AnyDiag (a, b) and not BJumps() +RULE RedBeat: + [ a, b, c | W { a }; b { b } | - ] -> [ a, b, c | W { c } | - ] emb w, b + pre DiagW2 (a, b, c) and not IsEight(c) + post not ex x, y (_new_W(x) and BeatsWX (x, y)) +RULE WhiteBeat: + [ a, b, c | B { a }; w { b } | - ] -> [ a, b, c | B { c } | - ] emb w, b + pre DiagB2 (a, b, c) and not IsFirst(c) + post not ex x, y (_new_B(x) and BeatsBX (x, y)) +RULE RedBeatBoth: + [ a, b, c | W { a }; b { b } | - ] -> [ a, b, c | W { c } | - ] emb w, b + pre _new_W(a) and Diag2 (a, b, c) and not IsEight(c) + post not ex x, y (_new_W(x) and BeatsWX (x, y)) +RULE WhiteBeatBoth: + [ a, b, c | B { a }; w { b } | - ] -> [ a, b, c | B { c } | - ] emb w, b + pre _new_B(a) and Diag2 (a, b, c) and not IsFirst(c) + post not ex x, y (_new_B(x) and BeatsBX (x, y)) +RULE RedBeatPromote: + [ a, b, c | W { a }; b { b } | - ] -> [ a, b, c | Wq { c } | - ] emb w, b + pre DiagW2 (a, b, c) and IsEight(c) +RULE WhiteBeatPromote: + [ a, b, c | B { a }; w { b } | - ] -> [ a, b, c | Bq { c } | - ] emb w, b + pre DiagB2 (a, b, c) and IsFirst(c) +RULE RedBeatCont: + [ a, b, c | W { a }; b { b } | - ] -> [ a, b, c | W { c } | - ] emb w, b + pre DiagW2 (a, b, c) and not IsEight(c) + post ex x, y (_new_W(x) and BeatsWX (x, y)) +RULE WhiteBeatCont: + [ a, b, c | B { a }; w { b } | - ] -> [ a, b, c | B { c } | - ] emb w, b + pre DiagB2 (a, b, c) and not IsFirst(c) + post ex x, y (_new_B(x) and BeatsBX (x, y)) +RULE RedBeatBothCont: + [ a, b, c | W { a }; b { b } | - ] -> [ a, b, c | W { c } | - ] emb w, b + pre _new_W(a) and Diag2 (a, b, c) and not IsEight(c) + post ex x, y (_new_W(x) and BeatsWX (x, y)) +RULE WhiteBeatBothCont: + [ a, b, c | B { a }; w { b } | - ] -> [ a, b, c | B { c } | - ] emb w, b + pre _new_B(a) and Diag2 (a, b, c) and not IsFirst(c) + post ex x, y (_new_B(x) and BeatsBX (x, y)) +RULE RedQBeat: + [ a, b, c | Wq { a }; b { b } | - ] -> [ a, b, c | Wq { c } | - ] emb w, b + pre Diag2 (a, b, c) +RULE WhiteQBeat: + [ a, b, c | Bq { a }; w { b } | - ] -> [ a, b, c | Bq { c } | - ] emb w, b + pre Diag2 (a, b, c) +LOC 0 { + PLAYER 1 { + PAYOFF :(ex x w(x)) - :(ex x b(x)) + MOVES + [RedMove -> 1]; [RedPromote -> 1]; [RedQMove -> 1]; + [RedBeat -> 1]; [RedBeatPromote -> 1]; [RedQBeat -> 1]; + [RedBeatCont -> 2] + } + PLAYER 2 { + PAYOFF :(ex x b(x)) - :(ex x w(x)) + } +} +LOC 1 { + PLAYER 1 { + PAYOFF :(ex x w(x)) - :(ex x b(x)) + } + PLAYER 2 { + PAYOFF :(ex x b(x)) - :(ex x w(x)) + MOVES + [WhiteMove -> 0]; [WhitePromote -> 0]; [WhiteQMove -> 0]; + [WhiteBeat -> 0]; [WhiteBeatPromote -> 0]; [WhiteQBeat -> 0]; + [WhiteBeatCont -> 3] + } +} +LOC 2 { + PLAYER 1 { + PAYOFF :(ex x w(x)) - :(ex x b(x)) + MOVES [RedBeatBoth -> 1]; [RedBeatPromote -> 1]; [RedBeatBothCont -> 2] + } + PLAYER 2 { + PAYOFF :(ex x b(x)) - :(ex x w(x)) + } +} +LOC 3 { + PLAYER 1 { + PAYOFF :(ex x w(x)) - :(ex x b(x)) + } + PLAYER 2 { + PAYOFF :(ex x b(x)) - :(ex x w(x)) + MOVES + [WhiteBeatBoth -> 0]; [WhiteBeatPromote -> 0]; [WhiteBeatBothCont -> 3] + } +} +MODEL [ | Wq:1 { }; Bq:1 { } | + ] \" + ... ... ... ... + B.. B.. B.. B.. + ... ... ... ... + B.. B.. B.. B.. + ... ... ... ... + B.. B.. B.. B.. + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + W.. W.. W.. W.. + ... ... ... ... + W.. W.. W.. W.. + ... ... ... ... + W.. W.. W.. W.. +\" +") + +let gomoku_str = (" +PLAYERS 1, 2 +DATA rCircle: circle, rCross: line, adv_ratio: 5, depth: 2 +REL Row5 (x, y, z, v, w) = R(x, y) and R(y, z) and R(z, v) and R(v, w) +REL Col5 (x, y, z, v, w) = C(x, y) and C(y, z) and C(z, v) and C(v, w) +REL DiagA5 (x, y, z, v, w) = + DiagA(x, y) and DiagA(y, z) and DiagA(z, v) and DiagA(v, w) +REL DiagB5 (x, y, z, v, w) = + DiagB(x, y) and DiagB(y, z) and DiagB(z, v) and DiagB(v, w) +REL Conn5 (x, y, z, v, w) = + Row5(x,y,z,v,w) or Col5(x,y,z,v,w) or DiagA5(x,y,z,v,w) or DiagB5(x,y,z,v,w) +REL WinQ() = + ex x,y,z,v,w (Q(x) and Q(y) and Q(z) and Q(v) and Q(w) and Conn5(x,y,z,v,w)) +REL WinP() = + ex x,y,z,v,w (P(x) and P(y) and P(z) and P(v) and P(w) and Conn5(x,y,z,v,w)) +RULE Cross: + [a1 | P:1 {}; Q:1 {} | - ] + -> + [a1 | P (a1); Q:1 {} | - ] + emb Q, P pre not WinQ() +RULE Circle: + [a1 | P:1 {}; Q:1 {} | - ] + -> + [a1 | P:1 {}; Q (a1) | - ] + emb Q, P pre not WinP() +LOC 0 { + PLAYER 1 { + PAYOFF :(WinP()) - :(WinQ()) + MOVES [Cross -> 1] + } + PLAYER 2 { PAYOFF :(WinQ()) - :(WinP()) } +} +LOC 1 { + PLAYER 1 { PAYOFF :(WinP()) - :(WinQ()) } + PLAYER 2 { + PAYOFF :(WinQ()) - :(WinP()) + MOVES [Circle -> 0] + } +} +MODEL [ | P:1 {}; Q:1 {} | ] \" + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... + ... ... ... ... +\" with DiagA (x, y) = ex u (R(x, u) and C(u, y)); + DiagB (x, y) = ex u (R(x, u) and C(y, u)) +") + +let entanglement_str = (" +PLAYERS 1, 2 +RULE Follow: + [ a1, a2 | C { (a2) }; R { (a1) } | + vx { a1->0., a2->0. }; vy { a1->0., a2->0. }; + x { a1->-10., a2->-10. }; y { a1->-10., a2->10. } ] + -> + [ a1, a2 | C { (a1) }; R { (a1) } | + vx { a1->0., a2->0. }; vy { a1->0., a2->0. }; + x { a1->-10., a2->-10. }; y { a1->-10., a2->10. } ] +emb R, C +RULE Wait: + [ a1 | R { (a1) } | + vx { a1->0. }; vy { a1->0. }; x { a1->-10. }; y { a1->-10. } ] + -> + [ a1 | R { (a1) } | + vx { a1->0. }; vy { a1->0. }; x { a1->-10. }; y { a1->-10. } ] +emb R, C +RULE Run: + [ a1, a2 | C:1 { }; E { (a1, a2) }; R { (a1) }; _opt_C { (a1) } | + vx { a1->0., a2->0. }; vy { a1->0., a2->0. }; + x { a1->-10., a2->10. }; y { a1->-10., a2->-10. } ] + -> + [ a1, a2 | C:1 { }; E { (a1, a2) }; R { (a2) }; _opt_C { (a1) } | + vx { a1->0., a2->0. }; vy { a1->0., a2->0. }; + x { a1->-10., a2->10. }; y { a1->-10., a2->-10. } ] +emb R, C +LOC 0 { + PLAYER 1 { + PAYOFF 0. + MOVES [Follow -> 1]; [Wait -> 1] + } + PLAYER 2 { PAYOFF 0. } +} +LOC 1 { + PLAYER 1 { PAYOFF 1. } + PLAYER 2 { + PAYOFF -1. + MOVES [Run -> 0] + } + } +MODEL [ d4, a2, a1, b1, b2, e4, c2, c1, f4, d2, d1, f1, f2, g1, g2, h1, h2, e1, e2, i1, i2 | C { (d4); (e4); (f4) }; E { (a2, a1); (a2, b2); (a1, a2); (a1, b1); (b1, a1); (b1, b2); (b1, c1); (b2, a2); (b2, b1); (b2, c2); (c2, b2); (c2, c1); (c2, d2); (c1, b1); (c1, c2); (c1, d1); (d2, c2); (d2, d1); (d2, e1); (d1, c1); (d1, d2); (d1, e2); (f1, f2); (f1, g1); (f1, e1); (f2, f1); (f2, g2); (f2, e2); (g1, f1); (g1, g2); (g1, h1); (g2, f2); (g2, g1); (g2, h2); (h1, g1); (h1, h2); (h1, i1); (h2, g2); (h2, h1); (h2, i2); (e1, d2); (e1, f1); (e1, e2); (e2, d1); (e2, f2); (e2, e1); (i1, h1); (i1, i2); (i2, h2); (i2, i1) }; R { (e1) }; _opt_C:1 { } | vx { d4->0., a2->0., a1->0., b1->0., b2->0., e4->0., c2->0., c1->0., f4->0., d2->0., d1->0., f1->0., f2->0., g1->0., g2->0., h1->0., h2->0., e1->0., e2->0., i1->0., i2->0. }; vy { d4->0., a2->0., a1->0., b1->0., b2->0., e4->0., c2->0., c1->0., f4->0., d2->0., d1->0., f1->0., f2->0., g1->0., g2->0., h1->0., h2->0., e1->0., e2->0., i1->0., i2->0. }; x { d4->100., a2->-50., a1->-50., b1->0., b2->0., e4->150., c2->50., c1->50., f4->200., d2->100., d1->100., f1->200., f2->200., g1->250., g2->250., h1->300., h2->300., e1->150., e2->150., i1->350., i2->350. }; y { d4->-150., a2->-100., a1->-50., b1->-50., b2->-100., e4->0., c2->-100., c1->-50., f4->-150., d2->-100., d1->-50., f1->-100., f2->-50., g1->-100., g2->-50., h1->-100., h2->-50., e1->-100., e2->-50., i1->-100., i2->-50. } ] +") + +let tictactoe_str = (" +PLAYERS 1, 2 +DATA r1: circle, r2: line, adv_ratio: 5, depth: 3 +REL DiagA (x, y) = ex u (R(x, u) and C(u, y)) +REL DiagB (x, y) = ex u (R(x, u) and C(y, u)) +REL Row3 (x, y, z) = R(x, y) and R(y, z) +REL Col3 (x, y, z) = C(x, y) and C(y, z) +REL DiagA3 (x, y, z) = DiagA(x, y) and DiagA(y, z) +REL DiagB3 (x, y, z) = DiagB(x, y) and DiagB(y, z) +REL Conn3 (x, y, z) = + Row3(x, y, z) or Col3(x, y, z) or DiagA3(x, y, z) or DiagB3(x, y, z) +REL WinQ() = ex x, y, z (Q(x) and Q(y) and Q(z) and Conn3(x, y, z)) +REL WinP() = ex x, y, z (P(x) and P(y) and P(z) and Conn3(x, y, z)) +RULE Cross: + [a | P:1 {} | - ] -> [a | P (a) | - ] emb Q, P pre not WinQ() +RULE Circle: + [a | Q:1 {} | - ] -> [a | Q (a) | - ] emb Q, P pre not WinP() +LOC 0 { + PLAYER 1 { PAYOFF :(WinP()) - :(WinQ()) + MOVES [Cross -> 1] } + PLAYER 2 { PAYOFF :(WinQ()) - :(WinP()) } +} +LOC 1 { + PLAYER 1 { PAYOFF :(WinP()) - :(WinQ()) } + PLAYER 2 { PAYOFF :(WinQ()) - :(WinP()) + MOVES [Circle -> 0] } +} +MODEL [ | P:1 {}; Q:1 {} | ] \" + + . . . + + . . . + + . . . +\" +") + +let games = ref + [ + "Breakthrough", compile_game_data breakthrough_str; + "Checkers", compile_game_data checkers_str; + (* "Chess", compile_game_data chess_str; *) + "Connect4", compile_game_data connect4_str; + "Entanglement", compile_game_data entanglement_str; + "Gomoku", compile_game_data gomoku_str; + "Pawn-Whopping", compile_game_data pawn_whopping_str; + "Tic-Tac-Toe", compile_game_data tictactoe_str; + ] Added: trunk/Toss/Server/JsHandler.ml =================================================================== --- trunk/Toss/Server/JsHandler.ml (rev 0) +++ trunk/Toss/Server/JsHandler.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -0,0 +1,184 @@ +(* JavaScript Handler for a subset of ReqHandler.handle_http_post requests. *) + + +(* ---------- Basic request type and internal handler ---------- *) + +open GameSelection + +(* History of states in last-in-first-out order. *) +let play_states = ref [] +(* Arbitrarily initialized -- [cur_game] only has effect with + non-empty [play_states]. The game state in any [game_data] is only + the initial state, not the current state of a game. *) +let cur_game = ref (snd (List.hd !GameSelection.games)) +let cur_move = ref 0 +let cur_all_moves = ref [| |] + +(* TODO; FIXME; remove the function below. *) +let select_moving a = (* temporary func - accept just one player w/ moves *) + let locs = Aux.array_find_all (fun l -> l.Arena.moves <> []) a in + if List.length locs <> 1 then failwith "too many moves" else + if locs = [] then a.(0) else List.hd locs + + +(* ------------ The Handler ------------ *) +let js = Js.string +let of_js = Js.to_string +let js_object = Js.Unsafe.variable "Object" +let js_any = Js.Unsafe.inject + +let js_handler = Js.Unsafe.variable "LOCAL" +let set_handle name f = + Js.Unsafe.set js_handler (js name) (Js.wrap_callback f) + + +let js_of_move game state move_id (player, move, _) = + let struc = state.Arena.struc in + let matched = Js.array + (Aux.array_map_of_list (fun (_, e) -> + js (Structure.elem_name struc e)) move.Arena.matching) in + let js_move = jsnew js_object () in + let player_name = Aux.rev_assoc game.Arena.player_names player in + Js.Unsafe.set js_move (js"matched") matched; + Js.Unsafe.set js_move (js"rule") (js (move.Arena.rule)); + Js.Unsafe.set js_move (js"player") (js player_name); + Js.Unsafe.set js_move (js"id") (Js.float (float_of_int move_id)); + js_move + +(* Translate current structure into an "info_obj" format. *) +let js_of_game_state game state = + let struc = state.Arena.struc in + let get_pos e = + Structure.fun_val struc "x" e, Structure.fun_val struc "y" e in + let elems = Structure.elements struc in + let (posx, posy) = List.split (List.map get_pos elems) in + let mkfl f l = List.fold_left f (List.hd l) (List.tl l) in + let (minl, maxl, suml) = (mkfl min, mkfl max, mkfl (+.)) in + let minx, maxx, miny, maxy = minl posx, maxl posx, minl posy, maxl posy in + (* elems are arrays of element name and position *) + let elems = Array.of_list + (List.map + (fun e -> + let e0 = js (Structure.elem_name struc e) in + let x, y = get_pos e in + Js.array [|js_any e0; js_any (Js.float x); js_any (Js.float y)|]) + elems) in + (* rels are arrays of element names, with additional "name" field *) + let num = Js.number_of_float in + let rels = Array.of_list + (Aux.concat_map + (fun (rel, _) -> + let tups = Structure.Tuples.elements + (Structure.rel_graph rel struc) in + let tups = List.map + (fun args -> Js.array + (Array.map (fun e -> js (Structure.elem_name struc e)) args)) + tups in + List.iter + (fun args -> Js.Unsafe.set args (js"name") (js rel)) tups; + tups) + (Structure.rel_signature struc)) in + let info_obj = jsnew js_object () in + Js.Unsafe.set info_obj (js"maxx") (num maxx); + Js.Unsafe.set info_obj (js"minx") (num minx); + Js.Unsafe.set info_obj (js"maxy") (num maxy); + Js.Unsafe.set info_obj (js"miny") (num miny); + Js.Unsafe.set info_obj (js"elems") (Js.array elems); + Js.Unsafe.set info_obj (js"rels") (Js.array rels); + if !cur_all_moves <> [||] then + Js.Unsafe.set info_obj (js"moves") + (Js.array (Array.mapi (js_of_move game state) !cur_all_moves)) + else ( (* find payoffs *) + let payoffs = Array.mapi + (fun i v -> i, Solver.M.get_real_val v.Arena.payoff struc) + game.Arena.graph.(state.Arena.cur_loc) in + let result = jsnew js_object () in + Array.iter + (fun (i, payoff) -> + (* Players use their names on the JS side, not numbers! *) + let player_name = Aux.rev_assoc game.Arena.player_names i in + Js.Unsafe.set result (js player_name) (Js.float payoff)) + payoffs; + Js.Unsafe.set info_obj (js"result") result); + info_obj + +let new_play game_name pl1 pl2 = + (* players are currently not used by [JsHandler] *) + let game_data = List.assoc (of_js game_name) !GameSelection.games in + let game, state = game_data.game_state in + cur_game := game_data; + play_states := [state]; + cur_all_moves := Move.list_moves game state; + cur_move := 0; + js_of_game_state game state + +let _ = set_handle "new_play" new_play + +let preview_move move_nbr = + let n = List.length !play_states - (move_nbr + 1) in + if n < 0 then Js.null + else + let game, _ = !cur_game.game_state in + let state = List.nth !play_states n in + Js.some (js_of_game_state game state) + +let _ = set_handle "prev_move" preview_move + +let make_move move_id cont = + if !play_states = [] then Js.null + else + let (p, m, n_state) = + !cur_all_moves.(int_of_float (Js.to_float move_id)) in + let game, _ = !cur_game.game_state in + play_states := n_state :: !play_states; + cur_all_moves := Move.list_moves game n_state; + cur_move := 0; + Js.Unsafe.fun_call cont + [|js_any (js_of_game_state game n_state)|] + +let _ = set_handle "make_move" make_move + +let suggest player_name time cont = + (* We do not use the player name. *) + Random.self_init (); + let time = Js.to_float time in + Play.set_timeout time; + let comp_started = Aux.gettimeofday () in + let game, _ = !cur_game.game_state in + let state = List.hd !play_states in + try + let (move, _) = + Aux.random_elem (Play.maximax_unfold_choose 100000 + game state !cur_game.heuristic) in + Play.cancel_timeout (); + let algo_iters = !Play.latest_gametree_size in + let move_id = Aux.array_argfind + (fun (_, m, _) -> m = move) !cur_all_moves in + let result = + js_of_move game state move_id (!cur_all_moves.(move_id)) in + Js.Unsafe.set result (js"comp_tree_size") + (Js.number_of_float (float_of_int algo_iters)); + Js.Unsafe.set result (js"comp_started") + (Js.number_of_float comp_started); + Js.Unsafe.set result (js"comp_ended") + (Js.number_of_float (Aux.gettimeofday ())); + Js.Unsafe.fun_call cont [|js_any result|] + with Not_found -> Js.null + +let _ = set_handle "suggest" suggest + +let get_game game_name = + let game_data = List.assoc (of_js game_name) !GameSelection.games in + js game_data.game_str + +let _ = set_handle "get_game" get_game + +let set_game game_name game_str = + let game_name = of_js game_name and game_str = of_js game_str in + try + games := (game_name, compile_game_data game_str) :: !games; + js ("Game "^game_name^" set.") + with Lexer.Parsing_error s -> + js ("Game "^game_name^" ERROR: "^s) + +let _ = set_handle "set_game" set_game Added: trunk/Toss/Solver/RealQuantElim/N.ml =================================================================== --- trunk/Toss/Solver/RealQuantElim/N.ml (rev 0) +++ trunk/Toss/Solver/RealQuantElim/N.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -0,0 +1,37 @@ +(* A proxy to the [Num] module from the [nums] library. *) + +module LocalNum = (struct + type num = int * int + let sign_num n = failwith "Local Num not implemented yet" + let mod_num m n = failwith "Local Num not implemented yet" + let div_num m n = failwith "Local Num not implemented yet" + let ( // ) = div_num + let num_of_int n = failwith "Local Num not implemented yet" + let ( +/ ) m n = failwith "Local Num not implemented yet" + let ( -/ ) m n = failwith "Local Num not implemented yet" + let ( */ ) m n = failwith "Local Num not implemented yet" + let float_of_num n = failwith "Local Num not implemented yet" + let num_of_string s = failwith "Local Num not implemented yet" + let string_of_num n = failwith "Local Num not implemented yet" + let abs_num n = failwith "Local Num not implemented yet" +end : sig + type num + val sign_num : num -> int + val mod_num : num -> num -> num + val div_num : num -> num -> num + val ( // ) : num -> num -> num + val num_of_int : int -> num + val ( +/ ) : num -> num -> num + val ( -/ ) : num -> num -> num + val ( */ ) : num -> num -> num + val float_of_num : num -> float + val num_of_string : string -> num + val string_of_num : num -> string + val abs_num : num -> num +end) + +IFDEF JAVASCRIPT THEN +module Q = LocalNum + ELSE +module Q = Num + ENDIF Modified: trunk/Toss/Solver/RealQuantElim/OrderedPoly.ml =================================================================== --- trunk/Toss/Solver/RealQuantElim/OrderedPoly.ml 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Solver/RealQuantElim/OrderedPoly.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -1,6 +1,6 @@ (* Polynomials with ordered variables, integer coefficients.*) -open Num +open N.Q (* ----------------------- BASIC TYPE DEFINITIONS --------------------------- *) @@ -219,7 +219,7 @@ match (p, q) with (Const n, Const m) -> if allow_frac then Const (n // m) else - if Num.sign_num (Num.mod_num n m) = 0 then Const (n // m) else + if N.Q.sign_num (N.Q.mod_num n m) = 0 then Const (n // m) else raise Not_found | (Poly (v, _), Poly (w, _)) -> if v <> w then raise Unmatched_variables else @@ -232,8 +232,8 @@ | Const n -> ( match u with Const m -> - if allow_frac then (Const (n // m), Const (Num.num_of_int 0)) else - let r = Num.mod_num n m in (Const ((n -/ r) // m), Const r) + if allow_frac then (Const (n // m), Const (N.Q.num_of_int 0)) else + let r = N.Q.mod_num n m in (Const ((n -/ r) // m), Const r) | Poly (_, _) -> raise Unmatched_variables ) | Poly (v, (p, d) :: ps) -> Modified: trunk/Toss/Solver/RealQuantElim/OrderedPoly.mli =================================================================== --- trunk/Toss/Solver/RealQuantElim/OrderedPoly.mli 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Solver/RealQuantElim/OrderedPoly.mli 2012-02-01 10:17:21 UTC (rev 1657) @@ -3,7 +3,7 @@ (** {2 Basic Type Definitions} *) -type polynomial = Const of Num.num | Poly of string * (polynomial * int) list +type polynomial = Const of N.Q.num | Poly of string * (polynomial * int) list type t = polynomial (** to be compatible with OrderedType signature *) @@ -29,14 +29,15 @@ val var : polynomial -> string val lower : polynomial -> polynomial -val constant_value : polynomial -> Num.num option +val constant_value : polynomial -> N.Q.num option val deg : polynomial -> int val leading_coeff : int -> polynomial -> polynomial val const_coeff : polynomial -> polynomial option val omit_leading : polynomial -> polynomial val multiple : int -> polynomial -> polynomial -val multiple_num : Num.num -> polynomial -> polynomial -val constant_factors : polynomial -> polynomial -> (Num.num * Num.num) option +val multiple_num : N.Q.num -> polynomial -> polynomial +val constant_factors : + polynomial -> polynomial -> (N.Q.num * N.Q.num) option (** {2 Arithmetic Functions} *) Modified: trunk/Toss/Solver/RealQuantElim/Poly.ml =================================================================== --- trunk/Toss/Solver/RealQuantElim/Poly.ml 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Solver/RealQuantElim/Poly.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -49,7 +49,7 @@ (* ----------------- CONVERTION TO UNORDERED POLYNOMIALS -------------------- *) let rec make_unordered = function - OrderedPoly.Const n -> Const (Num.float_of_num n) + OrderedPoly.Const n -> Const (N.Q.float_of_num n) | OrderedPoly.Poly (v, lst) -> make_unordered_list v lst and make_unordered_list v = function @@ -74,11 +74,11 @@ let scale = 1000000 in let f_scaled = Printf.sprintf "%.0f" (f *. (float_of_int scale)) in if f_scaled = "nan" || f_scaled = "inf" || f_scaled = "-inf" - then Num.num_of_int (-1) (* unlikely number *) + then N.Q.num_of_int (-1) (* unlikely number *) else - let num_scale = Num.num_of_int scale in - let num_f_scaled = Num.num_of_string f_scaled in - Num.div_num num_f_scaled num_scale + let num_scale = N.Q.num_of_int scale in + let num_f_scaled = N.Q.num_of_string f_scaled in + N.Q.div_num num_f_scaled num_scale (* List variables in the given polynomial. *) let rec vars = function Modified: trunk/Toss/Solver/RealQuantElim/SignTable.ml =================================================================== --- trunk/Toss/Solver/RealQuantElim/SignTable.ml 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Solver/RealQuantElim/SignTable.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -72,7 +72,7 @@ let int_case_str case = let psgn_str (p, i) = match constant_value p with - Some n -> if Num.sign_num n <> sign i then "wrong" else "ok" + Some n -> if N.Q.sign_num n <> sign i then "wrong" else "ok" | None -> if i > 0 then (str p) ^ " > 0" else if i = 0 then (str p) ^ " = 0" else (str p) ^ " < 0" @@ -104,7 +104,7 @@ | (r, _) :: rs -> let mulr = match q with None -> r | Some qp -> mul qp r in match constant_factors p mulr with - Some (c1, c2) -> ((-2, i), (Num.sign_num c1) * (Num.sign_num c2)) + Some (c1, c2) -> ((-2, i), (N.Q.sign_num c1) * (N.Q.sign_num c2)) | None -> find_const_factor ~i:(i+1) ~q:q p rs (* Helper function: find if p = q1 * q2 * c for some q1, q2 in [acc]. *) @@ -120,7 +120,8 @@ [] -> acc | p :: ps -> match constant_value p with - Some n -> determine_vals (acc @ [(p, ((-2, -2), Num.sign_num n))]) ps + Some n -> + determine_vals (acc @ [(p, ((-2, -2), N.Q.sign_num n))]) ps | None -> match find_const_factor p acc with ((-1, _), _) -> Modified: trunk/Toss/Solver/Structure.ml =================================================================== --- trunk/Toss/Solver/Structure.ml 2012-01-30 19:21:45 UTC (rev 1656) +++ trunk/Toss/Solver/Structure.ml 2012-02-01 10:17:21 UTC (rev 1657) @@ -1253,19 +1253,19 @@ find_unique (StringMap.fold (fun rel _ acc -> rel::acc) !struc.rel_signature []) in let uniq = uniq1 @ uniq2 @ uniq3 in - let lines = Str.split (Str.regexp "[\r\n]+\t*") board in + let lines = Aux.split_regexp ~regexp:"[\r\n]+\t*" board in let lines = List.filter (fun s->String.length s > 2) lines in - let rec split_line line = - let is_ok c = c = ' ' || c = '.' || Aux.is_alphanum c || c = '_' || + let rec split_line line = + let is_ok c = c = ' ' || c = '.' || Aux.is_alphanum c || c = '_' || c = '*' || c = '?' || c = '#' || c = '+' || c = '-' in let error txt = raise (Board_parse_error - ("Unrecognized field line: \"" ^ txt ^ - "\" of board line: \"" ^ line ^"\"")) in + ("Unrecognized field line: \"" ^ txt ^ + "\" of board line: \"" ^ line ^"\"")) in if line = "" then [] else if String.length line < 3 then error line else - if (is_ok line.[0] && is_ok line.[1] && is_ok line.[2]) then - let rest = String.sub line 3 ((String.length line) - 3) in - (String.sub line 0 3) :: (split_line rest) - else error (String.sub line 0 3) in + if (is_ok line.[0] && is_ok line.[1] && is_ok line.[2]) then + let rest = String.sub line 3 ((String.length line) - 3) in + (String.sub line 0 3) :: (split_line rest) + else error (String.sub line 0 3) in let rec rev_combine_pairs acc = function | [] -> acc | [hd] -> @@ -1296,12 +1296,12 @@ else if s.[0] = '*' then ["*"] (* treated specially *) else if sl = 0 && s.[sl] = '?' then ["_any_"] else if s.[0] = '+' then - let p = unabbrev (omit 1 s) in ["_new_" ^ p; p] + let p = unabbrev (omit 1 s) in ["_new_"^p; p] else if s.[0] = '-' then ["_del_"^unabbrev (omit 1 s)] else if s.[sl] = '?' then [unabbrev (String.sub s 0 sl); "_any_"] else if s.[0] = '?' then ["_opt_"^unabbrev (omit 1 s)] else if s.[sl] = '#' then - ["_diffthan_" ^ unabbrev (String.sub s 0 sl); "_any_"] + ["_diffthan_"^unabbrev (String.sub s 0 sl); "_any_"] else if s.[0] = '#' then ["_diffthan_"^unabbrev (omit 1 s)] else [unabbrev s] in let board_els = @@ -1346,8 +1346,8 @@ done; if List.hd !fields <> [] then raise (Board_parse_error - (Printf.sprintf - "Row %d is too long, expected %d columns" r c_max)); + (Printf.sprintf + "Row %d is too long, expected %d columns" r c_max)); fields := List.tl !fields; done; !struc Added: trunk/Toss/WebClient/JsHandler.js =================================================================== --- trunk/Toss/WebClient/JsHandler.js (rev 0) +++ trunk/Toss/WebClient/JsHandler.js 2012-02-01 10:17:21 UTC (rev 1657) @@ -0,0 +1,895 @@ +// This program was compiled from OCaml by js_of_ocaml 1.0 +function caml_raise_with_arg (tag, arg) { throw [0, tag, arg]; } +function caml_raise_with_string (tag, msg) { + caml_raise_with_arg (tag, new MlWrappedString (msg)); +} +function caml_invalid_argument (msg) { + caml_raise_with_string(caml_global_data[4], msg); +} +function caml_array_bound_error () { + caml_invalid_argument("index out of bounds"); +} +function caml_str_repeat(n, s) { + if (!n) { return ""; } + if (n & 1) { return caml_str_repeat(n - 1, s) + s; } + var r = caml_str_repeat(n >> 1, s); + return r + r; +} +function MlString(param) { + if (param != null) { + this.bytes = this.fullBytes = param; + this.last = this.len = param.length; + } +} +MlString.prototype = { + string:null, + bytes:null, + fullBytes:null, + array:null, + len:null, + last:0, + toJsString:function() { + return this.string = decodeURIComponent (escape(this.getFullBytes())); + }, + toBytes:function() { + if (this.string != null) + var b = unescape (encodeURIComponent (this.string)); + else { + var b = "", a = this.array, l = a.length; + for (var i = 0; i < l; i ++) b += String.fromCharCode (a[i]); + } + this.bytes = this.fullBytes = b; + this.last = this.len = b.length; + return b; + }, + getBytes:function() { + var b = this.bytes; + if (b == null) b = this.toBytes(); + return b; + }, + getFullBytes:function() { + var b = this.fullBytes; + if (b !== null) return b; + b = this.bytes; + if (b == null) b = this.toBytes (); + if (this.last < this.len) { + this.bytes = (b += caml_str_repeat(this.len - this.last, '\0')); + this.last = this.len; + } + this.fullBytes = b; + return b; + }, + toArray:function() { + var b = this.bytes; + if (b == null) b = this.toBytes (); + var a = [], l = this.last; + for (var i = 0; i < l; i++) a[i] = b.charCodeAt(i); + for (l = this.len; i < l; i++) a[i] = 0; + this.string = this.bytes = this.fullBytes = null; + this.last = this.len; + this.array = a; + return a; + }, + getArray:function() { + var a = this.array; + if (!a) a = this.toArray(); + return a; + }, + getLen:function() { + var len = this.len; + if (len !== null) return len; + this.toBytes(); + return this.len; + }, + toString:function() { var s = this.string; return s?s:this.toJsString(); }, + valueOf:function() { var s = this.string; return s?s:this.toJsString(); }, + blitToArray:function(i1, a2, i2, l) { + var a1 = this.array; + if (a1) + for (var i = 0; i < l; i++) a2 [i2 + i] = a1 [i1 + i]; + else { + var b = this.bytes; + if (b == null) b = this.toBytes(); + var l1 = this.last - i1; + if (l <= l1) + for (var i = 0; i < l; i++) a2 [i2 + i] = b.charCodeAt(i1 + i); + else { + for (var i = 0; i < l1; i++) a2 [i2 + i] = b.charCodeAt(i1 + i); + for (; i < l; i++) a2 [i2 + i] = 0; + } + } + }, + get:function (i) { + var a = this.array; + if (a) return a[i]; + var b = this.bytes; + if (b == null) b = this.toBytes(); + return (i<this.last)?b.charCodeAt(i):0; + }, + safeGet:function (i) { + if (!this.len) this.toBytes(); + if ((i < 0) || (i >= this.len)) caml_array_bound_error (); + return this.get(i); + }, + set:function (i, c) { + var a = this.array; + if (!a) { + if (this.last == i) { + this.bytes += String.fromCharCode (c & 0xff); + this.last ++; + return 0; + } + a = this.toArray(); + } else if (this.bytes != null) { + this.bytes = this.fullBytes = this.string = null; + } + a[i] = c & 0xff; + return 0; + }, + safeSet:function (i, c) { + if (this.len == null) this.toBytes (); + if ((i < 0) || (i >= this.len)) caml_array_bound_error (); + this.set(i, c); + }, + fill:function (ofs, len, c) { + if (ofs >= this.last && this.last && c == 0) return; + var a = this.array; + if (!a) a = this.toArray(); + else if (this.bytes != null) { + this.bytes = this.fullBytes = this.string = null; + } + var l = ofs + len; + for (var i = ofs; i < l; i++) a[i] = c; + }, + compare:function (s2) { + if (this.string != null && s2.string != null) { + if (this.string < s2.string) return -1; + if (this.string > s2.string) return 1; + return 0; + } + var b1 = this.getFullBytes (); + var b2 = s2.getFullBytes (); + if (b1 < b2) return -1; + if (b1 > b2) return 1; + return 0; + }, + equal:function (s2) { + if (this.string != null && s2.string != null) + return this.string == s2.string; + return this.getFullBytes () == s2.getFullBytes (); + }, + lessThan:function (s2) { + if (this.string != null && s2.string != null) + return this.string < s2.string; + return this.getFullBytes () < s2.getFullBytes (); + }, + lessEqual:function (s2) { + if (this.string != null && s2.string != null) + return this.string <= s2.string; + return this.getFullBytes () <= s2.getFullBytes (); + } +} +function MlWrappedString (s) { this.string = s; } +MlWrappedString.prototype = new MlString(); +function MlMakeString (l) { this.bytes = ""; this.len = l; } +MlMakeString.prototype = new MlString (); +function caml_array_get (array, index) { + if ((index < 0) || (index >= array.length - 1)) caml_array_bound_error(); + return array[index+1]; +} +function caml_array_set (array, index, newval) { + if ((index < 0) || (index >= array.length - 1)) caml_array_bound_error(); + array[index+1]=newval; return 0; +} +function caml_blit_string(s1, i1, s2, i2, len) { + if (len === 0) return; + if (i2 === s2.last && i1 === 0 && s1.last == len) { + var s = s1.bytes; + if (s !== null) + s2.bytes += s1.bytes; + else + s2.bytes += s1.getBytes(); + s2.last += len; + return; + } + var a = s2.array; + if (!a) a = s2.toArray(); else { s2.bytes = s2.string = null; } + s1.blitToArray (i1, a, i2, len); +} +function caml_call_gen(f, args) { + if(f.fun) + return caml_call_gen(f.fun, args); + var n = f.length; + var d = n - args.length; + if (d == 0) + return f.apply(null, args); + else if (d < 0) + return caml_call_gen(f.apply(null, args.slice(0,n)), args.slice(n)); + else + return function (x){ return caml_call_gen(f, args.concat([x])); }; +} +function caml_classify_float (x) { + if (isFinite (x)) { + if (Math.abs(x) >= 2.2250738585072014e-308) return 0; + if (x != 0) return 1; + return 2; + } + return isNaN(x)?4:3; +} +function caml_int64_compare(x,y) { + var x3 = x[3] << 16; + var y3 = y[3] << 16; + if (x3 > y3) return 1; + if (x3 < y3) return -1; + if (x[2] > y[2]) return 1; + if (x[2] < y[2]) return -1; + if (x[1] > y[1]) return 1; + if (x[1] < y[1]) return -1; + return 0; +} +function caml_int_compare (a, b) { + if (a < b) return (-1); if (a == b) return 0; return 1; +} +function caml_compare_val (a, b, total) { + var stack = []; + for(;;) { + if (!(total && a === b)) { + if (a instanceof MlString) { + if (b instanceof MlString) { + if (a != b) { + var x = a.compare(b); + if (x != 0) return x; + } + } else + return 1; + } else if (a instanceof Array && a[0] == (a[0]|0)) { + var ta = a[0]; + if (ta === 250) { + a = a[1]; + continue; + } else if (b instanceof Array && b[0] == (b[0]|0)) { + var tb = b[0]; + if (tb === 250) { + b = b[1]; + continue; + } else if (ta != tb) { + return (ta < tb)?-1:1; + } else { + switch (ta) { + case 248: { + var x = caml_int_compare(a[2], b[2]); + if (x != 0) return x; + break; + } + case 255: { + var x = caml_int64_compare(a, b); + if (x != 0) return x; + break; + } + default: + if (a.length != b.length) return (a.length < b.length)?-1:1; + if (a.length > 1) stack.push(a, b, 1); + } + } + } else + return 1; + } else if (b instanceof MlString || + (b instanceof Array && b[0] == (b[0]|0))) { + return -1; + } else { + if (a < b) return -1; + if (a > b) retur... [truncated message content] |