Solutions to mamunds maze problem

'
+

Python

The code is here.

You will need the httplib2 module.

Just run python maze.py http://amundsen.com/examples/mazes/2d/five-by-five/.

Im currently in a functional mood

')

')
Maze en Python (maze.py)
    1 #!/bin/env python
    2 # Python solution to mamund's maze problem (functional style)
    3 # see http://amundsen.com/examples/misc/maze-client.html
    4 
    5 from xml.etree.ElementTree import XML
    6 from httplib2 import Http
    7 
    8 MAZE = "http://amundsen.com/examples/mazes/2d/five-by-five/"
    9 RULES = {
   10     'east'  : ['south','east','north','west'],
   11     'south' : ['west','south','east','north'],
   12     'west'  : ['north','west','south','east'],
   13     'north' : ['east','north','west','south']
   14 }
   15 
   16 def get(uri):
   17     """ return the XML from the given uri """
   18     resp, content = Http().request(
   19                       uri,
   20                       headers={
   21                         'Accept':
   22                           "application/vnd.amundsen.maze+xml"})
   23     return XML(content)
   24 
   25 def get_links(uri):
   26     """ 
   27     return a dict {rel: href} of the <link>s found at the given uri
   28     """
   29     return dict(
   30          (link.get('rel'), link.get('href')) 
   31          for link in get(uri).findall('*/link')
   32         )
   33 
   34 def selector(rules):
   35     """
   36     a little closure to create the next-link selector based on the 
   37     given rules
   38     """
   39     def select(facing, links):
   40         """
   41         app logic:
   42         given the current facing direction and the available links,
   43         chooses the next direction (according to the rules),
   44         follows the link and return the new facing direction and the 
   45         available links for the current state
   46         """
   47         if facing is None and 'start' in links:
   48             return ('north', get_links(links['start']))
   49         if 'exit' in links:
   50             return ('exit', get_links(links['exit']))
   51         for choice in rules[facing]:
   52             if choice in links:
   53                 return (choice, get_links(links[choice]))
   54     return select
   55 
   56 def find_path(maze, rules):
   57     """ 
   58     just follow the links until exit, yielding the current state 
   59     """
   60     select_next = selector(rules)
   61     facing, links = None, get_links(maze)
   62     while facing is not 'exit':
   63         facing, links = select_next(facing, links)
   64         yield (facing, links)
   65 
   66 if __name__ == '__main__':
   67     import sys
   68     if len(sys.argv) == 2:
   69         maze = sys.argv[1]
   70     else:
   71         maze = MAZE
   72     for step, (facing, links) in enumerate(find_path(maze, RULES)):
   73         print "%s: go to %s"  % (step, facing)
   74         print "    <%s>" % (links.get('current', ''),)
   75     print "I'm free !"
   76 
+

Bash

(and grep, sed, curl...)

The code is here.

Just run ./maze.sh http://amundsen.com/examples/mazes/2d/five-by-five/. Details are printed on stderr, urls only on stdout.

Maze en Bash (maze.sh)
    1 #!/bin/bash
    2 # Bash solution to mamund's maze problem \o/
    3 # see http://amundsen.com/examples/misc/maze-client.html
    4 
    5 MAZE=http://amundsen.com/examples/mazes/2d/five-by-five/
    6 
    7 #---------------------------------------------------------------------
    8 function message {
    9     echo "# $1" >&2
   10 }
   11 function output {
   12     echo $1
   13 }
   14 
   15 # -- Orientation rules -----------------------------------------------
   16 function east {
   17     sed '
   18     s!^south!2 south!;
   19     s!^east!3 east!;
   20     s!^north!4 north!;
   21     s!^west!5 west!;'
   22 }
   23 function south {
   24     sed '
   25     s!^west!2 west!;
   26     s!^south!3 south!; 
   27     s!^east!4 east!; 
   28     s!^north!5 north!;'
   29 }
   30 function west {
   31     sed '
   32     s!^north!2 north!;
   33     s!^west!3 west!;
   34     s!^south!4 south!;
   35     s!^east!5 east!;'
   36 }
   37 function north {
   38     sed '
   39     s!^east!2 east!;
   40     s!^north!3 north!;
   41     s!^west!4 west!;
   42     s!^south!5 south!;'
   43 }
   44 function start_exit {
   45     sed '
   46     s!^exit!0 exit!;
   47     s!^start!1 north!;
   48     '
   49 }
   50 #---------------------------------------------------------------------
   51 
   52 #---------------------------------------------------------------------
   53 function get {
   54     # return the maze+xml from the given uri
   55     local uri="${1:?}"
   56     curl -sL --compressed \
   57         -H 'Accept: application/vnd.amundsen.maze+xml' \
   58         "$uri" |
   59         tr '\n' ' ' | tr -s ' '
   60 }
   61 
   62 
   63 #---------------------------------------------------------------------
   64 function get_links {
   65     # return rel href for the given uri
   66     local uri="${1:?}"
   67     get "$uri" | grep -o '<link [^>]*/>' | tr "'" '"' |
   68     grep -v 'rel="current"' |
   69     while read line ; do
   70         echo $(get_rel "$line") $(get_href "$line")
   71     done
   72 }
   73 function get_href {
   74      echo "$1" | sed 's!.*href="\([^"]*\)".*!\1!'
   75 }
   76 function get_rel {
   77      echo "$1" | sed 's!.*rel="\([^"]*\)".*!\1!'
   78 }
   79 
   80 #---------------------------------------------------------------------
   81 function select_next {
   82     # select the next direction
   83     local facing="${1:?}"
   84     local uri="${2:?}"
   85     get_links "$uri" | start_exit | $facing | sort -n | head -n 1
   86 }
   87 
   88 #---------------------------------------------------------------------
   89 function find_path {
   90     # bring me to exit !
   91     local uri="${1:?}"
   92     local facing="${2:?}"
   93     local next=""
   94     local count=0
   95     while [ "$facing" != "exit" ] ; do
   96         message "$count: I'm at <$uri>"
   97         next="$(select_next "$facing" "$uri")"
   98         facing=$(echo $next | cut -d ' ' -f 2)
   99         uri=$(echo $next | cut -d ' ' -f 3)
  100         message "$count: going to <$uri>, facing $facing"
  101         output $uri
  102         count=$((count+1))
  103     done
  104     message "I'm free!"
  105 
  106 }
  107 
  108 
  109 find_path "${1:-$MAZE}" "${2:-cat}"
  110 
