Commits

Anonymous committed ce56c52

type for maze & tiles, better that plain chars.

Comments (0)

Files changed (3)

maze/generator.ml

 (*ends by adding a door in the wall, taking care to open it in a usable path *)
 let gen_recdiv width height = 
   let min_size = 5 in
-  let maze = Array.make_matrix width height ' ' in
+  let maze = Array.make_matrix width height Maze.Open in
   let add_wall x1 y1 x2 y2 = 
     for x = x1 to x2 do
       for y = y1 to y2 do
-        Maze.set maze (x, y) '#' 
+        Maze.set maze (x, y) Maze.Wall
       done
     done
   in
   let rec open_vdoor xwall y h = 
     let door = y + Random.int h in   
-    if xwall + 1 < height && Maze.get maze (xwall+1, door) = '#'
-      || xwall -1 > 0 && Maze.get maze (xwall-1, door) = '#'
+    if xwall + 1 < height && Maze.get maze (xwall+1, door) = Maze.Wall
+      || xwall -1 > 0 && Maze.get maze (xwall-1, door) = Maze.Wall
     then open_vdoor xwall y h
-    else Maze.set maze (xwall, door) ' '
+    else Maze.set maze (xwall, door) Maze.Open
   in
   let rec open_hdoor x ywall w = 
     let door = x + Random.int w in
-    if ywall + 1 < width && Maze.get maze (door, ywall+1) = '#'
-      || ywall -1 > 0 && Maze.get maze (door, ywall-1) = '#'
+    if ywall + 1 < width && Maze.get maze (door, ywall+1) = Maze.Wall
+      || ywall -1 > 0 && Maze.get maze (door, ywall-1) = Maze.Wall
     then open_hdoor x ywall w
-    else Maze.set maze (door, ywall) ' '
+    else Maze.set maze (door, ywall) Maze.Open
   in  
   let rec vsplit x y w h = 
     if w < min_size then ()
   if Random.bool() then vsplit 0 0 width height
   else hsplit 0 0 width height;
     
