File: main.ml

package info (click to toggle)
obrowser 1.1%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 3,216 kB
  • ctags: 3,498
  • sloc: ml: 13,505; makefile: 343; sh: 11
file content (404 lines) | stat: -rw-r--r-- 12,497 bytes parent folder | download | duplicates (2)
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
open Js

type relief = Top | Bot | Flat
    
type box_config =
    { x:int; y:int; w:int; h:int; bw:int; mutable r:relief ;
      b1_col : Graphics.color ;
      b2_col : Graphics.color ;
      b_col : Graphics.color}
      
let draw_box_outline bcf col = 
  Graphics.set_color col ;
  Graphics.draw_rect bcf.x bcf.y bcf.w  bcf.h
    
let draw_box bcf = 
  let x1 = bcf.x and y1 = bcf.y in
  let x2 = x1+bcf.w and y2 = y1+bcf.h in 
  let ix1 = x1+bcf.bw
  and ix2 = x2-bcf.bw 
  and iy1 = y1+bcf.bw
  and iy2 = y2-bcf.bw in 
  let border1 g =
    Graphics.set_color g;
    Graphics.fill_poly 
      [| (x1,y1);(ix1,iy1);(ix2,iy1);(ix2,iy2);(x2,y2);(x2,y1) |] 
  in
  let border2 g = 
    Graphics.set_color g;
    Graphics.fill_poly 
      [| (x1,y1);(ix1,iy1);(ix1,iy2);(ix2,iy2);(x2,y2);(x1,y2) |]
  in
    Graphics.set_color bcf.b_col;
    ( match bcf.r with
          Top  -> 
            Graphics.fill_rect ix1 iy1 (ix2-ix1) (iy2-iy1) ;
            border1 bcf.b1_col ; 
            border2 bcf.b2_col
	| Bot  -> 
            Graphics.fill_rect ix1 iy1 (ix2-ix1) (iy2-iy1) ;
            border1 bcf.b2_col ; 
            border2 bcf.b1_col
	| Flat -> 
            Graphics.fill_rect x1 y1 bcf.w bcf.h ) ;
    draw_box_outline bcf Graphics.black
      
let erase_box bcf = 
  Graphics.set_color bcf.b_col ; 
  Graphics.fill_rect
    (bcf.x+bcf.bw) (bcf.y+bcf.bw) 
    (bcf.w-(2*bcf.bw)) (bcf.h-(2*bcf.bw))

type position = Left | Center | Right

let draw_string_in_box pos str bcf col = 
  let (w, h) = Graphics.text_size str in
  let ty = bcf.y + (bcf.h-h)/2 in 
    ( match pos with 
          Center -> Graphics.moveto (bcf.x + (bcf.w-w)/2) ty 
        | Right  -> let tx = bcf.x + bcf.w - w - bcf.bw - 1 in 
            Graphics.moveto tx ty 
        | Left   -> let tx = bcf.x + bcf.bw + 1 in Graphics.moveto tx ty  ) ;
    Graphics.set_color col ;
    Graphics.draw_string str

let set_grey x = Graphics.rgb x x x

let grey1 = set_grey 100
and grey2 = set_grey 170
and grey3= set_grey 240

type config = { 
  nbcols  : int ;
  nbrows : int ; 
  nbmines : int }

let default_config = { nbcols=10; nbrows=10; nbmines=15 } 

type cell = { 
  mutable mined : bool ;
  mutable seen : bool ; 
  mutable flag : bool ; 
  mutable nbm : int     
} 


type board = cell array array  

let iter_on_cell cf f = 
  for i=0 to cf.nbcols-1 do for j=0 to cf.nbrows-1 do f (i,j) done done 

let random_list_mines lc m = 
  let cell_list = ref [] 
  in while (List.length !cell_list) < m do 
      let n = Random.int lc in
        if not (List.mem n !cell_list) then cell_list := n :: !cell_list 
    done ;
    !cell_list 

let generate_seed () =
  let t = Sys.time () in           
  let n = int_of_float (t*.1000.0) 
  in Random.init(n mod 100000)            


let valid cf (i,j) = i>=0 && i<cf.nbcols && j>=0 && j<cf.nbrows  

let neighbours cf (x,y) =
  let ngb = [x-1,y-1; x-1,y; x-1,y+1; x,y-1; x,y+1; x+1,y-1; x+1,y; x+1,y+1]
  in List.filter (valid cf) ngb 


