Guest User

Untitled

a guest
Mar 10th, 2012
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
OCaml 4.18 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.   let () = Buffer.add_channel buffer channel size in
  18.   let s = Buffer.contents buffer in
  19.   let lines = split '\n' s in
  20.   let height, width = List.length lines, String.length (List.nth lines 0) 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 coord =
  33.   let x, y = coord in maze.(x).(y)
  34.  
  35. let maze_set maze coord value =
  36.   let x, y = coord in maze.(x).(y) <-value
  37.  
  38. let draw maze =
  39.   for y = 0 to (height maze) -1 do
  40.     for x = 0 to (width maze) -1 do
  41.       print_char (maze_get maze (x, y))
  42.     done;
  43.     print_newline ()
  44.   done
  45.  
  46. let distance (x1, y1) (x2, y2) =
  47.   let square x = x * x in
  48.   let sqrt_int x = int_of_float (sqrt (float_of_int x)) in
  49.   sqrt_int (square (x1-x2) + square (y1-y2))
  50.  
  51. let neighbor_nodes maze coord =
  52.   let x, y = coord in
  53.   let all = [x-1,y; x+1,y; x,y-1; x,y+1;] in
  54.   let filter (x, y) = x >= 0 && y >= 0 && x < width maze && y < height maze in
  55.   List.filter filter all      
  56.  
  57. let is_passable maze coord = maze_get maze coord <> '#'  
  58.  
  59. exception No_path_found
  60.  
  61.  
  62. module CoordTable = Hashtbl.Make(
  63.   struct
  64.     type t = int * int    
  65.     let equal a b = a = b    
  66.     let hash a = (fst a) * 64 + (snd a)
  67.   end)
  68.  
  69. let default_hashtbl_size = 3000
  70.  
  71. let rec reconstruct_path hashtbl node path =
  72.   if CoordTable.mem hashtbl node  then
  73.     node :: (reconstruct_path hashtbl (CoordTable.find hashtbl node) path)
  74.   else
  75.     node :: path          
  76.  
  77. let find_path maze start goal heuristic =
  78.   let closedset = ref [] and openset = ref [start] and camefrom = CoordTable.create default_hashtbl_size in
  79.   let gscore = CoordTable.create default_hashtbl_size and fscore = CoordTable.create default_hashtbl_size in
  80.   let () = CoordTable.add gscore start 0; CoordTable.add fscore start (heuristic start goal) in
  81.   let compare_fscore a b =
  82.     let score_a = CoordTable.find fscore a in
  83.     let score_b = CoordTable.find fscore b in
  84.     score_a - score_b
  85.   in
  86.   let rec loop () =
  87.     if !openset = [] then raise No_path_found
  88.     else
  89.       let current = List.hd !openset in
  90.       if current = goal then List.rev (reconstruct_path camefrom goal [])
  91.       else begin
  92.         openset := List.tl !openset;
  93.         closedset := current :: !closedset;
  94.        
  95.         let neighbors = neighbor_nodes maze current in
  96.         for i = 0 to (List.length neighbors) - 1 do
  97.           let neighbor = List.nth neighbors i in    
  98.           if is_passable maze neighbor && not (List.mem neighbor !closedset) then
  99.             let tentative_gscore = (CoordTable.find gscore current) + 1 in
  100.             let is_better =
  101.               if not (List.mem neighbor !openset) then (openset := neighbor :: !openset; true)
  102.               else tentative_gscore < CoordTable.find gscore neighbor
  103.             in if is_better then begin
  104.               CoordTable.add camefrom neighbor current;
  105.               CoordTable.add gscore neighbor tentative_gscore;
  106.               CoordTable.add fscore neighbor (tentative_gscore + (heuristic neighbor goal))              
  107.             end
  108.         done;
  109.         openset := List.sort (compare_fscore) !openset;
  110.         loop ()
  111.       end
  112.   in loop ()
  113.  
  114. let () =
  115.   let maze = read_maze "maze.txt" in
  116.   let path =
  117.     for i = 0 to 1000 do
  118.       ignore (find_path maze (0, 0) (78, 29) distance)
  119.     done;    
  120.     find_path maze (0, 0) (78, 29) distance
  121.   in
  122.   let walk coords = maze_set maze coords '.' in
  123.   List.iter walk path;
  124.   draw maze;
  125.   Printf.printf "%d steps\n" (List.length path)
Advertisement
Add Comment
Please, Sign In to add comment