File: canvas-fifteen.ml

package info (click to toggle)
lablgtk3 3.1.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,796 kB
  • sloc: ml: 40,890; ansic: 22,312; makefile: 133; sh: 17
file content (144 lines) | stat: -rw-r--r-- 4,329 bytes parent folder | download | duplicates (6)
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
(**************************************************************************)
(*    Lablgtk - Examples                                                  *)
(*                                                                        *)
(*    This code is in the public domain.                                  *)
(*    You may freely copy parts of it in your application.                *)
(*                                                                        *)
(**************************************************************************)

let piece_size = 50

let piece_color nb =
  let y = nb / 4 in
  let x = nb mod 4 in
  let r = (4 - x) * 255 / 4 in
  let g = (4 - y) * 255 / 4 in
  let b = 128 in
  Printf.sprintf "#%02x%02x%02x" r g b

type config = {
    canvas : GnoCanvas.canvas ;
    board : (GnoCanvas.group * GnoCanvas.text) array ;
    pos : int array ;
    mutable hole : int ;
  }
    

let move config num dpos =
  assert(List.mem dpos [ -1; 1; -4; 4]) ;
  let (it, _ ) = config.board.(num) in
  it#move 
    ~x:(float (dpos mod 4 * piece_size))
    ~y:(float (dpos / 4 * piece_size))
    

let item_event config num ev =
  begin match ev with
  | `ENTER_NOTIFY _ ->
      let (_, text) = config.board.(num) in
      text#set [ `FILL_COLOR "white" ]
  | `LEAVE_NOTIFY _ ->
      let (_, text) = config.board.(num) in
      text#set [ `FILL_COLOR "black" ]
  | `BUTTON_PRESS _ ->
      let pos = config.pos.(num) in
      if List.mem (config.hole - pos) [ -1; 1; 4; -4; ]
      then
	let dpos = config.hole - pos in
	config.hole <- config.hole - dpos ;
	config.pos.(num) <- config.pos.(num) + dpos ;
	move config num dpos ;
	config.canvas#update_now ()
  | _ -> ()
  end ;
  false

let scramble_moves = 128

let array_find a v =
  let imax = Array.length a in
  let rec proc = function
    | i when i = imax -> raise Not_found
    | i when a.(i) = v -> i
    | i -> proc (succ i) in
  proc 0

let scramble config () =
  for i = 1 to scramble_moves do
    let new_pos = ref (-1) in
    let ok = ref false in
    while not !ok do
      let dpos = Array.get [| -1; 1; -4; 4|] (Random.int 4) in
      new_pos := config.hole + dpos ;
      if not ((config.hole mod 4 = 0 && dpos = -1) ||
              (config.hole mod 4 = 3 && dpos =  1) ||
              !new_pos < 0 || !new_pos > 15)
      then ok := true
    done ;
    let num = array_find config.pos !new_pos in
    move config num (config.hole - !new_pos) ;
    config.pos.(num) <- config.hole ;
    config.hole <- !new_pos ;
    config.canvas#update_now ()
  done


let create_canvas_fifteen window = 
  let vbox = GPack.vbox ~border_width:4 ~packing:window#add () in
  let align = GBin.alignment ~packing:vbox#add () in
  let frame = GBin.frame ~shadow_type:`IN ~packing:align#add () in
  let dim = piece_size * 4 + 1 in
  let canvas = GnoCanvas.canvas
      ~width:dim ~height:dim
      ~packing:frame#add () in
  canvas#set_scroll_region 0. 0. (float dim) (float dim) ;
  let board = Array.init 15
      (fun i ->
	let x = i mod 4 in
	let y = i / 4 in
	let tile = 
	  GnoCanvas.group 
	    ~x:(float (x * piece_size)) ~y:(float (y * piece_size))
	    canvas#root in
	GnoCanvas.rect tile
	  ~props:[ `X1 0.; `Y1 0. ; `X2 (float piece_size) ; `Y2 (float piece_size) ;
		   `FILL_COLOR (piece_color i) ; `OUTLINE_COLOR "black" ;
		   `WIDTH_PIXELS 0 ] ;
	let text = 
	  GnoCanvas.text tile
	    ~props:[ `TEXT (string_of_int (succ i)) ; 
		     `X (float piece_size /. 2.) ;
		     `Y (float piece_size /. 2.) ;
		     `FONT "Sans bold 24" ;
		     `FILL_COLOR "black" ;
		     `ANCHOR `CENTER ] in
	(tile, text)) in
  let config = {
    canvas = canvas ;
    board = board ;
    pos = Array.init 15 (fun i -> i) ;
    hole = 15 ;
  } in
  Array.iteri
    (fun i ((tile : GnoCanvas.group), _) -> tile#connect#event (item_event config i) ; ())
    config.board ;
  let button = GButton.button ~label:"Scramble" ~packing:vbox#add () in
  button#connect#clicked (scramble config)



let main_1 () =
  Random.self_init () ;
  let window = GWindow.window () in
  create_canvas_fifteen window ;
  window#connect#destroy ~callback:GMain.Main.quit ;
  window#show () ;
  GMain.Main.main ()

let _ = 
   main_1 ()


(* Local Variables: *)
(* compile-command: "ocamlopt -w s -i -I ../../src lablgtk.cmxa gtkInit.cmx lablgnomecanvas.cmxa canvas-fifteen.ml" *)
(* End: *)