let initialize_board cf = 
  let cell_init () = { mined=false; seen=false; flag=false; nbm=0 } in 
  let copy_cell_init b (i,j) = b.(i).(j) <- cell_init() in
  let set_mined b n = b.(n / cf.nbrows).(n mod cf.nbrows).mined <- true
  in
  let count_mined_adj b (i,j) =
    let x = ref 0 in
    let inc_if_mined (i,j) = if b.(i).(j).mined then incr x 
    in List.iter inc_if_mined (neighbours cf (i,j)) ;
      !x
  in
  let set_count b (i,j) =
    if not b.(i).(j).mined 
    then b.(i).(j).nbm <- count_mined_adj b (i,j)
  in
  let list_mined = random_list_mines (cf.nbcols*cf.nbrows) cf.nbmines in 
  let board = Array.make_matrix cf.nbcols cf.nbrows (cell_init ()) 
  in iter_on_cell cf (copy_cell_init board) ;
    List.iter (set_mined board) list_mined ;
    iter_on_cell cf (set_count board) ;
    board 

let cells_to_see bd cf (i,j) = 
  let visited = Array.make_matrix cf.nbcols cf.nbrows false in 
  let rec relevant = function 
      [] -> ([],[])
    | ((x,y) as c)::l -> 
        let cell=bd.(x).(y)
        in if cell.mined || cell.flag || cell.seen || visited.(x).(y) 
          then relevant l
          else let (l1,l2) = relevant l 
          in visited.(x).(y) <- true ;
            if cell.nbm=0 then (l1,c::l2) else (c::l1,l2)
  in 
  let rec cells_to_see_rec = function 
      [] -> []  
    | ((x,y) as c)::l -> 
        if bd.(x).(y).nbm<>0 then c :: (cells_to_see_rec l)
        else let (l1,l2) = relevant (neighbours cf c)
        in  (c :: l1)  @  (cells_to_see_rec (l2 @ l))
  in visited.(i).(j) <- true ;
    cells_to_see_rec [(i,j)]  

let b0 = 3 
let l1 = 15 
let l2 = l1 
let l4 = 20 + 2*b0 
let l3 = l4*default_config.nbcols + 2*b0 
let l5 = 40 + 2*b0 


let h1 = l1 
let h2 = 30 
let h3 = l5+20 + 2*b0 
let h4 = h2 
let h5 = 20 + 2*b0 
let h6 = l5 + 2*b0 


type window_config = {
  cf : config ;            
  g_bcf : box_config ;   
  f_bcf : box_config ; 
  m_bcf : box_config ;
  m1_bcf : box_config ;
  m2_bcf : box_config ; 
  s_bcf : box_config ; 
  mutable cc_bcf : box_config ;
  cell : int*int -> (int*int) ;
  coor : int*int -> (int*int) 
} 

let make_box x y w h bw r =
  { x=x; y=y; w=w; h=h; bw=bw; r=r; b1_col=grey1; b2_col=grey3; b_col=grey2 } 
let make_wcf cf = 
  let wcols =  b0 + cf.nbcols*l4 + b0 
  and hrows =  b0 + cf.nbrows*h5 + b0  in
  let g_bcf =  let gw = (b0 + l1 + wcols + l2 + b0) 
               and gh = (b0 + h1 + hrows + h2 + h3 + h4 + b0)
  in make_box 0 0 gw gh b0 Top
  and f_bcf = make_box l1 h1 wcols hrows b0 Bot  in
  let m_bcf = make_box  ((g_bcf.w - l3) / 2) (b0+h1+hrows+h2) l3 h3 b0 Bot  in 
  let m1_bcf = make_box (m_bcf.x + b0) (b0 + h1 + hrows + h2)
    ((l3-l5)/2-(2*b0)) (h3-(2*b0)) 5 Flat  in
  let s_bcf = make_box (m1_bcf.x + m1_bcf.w) 
    (m1_bcf.y + (h3-h6) / 2) l5 h6 b0 Top  in 
  let m2_bcf = make_box (s_bcf.x + s_bcf.w) 
    m1_bcf.y m1_bcf.w m1_bcf.h 5 Flat  in
  let cc_bcf = make_box 0 0 l4 h5 b0 Top
  in { cf = cf; 
       g_bcf = g_bcf; f_bcf=f_bcf; m_bcf=m_bcf; m1_bcf=m1_bcf; 
       s_bcf=s_bcf; m2_bcf=m2_bcf; cc_bcf = cc_bcf;
       cell = (fun (i,j) -> ( l1+b0+l4*i , h1+b0+h5*j)) ;
       coor = (fun (x,y) -> ( (x-l1)/l4 , (y-h1)/h5 )) } 

