Guest User

Untitled

a guest
Mar 10th, 2012
222
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
OCaml 4.12 KB | None | 0 0
  1. let split separator s =
  2.   let list = ref [] in
  3.   let start = ref 0 in
  4.   let () = try
  5.       while true do
  6.         let index = String.index_from s !start separator in
  7.         list := (String.sub s !start (index - !start)) :: !list;
  8.         start := index + 1
  9.       done
  10.     with Not_found -> list := (String.sub s !start ((String.length s) - !start)) :: !list
  11.   in List.rev !list
  12.  
  13. let read_maze filename =
  14.   let channel = open_in_bin filename in
  15.   let size = in_channel_length channel in
  16.   let buffer = Buffer.create size in
  17.   Buffer.add_channel buffer channel size;
  18.   let s = Buffer.contents buffer in
  19.   let lines = split '\n' s in
  20.   let height, width = List.length lines, String.length (List.hd lines) in
  21.   let maze = Array.make_matrix width height ' ' in
  22.   for x = 0 to width -1 do
  23.     for y = 0 to height -1 do
  24.       maze.(x).(y) <- (List.nth lines y).[x]
  25.     done
  26.   done;
  27.   maze
  28.  
  29. let width maze = Array.length maze
  30. let height maze = Array.length maze.(0)
  31.  
  32. let maze_get maze (x, y) = maze.(x).(y)
  33.  
  34. let maze_set maze (x, y) value = maze.(x).(y) <- value
  35.  
  36. let draw maze =
  37.   for y = 0 to (height maze) -1 do
  38.     for x = 0 to (width maze) -1 do
  39.       print_char (maze_get maze (x, y))
  40.     done;
  41.     print_newline ()
  42.   done
  43.  
  44. let distance (x1, y1) (x2, y2) =
  45.   let square x = x * x in
  46.   let sqrt_int x = int_of_float (sqrt (float_of_int x)) in
  47.   sqrt_int (square (x1 - x2) + square (y1 - y2))
  48.  
  49. let neighbor_nodes maze (x, y) =
  50.   let all = [x -1, y; x +1, y; x, y -1; x, y +1;] in
  51.   let filter (x, y) = x >= 0 && y >= 0 && x < width maze && y < height maze in
  52.   List.filter filter all
  53.  
  54. let is_passable maze coord = maze_get maze coord <> '#'
  55.  
  56. exception No_path_found
  57.  
  58. let default_hashtbl_size = 3000
  59.  
  60. let rec reconstruct_path hashtbl node path =
  61.   if Hashtbl.mem hashtbl node then
  62.     let path = node :: path
  63.     in reconstruct_path hashtbl (Hashtbl.find hashtbl node) path
  64.   else
  65.     node :: path
  66.  
  67. let find_path maze start goal heuristic =
  68.   let gscore = Hashtbl.create default_hashtbl_size
  69.   and fscore = Hashtbl.create default_hashtbl_size in
  70.  
  71.   let module CoordSet = Set.Make(
  72.     struct
  73.       type t = int * int
  74.       let compare a b =
  75.         let score_a = try Hashtbl.find fscore a with Not_found -> max_int in
  76.         let score_b = try Hashtbl.find fscore b with Not_found -> max_int in
  77.         let diff = score_a - score_b in
  78.         if diff = 0 then Pervasives.compare a b else diff
  79.     end) in
  80.  
  81.   Hashtbl.add gscore start 0;
  82.   Hashtbl.add fscore start (heuristic start goal);
  83.  
  84.   let closedset = ref []
  85.   and openset = ref (CoordSet.singleton start)
  86.   and camefrom = Hashtbl.create default_hashtbl_size in
  87.  
  88.   let rec loop () =
  89.     if CoordSet.is_empty !openset then raise No_path_found
  90.     else
  91.       let current = CoordSet.min_elt !openset in
  92.       if current = goal then List.rev (reconstruct_path camefrom goal [])
  93.       else begin
  94.         openset := CoordSet.remove current !openset;
  95.         closedset := current :: !closedset;
  96.        
  97.         let set_scores node real_gscore =
  98.           Hashtbl.add camefrom node current;
  99.           Hashtbl.add gscore node real_gscore;
  100.           Hashtbl.add fscore node (real_gscore + (heuristic node goal))
  101.         in let neighbors = neighbor_nodes maze current in
  102.        
  103.         let explore node =
  104.           if is_passable maze node && not (List.mem node !closedset) then
  105.             let tentative_gscore = (Hashtbl.find gscore current) + 1 in
  106.             if not (CoordSet.mem node !openset) then begin
  107.               set_scores node tentative_gscore;
  108.               openset := CoordSet.add node !openset;
  109.             end
  110.             else if tentative_gscore < Hashtbl.find gscore node then set_scores node tentative_gscore
  111.         in List.iter explore neighbors;
  112.         loop ()
  113.       end
  114.   in loop ()
  115.  
  116. let () =
  117.   let maze = read_maze "maze.txt" in
  118.   let path =
  119.     for i = 0 to 1000 do
  120.       ignore (find_path maze (0, 0) (78, 29) distance)
  121.     done;
  122.     find_path maze (0, 0) (78, 29) distance
  123.   in
  124.   let walk coords = maze_set maze coords '.' in
  125.   List.iter walk path;
  126.   draw maze;
  127.   Printf.printf "%d steps\n" (List.length path)
Advertisement
Add Comment
Please, Sign In to add comment