Listing 4. Full Maze Program

import planner.

action(State, NewState, Action, Cost) ?=>
  (R, C, (ExitI, ExitJ), Walls, Doors, Keys,
    K, (HeroI, HeroJ)) = State,
    select((HeroI, HeroJ), Keys, NewKeys),
    Action = $take_key(HeroI, HeroJ),
    Cost = 1,
    NewState = (R, C, (ExitI, ExitJ),
                Walls, Doors, NewKeys,
                K + 1, (HeroI, HeroJ)).

action(State, NewState, Action, Cost) =>
  (R, C, (ExitI, ExitJ), Walls, Doors, Keys,
    K, (HeroI, HeroJ)) = State,
  (
    Di = 0, Dj = 1
  ;
    Di = 0, Dj = -1
  ;
    Di = 1, Dj = 0
  ;
    Di = -1, Dj = 0
  ),

  NewHeroI = HeroI + Di,
  NewHeroJ = HeroJ + Dj,
  NewHeroI >= 1, NewHeroI <= R,
  NewHeroJ >= 1, NewHeroJ <= C,

  (
    % move to open cell
    not membchk((NewHeroI, NewHeroJ), Walls),
    not membchk((NewHeroI, NewHeroJ), Doors),
    Action = $move(NewHeroI, NewHeroJ),
    Cost = 1,
    NewState = (R, C, (ExitI, ExitJ),
                Walls, Doors, Keys,
                K, (NewHeroI, NewHeroJ))
  ;
    % open a door and move to that cell
    K > 0,
    select((NewHeroI, NewHeroJ), Doors, NewDoors),
    Action = $open(NewHeroI, NewHeroJ),
    Cost = 2,
    NewState = (R, C, (ExitI, ExitJ),
                Walls, NewDoors, Keys,
                K - 1, (NewHeroI, NewHeroJ))
  ).

final((_, _, (I, J), _, _, _, _, (I, J))) =>
  true.

main =>
  R = read_int(), C = read_int(),
  Walls = [], Doors = [], Keys = [],
  (ExitI, ExitJ) = (_, _),
  (HeroI, HeroJ) = (_, _),
  foreach (I in 1..R)
    Line = read_line(),
    foreach (J in 1..C)
      Char = Line[J],
      if Char == '@' then
        HeroI := I, HeroJ := J
      end,
      if Char == 'X' then
        ExitI := I, ExitJ := J
      end,
      if Char == '#' then
        Walls := [(I, J) | Walls]
      end,
      if Char == '|' then
        Doors := [(I, J) | Doors]
      end,
      if Char == '=' then
        Keys := [(I, J) | Keys]
      end
    end
  end,
  InitState = (R, C, (ExitI, ExitJ),
               Walls, Doors, Keys,
               0, (HeroI, HeroJ)),
  best_plan_unbounded(InitState, Plan),
  println(Plan).