let close_ccell wcf i j =
  let x,y = wcf.cell (i,j) 
  in wcf.cc_bcf <- {wcf.cc_bcf with x=x; y=y; r=Top} 

let open_ccell wcf i j =
  let x,y = wcf.cell (i,j) 
  in wcf.cc_bcf <- {wcf.cc_bcf with x=x; y=y; r=Flat}  

let draw_closed_cc wcf i j = 
  close_ccell wcf i j;
  draw_box wcf.cc_bcf 

let draw_num_cc wcf i j n =
  open_ccell wcf i j ;
  draw_box wcf.cc_bcf ;
  if n<>0 then draw_string_in_box Center (string_of_int n) 
    wcf.cc_bcf Graphics.white 

let draw_bomb_cc wcf i j = 
  open_ccell wcf i j ;
  let cc = wcf.cc_bcf 
  in draw_box wcf.cc_bcf ;
    Graphics.set_color Graphics.black ; 
    Graphics.fill_circle (cc.x+cc.w/2) (cc.y+cc.h/2) (cc.h/3) 

let draw_flag_cc wcf i j =
  close_ccell wcf i j ;
  draw_box wcf.cc_bcf ;
  draw_string_in_box Center "!" wcf.cc_bcf Graphics.blue 

let draw_cross_cc wcf i j =
  let x,y = wcf.cell (i,j) 
  and w,h = wcf.cc_bcf.w, wcf.cc_bcf.h in
  let a=x+w/4 and b=x+3*w/4 
	      and c=y+h/4 and d=y+3*h/4 
  in Graphics.set_color Graphics.red ;
    Graphics.set_line_width 3 ;
    Graphics.moveto a d ; Graphics.lineto b c ; 
    Graphics.moveto a c ; Graphics.lineto b d ;
    Graphics.set_line_width 1 

let draw_cell wcf bd i j = 
  let cell = bd.(i).(j) 
  in match (cell.flag, cell.seen , cell.mined ) with 
      (true,_,_)  -> draw_flag_cc wcf i j
    | (_,false,_) -> draw_closed_cc wcf i j
    | (_,_,true)  -> draw_bomb_cc wcf i j
    | _           -> draw_num_cc wcf i j cell.nbm  

let draw_cell_end wcf bd i j = 
  let cell = bd.(i).(j) 
  in match (cell.flag, cell.mined ) with 
      (true,true) -> draw_flag_cc wcf i j
    | (true,false) -> draw_num_cc wcf i j cell.nbm; draw_cross_cc wcf i j
    | (false,true) -> draw_bomb_cc wcf i j
    | (false,false) -> draw_num_cc wcf i j cell.nbm 

let draw_flag_switch wcf on =  
  if on  then wcf.s_bcf.r <- Bot  else wcf.s_bcf.r <- Top ;
  draw_box wcf.s_bcf ;
  if on  then draw_string_in_box Center "ON" wcf.s_bcf Graphics.red
  else draw_string_in_box Center "OFF" wcf.s_bcf Graphics.blue 

let draw_mark_title wcf =
  let m = "Marquage" in 
  let w,h = Graphics.text_size m in
  let x = (wcf.g_bcf.w-w)/2 
  and y0 = wcf.m_bcf.y+wcf.m_bcf.h in
  let y = y0+(wcf.g_bcf.h-(y0+h))/2 
  in Graphics.moveto x y ;
    Graphics.draw_string m  

let print_score wcf nbcto nbfc =
  erase_box wcf.m1_bcf ;
  draw_string_in_box Center (string_of_int nbcto) wcf.m1_bcf Graphics.blue ;
  erase_box wcf.m2_bcf ;
  draw_string_in_box Center (string_of_int (wcf.cf.nbmines-nbfc)) wcf.m2_bcf 
    ( if nbfc>wcf.cf.nbmines then Graphics.red else Graphics.blue ) 

let draw_field_initial wcf = 
  draw_closed_cc wcf 0 0 ;
  let cc = wcf.cc_bcf  in 
  let bitmap = draw_box cc ; Graphics.get_image cc.x cc.y cc.w cc.h  in
  let draw_bitmap (i,j) = let x,y=wcf.cell (i,j) 
  in Graphics.draw_image bitmap x y 
  in iter_on_cell wcf.cf draw_bitmap  

let draw_field_end wcf bd = 
  iter_on_cell wcf.cf (fun (i,j) -> draw_cell_end wcf bd i j)  