+

OCaml

The code is here.

You will need the OCamlNet module.

Just run ocaml maze.ml http://amundsen.com/examples/mazes/2d/five-by-five/. You can also compile it.

Since I’m only a Caml beginner, I tried to use some aspects as an exercise, so it may be not the best approach…

Maze en Caml (maze.ml)
    1 #!/bin/env ocaml
    2 
    3 (*
    4  * OCaml solution to mamund's maze problem (functional style)
    5  * see http://amundsen.com/examples/misc/maze-client.html
    6  *)
    7 
    8 #use "topfind";;
    9 
   10 (* OcamlNet for the HTTP client:
   11  * http://projects.camlcity.org/projects/ocamlnet.html *)
   12 #require "netclient" ;;
   13 #require "str";;
   14 open Str
   15 open Http_client.Convenience
   16 
   17 
   18 type direction =
   19     | Start of string
   20     | East of string
   21     | West of string
   22     | North of string
   23     | South of string
   24     | Exit of string
   25     | Current of string
   26     | Unknown of string * string
   27 
   28 
   29 let parse_direction = function
   30     | ("start", href) -> Start(href)
   31     | ("east", href) -> East(href)
   32     | ("west", href) -> West(href)
   33     | ("north", href) -> North(href)
   34     | ("south", href) -> South(href)
   35     | ("exit", href) -> Exit(href)
   36     | ("current", href) -> Current(href)
   37     | (rel, href) -> Unknown(rel,href)
   38 
   39 
   40 let format_direction = function
   41     | Start(href) -> "Start: <" ^ href ^ ">"
   42     | East(href) -> "East: <" ^ href ^ ">"
   43     | West(href) -> "West: <" ^ href ^ ">"
   44     | North(href) -> "North: <" ^ href ^ ">"
   45     | South(href) -> "South: <" ^ href ^ ">"
   46     | Exit(href) -> "Exit: <" ^ href ^ ">"
   47     | Current(href) -> ""
   48     | Unknown(rel,href) -> rel ^ ": <" ^ href ^ ">"
   49 
   50 
   51 
   52 (* Parse the "Link" header with some regexp *)
   53 let parse_link_header url =
   54     let extract_link l =
   55         let re = Str.regexp "<\\([^>]+\\)>; +rel=\"\\([^\"]+\\)\"" in
   56         let m = Str.string_match re l 0 in
   57         if m then parse_direction((Str.matched_group 2 l),
   58                                   (Str.matched_group 1 l))
   59         else Unknown("","")
   60     and call = http_head_message url in
   61     List.map extract_link (Str.split (Str.regexp ",") (call#response_header#field "Link")) 
   62 
   63 exception Lost
   64 exception Out
   65 let select_next_direction facing =
   66     let choose_direction f uri =
   67         let _choose (rank1, dir1) (rank2, dir2) = compare rank1 rank2
   68         and _mapper f dir = (f(dir),dir) in
   69         snd (List.hd (List.sort _choose 
   70                                 (List.map (_mapper f) 
   71                                           (parse_link_header uri))))
   72     in
   73     match facing with
   74     | East(uri) -> (choose_direction (function
   75                         | Exit(_)  -> 0
   76                         | South(_) -> 1
   77                         | East(_)  -> 2
   78                         | North(_) -> 3
   79                         | West(_)  -> 4
   80                         | _ -> 5) uri)
   81     | South(uri) -> (choose_direction (function
   82                         | Exit(_)  -> 0
   83                         | West(_)  -> 1
   84                         | South(_) -> 2
   85                         | East(_)  -> 3
   86                         | North(_) -> 4
   87                         | _ -> 5) uri)
   88     | West(uri) -> (choose_direction (function
   89                         | Exit(_)  -> 0
   90                         | North(_) -> 1
   91                         | West(_)  -> 2
   92                         | South(_) -> 3
   93                         | East(_)  -> 4
   94                         | _ -> 5) uri)
   95     | North(uri) -> (choose_direction (function
   96                         | Exit(_)  -> 0
   97                         | East(_)  -> 1
   98                         | North(_) -> 2
   99                         | West(_)  -> 3
  100                         | South(_) -> 4
  101                         | _ -> 5) uri)
  102     | Exit(uri) -> raise Out
  103     | Start(uri) -> North(uri)
  104     | _ -> raise Lost
  105 
  106 
  107 
  108 open Printf
  109 let () =
  110     let start_uri = if (Array.length Sys.argv) > 1 
  111                     then Sys.argv.(1) 
  112                     else "http://amundsen.com/examples/mazes/2d/five-by-five/"
  113     in
  114     let s = ref (North start_uri)
  115     and i = ref 0 in 
  116     try while true do
  117         printf "%d: %s\n" !i (format_direction !s) ;
  118         flush stdout ;
  119         s := select_next_direction !s ;
  120         i := !i +1 ;
  121         done
  122     with Out -> printf "I'm free!!\n" ;