File: 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 (106 lines) | stat: -rw-r--r-- 3,427 bytes parent folder | download | duplicates (3)
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
(**************************************************************************)
(*    Lablgtk - Examples                                                  *)
(*                                                                        *)
(*    This code is in the public domain.                                  *)
(*    You may freely copy parts of it in your application.                *)
(*                                                                        *)
(**************************************************************************)

(* $Id$ *)

open StdLabels
open Gaux
open Gtk
open GObj

class position ~init_x ~init_y ~min_x ~min_y ~max_x ~max_y = object
  val mutable x = init_x
  val mutable y = init_y
  method current = (x, y)
  method up ()    = if y > min_y then y <- y-1 else (); (x, y)
  method down ()  = if y < max_y then y <- y+1 else (); (x, y)
  method left ()  = if x > min_x then x <- x-1 else (); (x, y)
  method right () = if x < max_x then x <- x+1 else (); (x, y)
end

let game_init () = (* generate initial puzzle state *)
  let rec game_aux acc rest n_invert =
    let len = List.length rest in
    if len=0 then
      if n_invert mod 2 = 0 then
	acc (* to be solvable, n_invert must be even *)
      else
	(List.hd (List.tl acc))::(List.hd acc)::(List.tl (List.tl acc))
    else begin
      let rec extract n xs =
      	if (n=0) then (List.hd xs, List.tl xs)
      	else
	  let (ans, ys) = extract (n-1) (List.tl xs) in
          (ans, List.hd xs :: ys) in
      let ran = Random.int len in
      let (elm, rest1) = extract ran rest in
      let rec count p xs = match xs with
	[] -> 0
      |	y :: ys -> let acc = count p ys in
	         if p y then 1+acc else acc
      in
      let new_n_invert = count (fun x -> elm > x) acc in
      game_aux (elm :: acc) rest1 (n_invert+new_n_invert)
    end in
  let rec from n = if n=0 then [] else n :: from (n-1) in
  game_aux [] (from 15) 0
      
let _ = Random.init (int_of_float (Sys.time () *. 1000.))
let _ = GMain.init ()
let window = GWindow.window ()
let _ = window#connect#destroy ~callback:GMain.quit

let tbl = GPack.table ~rows:4 ~columns:4 ~homogeneous:true ~packing:window#add ()
let dummy = GMisc.label ~text:"" ~packing:(tbl#attach ~left:3 ~top:3) ()
let arr = Array.make_matrix ~dimx:4 ~dimy:4 dummy
let init = game_init ()
let _ =
  for i = 0 to 15 do
    let j = i mod 4  in
    let k = i/4 in
    let frame =
      GBin.frame ~shadow_type:`OUT ~width:32 ~height:32
	~packing:(tbl#attach ~left:j ~top:k) () in
    if i < 15 then
      arr.(j).(k) <-
	GMisc.label ~text:(string_of_int (List.nth init i))
	  ~packing:frame#add ()
  done
let pos = new position ~init_x:3 ~init_y:3 ~min_x:0 ~min_y:0 ~max_x:3 ~max_y:3
    
open GdkKeysyms

let _ =
  window#event#connect#key_press ~callback:
    begin fun ev ->
      let (x0, y0) = pos#current in
      let wid0 = arr.(x0).(y0) in
      let key = GdkEvent.Key.keyval ev in
      if key = _q || key = _Escape then (GMain.quit (); exit 0) else
      let (x1, y1) =
	if key = _h || key = _Left then 
          pos#right ()
	else if key = _j || key = _Down then
	  pos#up ()
	else if key = _k || key = _Up then
	  pos#down ()
	else if key = _l || key = _Right then
	  pos#left ()
	else (x0, y0)
      in
      let wid1 = arr.(x1).(y1) in
      wid0#set_text (wid1#text);
      wid1#set_text "";
      true
    end
	      
let main () = 
  window#show ();
  GMain.main ()

let _ = main ()