let open_wcf wcf = 
  Node.append
    (get_element_by_id "body")
    (Graphics.open_graph wcf.g_bcf.w wcf.g_bcf.h) ;
  draw_box wcf.g_bcf ;
  draw_box wcf.m_bcf ;
  draw_flag_switch wcf false ;
  draw_box wcf.f_bcf ;
  draw_field_initial wcf ;
  draw_mark_title wcf ;
  print_score wcf ((wcf.cf.nbrows*wcf.cf.nbcols)-wcf.cf.nbmines) 0 

type clickon = Out | Cell of (int*int) | SelectBox  

let locate_click wcf st1 st2 =
  let clickon_of st = 
    let x = st.Graphics.mouse_x and y = st.Graphics.mouse_y
    in if x>=wcf.s_bcf.x && x<=wcf.s_bcf.x+wcf.s_bcf.w && 
        y>=wcf.s_bcf.y && y<=wcf.s_bcf.y+wcf.s_bcf.h  
      then SelectBox
      else let (x2,y2) = wcf.coor (x,y)
      in if x2>=0 && x2<wcf.cf.nbcols && y2>=0 && y2<wcf.cf.nbrows
      then Cell (x2,y2) else Out
  in 
  let r1=clickon_of st1 and r2=clickon_of st2
  in if r1=r2 then r1 else Out 

type demin_cf = 
    { wcf : window_config; bd : cell array array;
      mutable nb_marked_cells : int; 
      mutable nb_hidden_cells : int;  
      mutable flag_switch_on : bool } 

exception Fin

let loop d f_init f_key f_mouse f_end = 
  try
    f_init ();
    while true do 
      let st = Graphics.wait_next_event 
        [Graphics.Button_down;Graphics.Key_pressed]  
      in if st.Graphics.keypressed  then f_key st.Graphics.key
        else let st2 = Graphics.wait_next_event [Graphics.Button_up] 
        in f_mouse (locate_click d.wcf st st2)
    done
  with Fin -> f_end ()

let d_init d () = open_wcf d.wcf          
let d_end  () = Graphics.close_graph()
let d_key c = if c='q' || c='Q' then raise Fin

let mark_cell d i j =
  if d.bd.(i).(j).flag 
  then ( d.nb_marked_cells <- d.nb_marked_cells -1; 
         d.bd.(i).(j).flag <- false )
  else ( d.nb_marked_cells <- d.nb_marked_cells +1 ; 
         d.bd.(i).(j).flag <- true ) ;
  draw_cell d.wcf d.bd i j ;
  print_score d.wcf d.nb_hidden_cells d.nb_marked_cells

let ending d str = 
  draw_field_end d.wcf d.bd ;
  erase_box  d.wcf.s_bcf ;
  draw_string_in_box Center str d.wcf.s_bcf Graphics.black;
  ignore(Graphics.wait_next_event 
           [Graphics.Button_down;Graphics.Key_pressed]);
  raise Fin

let reveal d i j = 
  let reveal_cell (i,j) = 
    d.bd.(i).(j).seen <- true ; 
    draw_cell d.wcf d.bd i j ;
    d.nb_hidden_cells <- d.nb_hidden_cells -1 
  in 
    List.iter reveal_cell (cells_to_see d.bd d.wcf.cf (i,j)) ;
    print_score d.wcf d.nb_hidden_cells d.nb_marked_cells ;
    if d.nb_hidden_cells = 0 then ending d "GAGNE"

let d_mouse d click = match click with 
    Cell (i,j) -> 
      if d.bd.(i).(j).seen then ()
      else if d.flag_switch_on then mark_cell d i j 
      else if d.bd.(i).(j).flag then ()
      else if d.bd.(i).(j).mined then ending d "PERDU"
      else reveal d i j
  | SelectBox -> 
      d.flag_switch_on <- not d.flag_switch_on;
      draw_flag_switch d.wcf d.flag_switch_on
  | Out -> () 

let create_demin nb_c nb_r nb_m = 
  let nbc = max default_config.nbcols nb_c 
  and nbr = max default_config.nbrows nb_r in 
  let nbm = min (nbc*nbr) (max 1 nb_m) in
  let cf = { nbcols=nbc ; nbrows=nbr ; nbmines=nbm } in 
    generate_seed () ;
    let wcf = make_wcf cf in
      {  wcf = wcf ;
	 bd = initialize_board wcf.cf;
	 nb_marked_cells = 0; 
	 nb_hidden_cells = cf.nbrows*cf.nbcols-cf.nbmines;
	 flag_switch_on = false } 

let go nbc nbr nbm = 
  let d = create_demin nbc nbr nbm in
    loop d (d_init d) d_key (d_mouse d) (d_end)

let _ = go 20 20 15