1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
(**************************************************************************)
(* Lablgtk - Examples *)
(* *)
(* This code is in the public domain. *)
(* You may freely copy parts of it in your application. *)
(* *)
(**************************************************************************)
(* $Id$ *)
open StdLabels
(* The game logic *)
type color = [`none|`white|`black]
module type BoardSpec = sig
type t
val size : int
val get : t -> x:int -> y:int -> color
val set : t -> x:int -> y:int -> color:color -> unit
end
module Board (Spec : BoardSpec) = struct
open Spec
let size = size
let on_board x y =
x >= 0 && x < size && y >= 0 && y < size
let rec string board ~x ~y ~dx ~dy ~color l =
let x = x+dx and y = y+dy in
if on_board x y then
let col = get board ~x ~y in
if col = (color : [`white|`black] :> color) then l else
if col = `none then [] else
string board ~x ~y ~dx ~dy ~color ((x,y)::l)
else []
let find_swaps board ~x ~y ~color =
if get board ~x ~y <> `none then [] else
List.fold_left [-1,-1; -1,0; -1,1; 0,-1; 0,1; 1,-1; 1,0; 1,1]
~init:[]
~f:(fun acc (dx,dy) -> string board ~x ~y ~dx ~dy ~color [] @ acc)
let action board ~x ~y ~color =
let swaps = find_swaps board ~x ~y ~color in
if swaps = [] then false else begin
List.iter ((x,y)::swaps)
~f:(fun (x,y) -> set board ~x ~y ~color:(color :> color));
true
end
let check_impossible board ~color =
try
for x = 0 to size - 1 do for y = 0 to size - 1 do
if find_swaps board ~x ~y ~color <> [] then raise Exit
done done;
true
with Exit -> false
let count_cells board =
let w = ref 0 and b = ref 0 in
for x = 0 to size - 1 do for y = 0 to size - 1 do
match get board ~x ~y with
`white -> incr w
| `black -> incr b
| `none -> ()
done done;
(!w,!b)
end
(* GUI *)
open GMain
(* Toplevel window *)
let window = GWindow.window ~title:"pousse" ()
(* Create pixmaps *)
let pixdraw =
GDraw.pixmap ~window ~width:40 ~height:40 ~mask:true ()
let pixdraw1 =
GDraw.pixmap ~window ~width:40 ~height:40 ~mask:true ()
let pixdraw2 =
GDraw.pixmap ~window ~width:40 ~height:40 ~mask:true ()
let _ =
pixdraw1#set_foreground `BLACK;
pixdraw1#arc ~x:3 ~y:3 ~width:34 ~height:34 ~filled:true ();
pixdraw2#set_foreground `WHITE;
pixdraw2#arc ~x:3 ~y:3 ~width:34 ~height:34 ~filled:true ();
pixdraw2#set_foreground `BLACK;
pixdraw2#arc ~x:3 ~y:3 ~width:34 ~height:34 ()
(* The cell class: a button with a pixmap on it *)
class cell ?packing ?show () =
let button = GButton.button ?packing ?show () in
object (self)
inherit GObj.widget button#as_widget
method connect = button#connect
val mutable color : color = `none
val pm = GMisc.pixmap pixdraw ~packing:button#add ()
method color = color
method set_color col =
if col <> color then begin
color <- col;
pm#set_pixmap
(match col with `none -> pixdraw
| `black -> pixdraw1
| `white -> pixdraw2)
end
end
module RealBoard = Board (
struct
type t = cell array array
let size = 8
let get (board : t) ~x ~y = board.(x).(y)#color
let set (board : t) ~x ~y ~color = board.(x).(y)#set_color color
end
)
(* Conducting a game *)
open RealBoard
class game ~(frame : #GContainer.container) ~(label : #GMisc.label)
~(statusbar : #GMisc.statusbar) =
let table = GPack.table ~columns:size ~rows:size ~packing:frame#add () in
object (self)
val cells =
Array.init size
~f:(fun i -> Array.init size
~f:(fun j -> new cell ~packing:(table#attach ~top:i ~left:j) ()))
val label = label
val turn = statusbar#new_context ~name:"turn"
val messages = statusbar#new_context ~name:"messages"
val mutable current_color = `black
method board = cells
method table = table
method player = current_color
method swap_players () =
current_color <-
match current_color with
`white -> turn#pop (); turn#push "Player is black"; `black
| `black -> turn#pop (); turn#push "Player is white"; `white
method finish () =
turn#pop ();
let w, b = count_cells cells in
turn#push
(if w > b then "White wins" else
if w < b then "Black wins" else
"Game is a draw");
()
method update_label () =
let w, b = count_cells cells in
label#set_text (Printf.sprintf "White: %d Black: %d " w b)
method play x y =
if action cells ~x ~y ~color:current_color then begin
self#update_label ();
self#swap_players ();
if check_impossible cells ~color:current_color then begin
self#swap_players ();
if check_impossible cells ~color:current_color then self#finish ()
end
end else
messages#flash "You cannot play there"
initializer
for i = 0 to size-1 do for j = 0 to size-1 do
let cell = cells.(i).(j) in
cell#connect#enter ~callback:cell#misc#grab_focus;
cell#connect#clicked ~callback:(fun () -> self#play i j)
done done;
List.iter ~f:(fun (x,y,col) -> cells.(x).(y)#set_color col)
[ 3,3,`black; 4,4,`black; 3,4,`white; 4,3,`white ];
self#update_label ();
turn#push "Player is black";
()
end
(* Graphical elements *)
let vbox = GPack.vbox ~packing:window#add ()
let frame = GBin.frame ~shadow_type:`IN ~packing:vbox#add ()
let hbox = GPack.hbox ~packing:vbox#pack ()
let bar = GMisc.statusbar ~packing:hbox#add ()
let frame2 = GBin.frame ~shadow_type:`IN ~packing:hbox#pack ()
let label =
GMisc.label ~justify:`LEFT ~xpad:5 ~xalign:0.0 ~packing:frame2#add ()
let game = new game ~frame ~label ~statusbar:bar
(* Start *)
let _ =
window#connect#destroy ~callback:Main.quit;
window#show ();
Main.main ()
|