-  let start = select_point maze 0 0 (width/2) (height/2) ' ' in
-  let goal = select_point maze (width/2) (height/2) (width-1) (height-1) ' ' in
-  Maze.set maze start '@';
-  Maze.set maze goal 'X';
+  let start = select_point maze 0 0 (width/2) (height/2) Maze.Open in
+  let goal = select_point maze 
+    (width/2) (height/2) (width-1) (height-1) Maze.Open in
+  Maze.set maze start Maze.Start;
+  Maze.set maze goal Maze.Goal;
   maze, start, goal      
 
 (*Start at a particular cell and call it the "exit."                          *)
 (* If that neighbor hasn't been visited, remove the wall between this cell    *)
 (* and that neighbor, and then recurse with that neighbor as the current cell.*)
 let gen_backtracker width height =
-  let maze = Array.make_matrix width height '#' in
+  let maze = Array.make_matrix width height Maze.Wall in
   (* start with a random point, with even coords *)
-  let start = select_point maze 0 0 (width-1) (height-1) '#' in
+  let start = select_point maze 0 0 (width-1) (height-1) Maze.Wall in
   let start = 
     if (fst start) mod 2 <> 0 then (fst start)-1, snd start else start in
   let start = 
     if (snd start) mod 2 <> 0 then fst start, (snd start)-1 else start in
   let remove_wall (x1, y1) (x2, y2) =
-    if x1 <> x2 then Maze.set maze ((max x1 x2)-1, y1) ' '
-    else if y1 <> y2 then Maze.set maze (x1, (max y1 y2)-1) ' '
+    if x1 <> x2 then Maze.set maze ((max x1 x2)-1, y1) Maze.Open
+    else if y1 <> y2 then Maze.set maze (x1, (max y1 y2)-1) Maze.Open
   in
   let even_neighbors maze (x, y) =
 	  let nodes = [] in
   let visited = ref [] in
   let rec recurse previous current =
     if not (List.mem current !visited) then begin
-	    Maze.set maze current ' ';
+	    Maze.set maze current Maze.Open;
 	    remove_wall previous current;
       visited := current :: !visited;      
       let shuffle lst = List.sort (fun a b -> (Random.int 3) - 1) lst in
     end    
   in
   recurse start start;
-  let goal = select_point maze 0 0 (width-1) (height-1) ' ' in
-  Maze.set maze start '@';
-  Maze.set maze goal 'X';  
+  let goal = select_point maze 0 0 (width-1) (height-1) Maze.Open in
+  Maze.set maze start Maze.Start;
+  Maze.set maze goal Maze.Goal;  
   maze, start, goal
 
 let rec add_holes maze n = match+ n with
   | _ -> 
     let x = Random.int ((Maze.width maze) -1)
     and y = Random.int ((Maze.height maze) -1) in
-    if Maze.get maze (x, y) = '#' then Maze.set maze (x, y) ' ';
+    if not (Maze.is_passable maze (x, y)) then Maze.set maze (x, y) Maze.Open;
     add_holes maze (pred n)
     
 let rec generate generator width height = match generator with
-module Parser = struct
-  let split separator s =
-    let list = ref [] in
-    let start = ref 0 in
-    let () = try
-        while true do
-          let index = String.index_from s !start separator in
-          list := (String.sub s !start (index - !start)) :: !list;
-          start := index + 1
-        done
-      with Not_found -> 
-        list := (String.sub s !start ((String.length s) - !start)) :: !list
-    in
-    List.rev !list
-  
-  let from_string str =
-    let ants = ref [] and goal = ref (0, 0) in
-    let lines = split '\n' str in
-    let height, width = List.length lines, String.length (List.hd lines) in
-    let maze = Array.make_matrix width height ' ' in
-    for x = 0 to width -1 do
-      for y = 0 to height -1 do
-        maze.(x).(y) <- (List.nth lines y).[x];
-        if maze.(x).(y) = '@' then ants := (x, y) :: !ants
-        else if maze.(x).(y) = 'X' then goal := x, y
-      done
-    done;
-    maze, !goal, !ants
-  
-  let from_file filename =
-    let channel = open_in_bin filename in
-    let size = in_channel_length channel in
-    let buffer = Buffer.create size in
-    Buffer.add_channel buffer channel size;
-    from_string (Buffer.contents buffer)
-end
+type tile = Start|Goal|Wall|Open
+type maze = tile array array
 
 let width maze = Array.length maze
 let height maze = Array.length maze.(0)
 let check maze (x, y) = 
   x >= 0 && y >= 0 && x < (width maze) && y < (height maze)
 
-let walk maze path =
-  let walk_once coords = if get maze coords = ' ' then set maze coords '.' in
-  List.iter walk_once path
+let tile_to_char = function
+  | Start -> '@'
+  | Goal -> 'X'
+  | Wall -> '#'
+  | Open -> ' '
 
-let draw maze =
+let to_string maze =
+  let buffer = Buffer.create ((height maze) * ((width maze) +1)) in
   for y = 0 to (height maze) -1 do
     for x = 0 to (width maze) -1 do
-      print_char (get maze (x, y))
+      let tile = tile_to_char (get maze (x, y)) in
+      Buffer.add_char buffer tile
     done;
-    print_newline ()
+    Buffer.add_char buffer '\n'
   done
 
-let is_passable maze coord = get maze coord <> '#'
+let is_passable maze coord = match get maze coord with
+  | Wall -> false
+  | _ -> true
 
 let distance (x1, y1) (x2, y2) =
   let square x = x * x in
   
   let draw_tile screen x y tile =
     let open Sdlvideo in
-    if tile = '@' then draw_img screen x y flag
-    else if tile = 'X' then draw_img screen x y castle
-    else begin
-      let gray = map_RGB screen (150, 150, 150) in
-      let background = match tile with
-        | 'X' -> map_RGB screen Sdlvideo.green
-        | '#' -> gray
-        | _ -> map_RGB screen Sdlvideo.white
-      in
-      draw_background screen x y background
-    end
+    let gray = map_RGB screen (150, 150, 150)
+    and white = map_RGB screen Sdlvideo.white in
+    match tile with
+      | Maze.Start -> draw_img screen x y flag
+      | Maze.Goal -> draw_img screen x y castle
+      | Maze.Wall -> draw_background screen x y gray
+      | Maze.Open -> draw_background screen x y white
   
   let draw_bullet screen maze bullet (x, y) =
     let tile = Maze.get maze (x, y) in
-    if tile = ' ' then
+    if tile = Maze.Open then
       draw_img screen x y bullet
     else
       draw_tile screen x y tile
   
   let draw_knight screen maze (x, y) =
     let tile = Maze.get maze (x, y) in
-    if tile = ' ' || tile = '@' then
+    if tile = Maze.Open || tile = Maze.Start then
       draw_img screen x y knight
   
   let draw_dragon screen maze (x, y) =
     let tile = Maze.get maze (x, y) in
-    if tile = ' ' || tile = '@' then
+    if tile = Maze.Open || tile = Maze.Start then
       draw_img screen x y dragon
   
   let draw_maze screen maze =
 
 module Game = struct
   type state = {
-    maze: char array array;
+    maze: Maze.maze;
     start: int * int;
     goal: int * int;
     dragon_delay: int;
     in
     if next = position then interact screen state
     else if not (Maze.check state.maze next)
-    || Maze.get state.maze next = '#' then begin
+      || not (Maze.is_passable state.maze next) then begin
       Sfx.play Sfx.error;
       interact screen state
     end