import std.string, std.typecons, std.exception, std.algorithm;
import queue_usage2; // No queue in Phobos 2.064.

const struct Board {
    private enum El { floor = ' ', wall = '#', goal = '.',
                      box = '$', player = '@', boxOnGoal='*' }
    private alias CTable = string;
    private immutable size_t ncols;
    private immutable CTable sData, dData;
    private immutable int playerx, playery;

    this(in string[] board) immutable pure nothrow @safe
    in {
        foreach (const row; board) {
            assert(row.length == board[0].length,
                   "Unequal board rows.");
            foreach (immutable c; row)
                assert(c.inPattern(" #[email protected]*"), "Not valid input");
        }
    } body {
        /*static*/ immutable sMap =
            [' ':' ', '.':'.', '@':' ', '#':'#', '$':' '];
        /*static*/ immutable dMap =
            [' ':' ', '.':' ', '@':'@', '#':' ', '$':'*'];
        ncols = board[0].length;

        int plx = 0, ply = 0;
        CTable sDataBuild, dDataBuild;

        foreach (immutable r, const row; board)
            foreach (immutable c, const ch; row) {
                sDataBuild ~= sMap[ch];
                dDataBuild ~= dMap[ch];
                if (ch == El.player) {
                    plx = c;
                    ply = r;
                }
            }

        this.sData = sDataBuild;
        this.dData = dDataBuild;
        this.playerx = plx;
        this.playery = ply;
    }

    private bool move(in int x, in int y, in int dx,
                      in int dy, ref CTable data)
    const pure nothrow /*@safe*/ {
        if (sData[(y + dy) * ncols + x + dx] == El.wall ||
            data[(y + dy) * ncols + x + dx] != El.floor)
            return false;

        auto data2 = data.dup;
        data2[y * ncols + x] = El.floor;
        data2[(y + dy) * ncols + x + dx] = El.player;
        data = data2.assumeUnique; // Not enforced.
        return true;
    }

    private bool push(in int x, in int y, in int dx,
                      in int dy, ref CTable data)
    const pure nothrow /*@safe*/ {
        if (sData[(y + 2 * dy) * ncols + x + 2 * dx] == El.wall ||
            data[(y + 2 * dy) * ncols + x + 2 * dx] != El.floor)
            return false;

        auto data2 = data.dup;
        data2[y * ncols + x] = El.floor;
        data2[(y + dy) * ncols + x + dx] = El.player;
        data2[(y + 2 * dy) * ncols + x + 2*dx] = El.boxOnGoal;
        data = data2.assumeUnique; // Not enforced.
        return true;
    }

    private bool isSolved(in CTable data)
    const pure nothrow @safe @nogc {
        foreach (immutable i, immutable d; data)
            if ((sData[i] == El.goal) != (d == El.boxOnGoal))
                return false;
        return true;
    }

    string solve() pure nothrow /*@safe*/ {
        bool[immutable CTable] visitedSet = [dData: true];

        alias Four = Tuple!(CTable, string, int, int);
        GrowableCircularQueue!Four open;
        open.push(Four(dData, "", playerx, playery));

        static immutable dirs = [tuple( 0, -1, 'u', 'U'),
                                 tuple( 1,  0, 'r', 'R'),
                                 tuple( 0,  1, 'd', 'D'),
                                 tuple(-1,  0, 'l', 'L')];

        while (!open.empty) {
            //immutable (cur, cSol, x, y) = open.pop;
            immutable item = open.pop;
            immutable cur = item[0];
            immutable cSol = item[1];
            immutable x = item[2];
            immutable y = item[3];

            foreach (immutable di; dirs) {
                CTable temp = cur;
                //immutable (dx, dy) = di[0 .. 2];
                immutable dx = di[0];
                immutable dy = di[1];

                if (temp[(y + dy) * ncols + x + dx] == El.boxOnGoal) {
                    if (push(x, y, dx, dy, temp) && temp !in visitedSet) {
                        if (isSolved(temp))
                            return cSol ~ di[3];
                        open.push(Four(temp, cSol ~ di[3], x + dx, y + dy));
                        visitedSet[temp] = true;
                    }
                } else if (move(x, y, dx, dy, temp) && temp !in visitedSet) {
                    if (isSolved(temp))
                        return cSol ~ di[2];
                    open.push(Four(temp, cSol ~ di[2], x + dx, y + dy));
                    visitedSet[temp] = true;
                }
            }
        }

        return "No solution";
    }
}

void main() {
    import std.stdio, core.memory;
    GC.disable; // Uses about twice the memory.

    immutable level =
"#######
#     #
#     #
#. #  #
#. $$ #
#.$$  #
#.#  @#
#######";

    immutable b = immutable(Board)(level.splitLines);
    writeln(level, "\n\n", b.solve);
}


defmodule Sokoban do
  defp setup(level) do
    {leng, board} = normalize(level)
    {player, goal} = check_position(board)
    board = replace(board, [{".", " "}, {"+", " "}, {"*", "$"}])
    lurd = [{-1, "l", "L"}, {-leng, "u", "U"}, {1, "r", "R"}, {leng, "d", "D"}]
    dirs = [-1, -leng, 1, leng]
    dead_zone = set_dead_zone(board, goal, dirs)
    {board, player, goal, lurd, dead_zone}
  end

  defp normalize(level) do
    board = String.split(level, "\n", trim: true)
            |> Enum.map(&String.trim_trailing &1)
    leng  = Enum.map(board, &String.length &1) |> Enum.max
    board = Enum.map(board, &String.pad_trailing(&1, leng)) |> Enum.join
    {leng, board}
  end

  defp check_position(board) do
    board = String.codepoints(board)
    player = Enum.find_index(board, fn c -> c in ["@", "+"] end)
    goal = Enum.with_index(board)
           |> Enum.filter_map(fn {c,_} -> c in [".", "+", "*"] end, fn {_,i} -> i end)
    {player, goal}
  end

  defp set_dead_zone(board, goal, dirs) do
    wall = String.replace(board, ~r/[^#]/, " ")
           |> String.codepoints
           |> Enum.with_index
           |> Enum.into(Map.new, fn {c,i} -> {i,c} end)
    corner = search_corner(wall, goal, dirs)
    set_dead_zone(wall, dirs, goal, corner, corner)
  end

  defp set_dead_zone(wall, dirs, goal, corner, dead) do
    dead2 = Enum.reduce(corner, dead, fn pos,acc ->
              Enum.reduce(dirs, acc, fn dir,acc2 ->
                if wall[pos+dir] == "#", do: acc2,
                    else: acc2 ++ check_side(wall, dirs, pos+dir, dir, goal, dead, [])
              end)
            end)
    if dead == dead2, do: :lists.usort(dead),
                    else: set_dead_zone(wall, dirs, goal, corner, dead2)
  end

  defp replace(string, replacement) do
    Enum.reduce(replacement, string, fn {a,b},str ->
      String.replace(str, a, b)
    end)
  end

  defp search_corner(wall, goal, dirs) do
    Enum.reduce(wall, [], fn {i,c},corner ->
      if c == "#" or i in goal do
        corner
      else
        case count_wall(wall, i, dirs) do
          2 -> if wall[i-1] != wall[i+1], do: [i | corner], else: corner
          3 -> [i | corner]
          _ -> corner
        end
      end
    end)
  end

  defp check_side(wall, dirs, pos, dir, goal, dead, acc) do
    if wall[pos] == "#" or
      count_wall(wall, pos, dirs) == 0 or
      pos in goal do
      []
    else
      if pos in dead, do: acc, else: check_side(wall, dirs, pos+dir, dir, goal, dead, [pos|acc])
    end
  end

  defp count_wall(wall, pos, dirs) do
    Enum.count(dirs, fn dir -> wall[pos + dir] == "#" end)
  end

  defp push_box(board, pos, dir, route, goal, dead_zone) do
    pos2dir = pos + 2 * dir
    if String.at(board, pos2dir) == " " and not pos2dir in dead_zone do
      board2 = board |> replace_at(pos,     " ")
                     |> replace_at(pos+dir, "@")
                     |> replace_at(pos2dir, "$")
      unless visited?(board2) do
        if solved?(board2, goal) do
          IO.puts route
          exit(:normal)
        else
          queue_in({board2, pos+dir, route})
        end
      end
    end
  end

  defp move_player(board, pos, dir) do
    board |> replace_at(pos, " ") |> replace_at(pos+dir, "@")
  end

  defp replace_at(str, pos, c) do
    {left, right} = String.split_at(str, pos)
    {_, right} = String.split_at(right, 1)
    left <> c <> right
    # String.slice(str, 0, pos) <> c <> String.slice(str, pos+1..-1)
  end

  defp solved?(board, goal) do
    Enum.all?(goal, fn g -> String.at(board, g) == "$" end)
  end

  @pattern :sokoban_pattern_set
  @queue   :sokoban_queue

  defp start_link do
    Agent.start_link(fn -> MapSet.new end, name: @pattern)
    Agent.start_link(fn -> :queue.new end, name: @queue)
  end

  defp visited?(board) do
    Agent.get_and_update(@pattern, fn set ->
      {board in set, MapSet.put(set, board)}
    end)
  end

  defp queue_in(data) do
    Agent.update(@queue, fn queue -> :queue.in(data, queue) end)
  end

  defp queue_out do
    Agent.get_and_update(@queue, fn q ->
      case :queue.out(q) do
        {{:value, data}, queue} -> {data, queue}
        x -> x
      end
    end)
  end

  def solve(level) do
    {board, player, goal, lurd, dead_zone} = setup(level)
    start_link
    visited?(board)
    queue_in({board, player, ""})
    solve(goal, lurd, dead_zone)
  end

  defp solve(goal, lurd, dead_zone) do
    case queue_out do
      {board, pos, route} ->
        Enum.each(lurd, fn {dir,move,push} ->
          case String.at(board, pos+dir) do
            "$" -> push_box(board, pos, dir, route<>push, goal, dead_zone)
            " " -> board2 = move_player(board, pos, dir)
                   unless visited?(board2) do
                     queue_in({board2, pos+dir, route<>move})
                   end
            _ -> :not_move    # wall
          end
        end)
      _ ->
        IO.puts "No solution"
        exit(:normal)
    end
    solve(goal, lurd, dead_zone)
  end
end

level = """
#######
#     #
#     #
#. #  #
#. $$ #
#.$$  #
#.#  @#
#######
"""
IO.puts level
Sokoban.solve(level)


package main

import (
    "fmt"
    "strings"
)

func main() {
    level := `
#######
#     #
#     #
#. #  #
#. $$ #
#.$$  #
#.#  @#
#######`
    fmt.Printf("level:%s\n", level)
    fmt.Printf("solution:\n%s\n", solve(level))
}

func solve(board string) string {
    buffer = make([]byte, len(board))
    width := strings.Index(board[1:], "\n") + 1
    dirs := []struct {
        move, push string
        dPos       int
    }{
        {"u", "U", -width},
        {"r", "R", 1},
        {"d", "D", width},
        {"l", "L", -1},
    }
    visited := map[string]bool{board: true}
    open := []state{state{board, "", strings.Index(board, "@")}}
    for len(open) > 0 {
        s1 := &open[0]
        open = open[1:]
        for _, dir := range dirs {
            var newBoard, newSol string
            newPos := s1.pos + dir.dPos
            switch s1.board[newPos] {
            case '$', '*':
                newBoard = s1.push(dir.dPos)
                if newBoard == "" || visited[newBoard] {
                    continue
                }
                newSol = s1.cSol + dir.push
                if strings.IndexAny(newBoard, ".+") < 0 {
                    return newSol
                }
            case ' ', '.':
                newBoard = s1.move(dir.dPos)
                if visited[newBoard] {
                    continue
                }
                newSol = s1.cSol + dir.move
            default:
                continue
            }
            open = append(open, state{newBoard, newSol, newPos})
            visited[newBoard] = true
        }
    }
    return "No solution"
}

type state struct {
    board string
    cSol  string
    pos   int
}

var buffer []byte

func (s *state) move(dPos int) string {
    copy(buffer, s.board)
    if buffer[s.pos] == '@' {
        buffer[s.pos] = ' '
    } else {
        buffer[s.pos] = '.'
    }
    newPos := s.pos + dPos
    if buffer[newPos] == ' ' {
        buffer[newPos] = '@'
    } else {
        buffer[newPos] = '+'
    }
    return string(buffer)
}

func (s *state) push(dPos int) string {
    newPos := s.pos + dPos
    boxPos := newPos + dPos
    switch s.board[boxPos] {
    case ' ', '.':
    default:
        return ""
    }
    copy(buffer, s.board)
    if buffer[s.pos] == '@' {
        buffer[s.pos] = ' '
    } else {
        buffer[s.pos] = '.'
    }
    if buffer[newPos] == '$' {
        buffer[newPos] = '@'
    } else {
        buffer[newPos] = '+'
    }
    if buffer[boxPos] == ' ' {
        buffer[boxPos] = '$'
    } else {
        buffer[boxPos] = '*'
    }
    return string(buffer)
}


V moves = [
    [-1, -2], [1, -2], [-1, 2], [1, 2],
    [-2, -1], [-2, 1], [2, -1], [2, 1]
]

F solve(&pz, sz, sx, sy, idx, cnt)
   I idx > cnt
      R 1

   L(i) 0 .< :moves.len
      V x = sx + :moves[i][0]
      V y = sy + :moves[i][1]
      I sz > x & x > -1 & sz > y & y > -1 & pz[x][y] == 0
         pz[x][y] = idx
         I 1 == solve(&pz, sz, x, y, idx + 1, cnt)
            R 1
         pz[x][y] = 0
   R 0

F find_solution(pz, sz)
   V p = [[-1] * sz] * sz
   V idx = 0
   V x = 0
   V y = 0
   V cnt = 0
   L(j) 0 .< sz
      L(i) 0 .< sz
         I pz[idx] == ‘x’
            p[i][j] = 0
            cnt++
         E I pz[idx] == ‘s’
            p[i][j] = 1
            cnt++
            x = i
            y = j
         idx++

   I 1 == solve(&p, sz, x, y, 2, cnt)
      L(j) 0 .< sz
         L(i) 0 .< sz
            I p[i][j] != -1
               print(‘ #02’.format(p[i][j]), end' ‘’)
            E
               print(‘   ’, end' ‘’)
         print()
   E
      print(‘Cannot solve this puzzle!’)

find_solution(‘.xxx.....x.xx....xxxxxxxxxx..x.xx.x..xxxsxxxxxx...xx.x.....xxx..’, 8)
print()
find_solution(‘.....s.x..........x.x.........xxxxx.........xxx.......x..x.x..x..xxxxx...xxxxx..xx.....xx..xxxxx...xxxxx..x..x.x..x.......xxx.........xxxxx.........x.x..........x.x.....’, 13)


import Control.Monad (liftM)
import Data.Array
import Data.List (transpose)
import Data.Maybe (mapMaybe)
import qualified Data.Sequence as Seq
import qualified Data.Set as Set
import Prelude hiding (Left, Right)

data Field = Space | Wall | Goal
           deriving (Eq)

data Action = Up | Down | Left | Right | PushUp | PushDown | PushLeft | PushRight

instance Show Action where
  show Up        = "u"
  show Down      = "d"
  show Left      = "l"
  show Right     = "r"
  show PushUp    = "U"
  show PushDown  = "D"
  show PushLeft  = "L"
  show PushRight = "R"

type Index = (Int, Int)
type FieldArray = Array Index Field
type BoxArray = Array Index Bool
type PlayerPos = Index
type GameState = (BoxArray, PlayerPos)
type Game = (FieldArray, GameState)

toField :: Char -> Field
toField '#' = Wall
toField ' ' = Space
toField '@' = Space
toField '$' = Space
toField '.' = Goal
toField '+' = Goal
toField '*' = Goal

toPush :: Action -> Action
toPush Up    = PushUp
toPush Down  = PushDown
toPush Left  = PushLeft
toPush Right = PushRight
toPush n     = n

toMove :: Action -> Index
toMove PushUp    = ( 0, -1)
toMove PushDown  = ( 0,  1)
toMove PushLeft  = (-1,  0)
toMove PushRight = ( 1,  0)
toMove n = toMove $ toPush n

-- Parse the string-based game board into an easier-to-use format.
-- Assume that the board is valid (rectangular, one player, etc).
parseGame :: [String] -> Game
parseGame fieldStrs = (field, (boxes, player))
  where
    width     = length $ head fieldStrs
    height    = length fieldStrs
    bound     = ((0, 0), (width - 1, height - 1))
    flatField = concat $ transpose fieldStrs
    charField = listArray bound flatField
    field     = fmap toField charField
    boxes     = fmap (`elem` "$*") charField
    player    = fst $ head $ filter (flip elem "@+" . snd) $ assocs charField

add :: (Num a, Num b) => (a, b) -> (a, b) -> (a, b)
add (a, b) (x, y) = (a + x, b + y)

-- Attempt to perform an action, returning the updated game and adjusted
-- action if the action was legal.
tryAction :: Game -> Action -> Maybe (Game, Action)
tryAction (field, (boxes, player)) action
  | field ! vec == Wall = Nothing
  | boxes ! vec =
     if boxes ! vecB || field ! vecB == Wall
     then Nothing
     else Just ((field, (boxes // [(vec, False), (vecB, True)], vec)),
               toPush action)
  | otherwise = Just ((field, (boxes, vec)), action)
  where
    actionVec = toMove action
    vec       = player `add` actionVec
    vecB      = vec `add` actionVec

-- Search the game for a solution.
solveGame :: Game -> Maybe [Action]
solveGame (field, initState) =
  liftM reverse $ bfs (Seq.singleton (initState, [])) (Set.singleton initState)
  where
    goals           = map fst $ filter ((== Goal) . snd) $ assocs field
    isSolved st     = all (st !) goals
    possibleActions = [Up, Down, Left, Right]

    -- Breadth First Search of the game tree.
    bfs :: Seq.Seq (GameState, [Action]) -> Set.Set GameState -> Maybe [Action]
    bfs queue visited =
      case Seq.viewl queue of
        Seq.EmptyL -> Nothing
        (game@(boxes, _), actions) Seq.:< queueB ->
          if isSolved boxes
          then Just actions
          else
            let newMoves = filter (flip Set.notMember visited . fst) $
                           map (\((_, g), a) -> (g, a)) $
                           mapMaybe (tryAction (field, game)) possibleActions
                visitedB = foldl (flip Set.insert) visited $
                           map fst newMoves
                queueC   = foldl (Seq.|>) queueB $
                           map (\(g, a) -> (g, a:actions)) newMoves
            in bfs queueC visitedB

exampleA :: [String]
exampleA =
  ["#######"
  ,"#     #"
  ,"#     #"
  ,"#. #  #"
  ,"#. $$ #"
  ,"#.$$  #"
  ,"#.#  @#"
  ,"#######"]

main :: IO ()
main =
  case solveGame $ parseGame exampleA of
    Nothing       -> putStrLn "Unsolvable"
    Just solution -> do
      mapM_ putStrLn exampleA
      putStrLn ""
      putStrLn $ concatMap show solution


with Knights_Tour, Ada.Text_IO, Ada.Command_Line;

procedure Holy_Knight is

   Size: Positive := Positive'Value(Ada.Command_Line.Argument(1));
   package KT is new Knights_Tour(Size => Size);
   Board: KT.Tour := (others => (others => Natural'Last));

   Start_X, Start_Y: KT.Index:= 1; -- default start place (1,1)
   S: String(KT.Index);
   I: Positive := KT.Index'First;
begin
   -- read the board from standard input
   while not Ada.Text_IO.End_Of_File and I <= Size loop
      S := Ada.Text_IO.Get_Line;
      for J in KT.Index loop
         if S(J) = ' ' or S(J) = '-' then
            Board(I,J) := Natural'Last;
         elsif S(J) = '1' then
              Start_X := I; Start_Y := J;  Board(I,J) := 1;
         else Board(I,J) := 0;
         end if;
      end loop;
      I := I + 1;
   end loop;

   -- print the board
   Ada.Text_IO.Put_Line("Start Configuration (Length:"
                          & Natural'Image(KT.Count_Moves(Board)) & "):");
   KT.Tour_IO(Board, Width => 1);
   Ada.Text_IO.New_Line;

   -- search for the tour and print it
   Ada.Text_IO.Put_Line("Tour:");
   KT.Tour_IO(KT.Warnsdorff_Get_Tour(Start_X, Start_Y, Board));
end Holy_Knight;


# directions for moves #
INT nne = 1, ne  = 2, se = 3, sse = 4;
INT ssw = 5, sw  = 6, nw = 7, nnw = 8;

INT lowest move  = nne;
INT highest move = nnw;

# the vertical position changes of the moves                             #
[]INT offset v = ( -2, -1,  1,  2,  2,  1, -1, -2 );
# the horizontal position changes of the moves                           #
[]INT offset h = (  1,  2,  2,  1, -1, -2, -2, -1 );

MODE SQUARE = STRUCT( INT move      # the number of the move that caused #
                                    # the knight to reach this square    #
                    , INT direction # the direction of the move that     #
                                    # brought the knight here - one of   #
                                    # nne, ne, se, sse, ssw, sw, nw or   #
                                    # nnw                                #
                    );
# get the size of the board - must be between 4 and 8                    #
INT board size = 8;
# the board #
[ board size, board size ]SQUARE board;
# starting position #
INT start row := 1;
INT start col := 1;
# the tour will be complete when we have made as many moves              #
# as there are free squares in the initial board                         #
INT  final move    := 0;

# initialise the board setting the free squares from the supplied pttern #
# the pattern has the rows in revers order                               #
PROC initialise board = ( []STRING pattern )VOID:
     BEGIN
        INT pattern row := UPB board;
        FOR row FROM 1 LWB board TO 1 UPB board
        DO
            FOR col FROM 2 LWB board TO 2 UPB board
            DO
                IF pattern[ pattern row ][ col ] = "-"
                THEN
                    # can't use this square                              #
                    board[ row, col ] := ( -1, -1 )
                ELSE
                    # available square                                   #
                    board[ row, col ] := ( 0, 0 );
                    final move +:= 1;
                    IF pattern[ pattern row ][ col ] = "1"
                    THEN
                        # have the start position                        #
                        start row := row;
                        start col := col
                    FI
                FI
            OD;
            pattern row -:= 1
        OD
     END; # initialise board #
# statistics #
INT iterations := 0;
INT backtracks := 0;

# prints the board #
PROC print tour = VOID:
BEGIN
    # format "number" into at least two characters #
    PROC n2 = ( INT number )STRING:
        IF   number < 0
        THEN
            " -"
        ELIF number < 10 AND number >= 0
        THEN
            " " + whole( number, 0 )
        ELSE
            whole( number, 0 )
        FI; # n2 #
    print( ( "     a  b  c  d  e  f  g  h", newline ) );
    print( ( "   ________________________", newline ) );
    FOR row FROM 1 UPB board BY -1 TO 1 LWB board
    DO
        print( ( n2( row ) ) );
        print( ( "|" ) );

        FOR col FROM 2 LWB board TO 2 UPB board
        DO
            print( ( " " ) );
            print( ( n2( move OF board[ row, col ] ) ) )
        OD;
        print( ( newline ) )
    OD
END; # print tour #

# update the board to the first knight's tour found starting from       #
# "start row" and "start col".                                          #
# return TRUE if one was found, FALSE otherwise                         #
PROC find tour = BOOL:
BEGIN

    BOOL result       := TRUE;
    INT  move number  := 1;
    INT  row          := start row;
    INT  col          := start col;
    INT  direction    := lowest move - 1;
    # the first move is to place the knight on the starting square #
    board[ row, col ] := ( move number, lowest move - 1 );
    # attempt to find a sequence of moves that will reach each square once #
    WHILE
        move number < final move AND result
    DO
        IF direction < highest move
        THEN
            # try the next move from this position #
            direction +:= 1;
            INT new row = row + offset v[ direction ];
            INT new col = col + offset h[ direction ];
            IF  new row <= 1 UPB board
            AND new row >= 1 LWB board
            AND new col <= 2 UPB board
            AND new col >= 2 LWB board
            THEN
                # the move is legal, check the new square is unused #
                IF move OF board[ new row, new col ] = 0
                THEN
                    # can move here #
                    iterations       +:= 1;
                    row               := new row;
                    col               := new col;
                    move number      +:= 1;
                    board[ row, col ] := ( move number, direction );
                    direction         := lowest move - 1
                FI
            FI
        ELSE
            # no more moves from this position - backtrack #
            IF move number = 1
            THEN
                # at the starting position - no solution #
                result := FALSE
            ELSE
                # not at the starting position - undo the latest move #
                backtracks  +:= 1;
                move number -:= 1;
                INT curr row := row;
                INT curr col := col;
                row -:= offset v[ direction OF board[ curr row, curr col ] ];
                col -:= offset h[ direction OF board[ curr row, curr col ] ];
                # determine which direction to try next #
                direction := direction OF board[ curr row, curr col ];
                # reset the square we just backtracked from #
                board[ curr row, curr col ] := ( 0, 0 )
            FI
        FI
    OD;
    result
END; # find tour #

main:(
    initialise board( ( "-000----"
                      , "-0-00---"
                      , "-0000000"
                      , "000--0-0"
                      , "0-0--000"
                      , "1000000-"
                      , "--00-0--"
                      , "---000--"
                      )
                    );
    IF find tour
    THEN
        # found a solution #
        print tour
    ELSE
        # couldn't find a solution #
        print( ( "Solution not found", newline ) )
    FI;
    print( ( iterations, " iterations, ", backtracks, " backtracks", newline ) )
)


import java.util.*;

public class Sokoban {
    String destBoard, currBoard;
    int playerX, playerY, nCols;

    Sokoban(String[] board) {
        nCols = board[0].length();
        StringBuilder destBuf = new StringBuilder();
        StringBuilder currBuf = new StringBuilder();

        for (int r = 0; r < board.length; r++) {
            for (int c = 0; c < nCols; c++) {

                char ch = board[r].charAt(c);

                destBuf.append(ch != '$' && ch != '@' ? ch : ' ');
                currBuf.append(ch != '.' ? ch : ' ');

                if (ch == '@') {
                    this.playerX = c;
                    this.playerY = r;
                }
            }
        }
        destBoard = destBuf.toString();
        currBoard = currBuf.toString();
    }

    String move(int x, int y, int dx, int dy, String trialBoard) {

        int newPlayerPos = (y + dy) * nCols + x + dx;

        if (trialBoard.charAt(newPlayerPos) != ' ')
            return null;

        char[] trial = trialBoard.toCharArray();
        trial[y * nCols + x] = ' ';
        trial[newPlayerPos] = '@';

        return new String(trial);
    }

    String push(int x, int y, int dx, int dy, String trialBoard) {

        int newBoxPos = (y + 2 * dy) * nCols + x + 2 * dx;

        if (trialBoard.charAt(newBoxPos) != ' ')
            return null;

        char[] trial = trialBoard.toCharArray();
        trial[y * nCols + x] = ' ';
        trial[(y + dy) * nCols + x + dx] = '@';
        trial[newBoxPos] = '$';

        return new String(trial);
    }

    boolean isSolved(String trialBoard) {
        for (int i = 0; i < trialBoard.length(); i++)
            if ((destBoard.charAt(i) == '.')
                    != (trialBoard.charAt(i) == '$'))
                return false;
        return true;
    }

    String solve() {
        class Board {
            String cur, sol;
            int x, y;

            Board(String s1, String s2, int px, int py) {
                cur = s1;
                sol = s2;
                x = px;
                y = py;
            }
        }
        char[][] dirLabels = {{'u', 'U'}, {'r', 'R'}, {'d', 'D'}, {'l', 'L'}};
        int[][] dirs = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};

        Set<String> history = new HashSet<>();
        LinkedList<Board> open = new LinkedList<>();

        history.add(currBoard);
        open.add(new Board(currBoard, "", playerX, playerY));

        while (!open.isEmpty()) {
            Board item = open.poll();
            String cur = item.cur;
            String sol = item.sol;
            int x = item.x;
            int y = item.y;

            for (int i = 0; i < dirs.length; i++) {
                String trial = cur;
                int dx = dirs[i][0];
                int dy = dirs[i][1];

                // are we standing next to a box ?
                if (trial.charAt((y + dy) * nCols + x + dx) == '$') {

                    // can we push it ?
                    if ((trial = push(x, y, dx, dy, trial)) != null) {

                        // or did we already try this one ?
                        if (!history.contains(trial)) {

                            String newSol = sol + dirLabels[i][1];

                            if (isSolved(trial))
                                return newSol;

                            open.add(new Board(trial, newSol, x + dx, y + dy));
                            history.add(trial);
                        }
                    }

                // otherwise try changing position
                } else if ((trial = move(x, y, dx, dy, trial)) != null) {

                    if (!history.contains(trial)) {
                        String newSol = sol + dirLabels[i][0];
                        open.add(new Board(trial, newSol, x + dx, y + dy));
                        history.add(trial);
                    }
                }
            }
        }
        return "No solution";
    }

    public static void main(String[] a) {
        String level = "#######,#     #,#     #,#. #  #,#. $$ #,"
                + "#.$$  #,#.#  @#,#######";
        System.out.println(new Sokoban(level.split(",")).solve());
    }
}


( ( Holy-Knight
  =     begin colWidth crumbs non-empty pairs path parseLine
      , display isolateStartCell minDistance numberElementsAndSort
      , parseBoard reverseList rightAlign solve strlen
    .   "'non-empty' is a pattern that is used several times in bigger patterns."
      & ( non-empty
        =
        =   %@
          : ~( "."
             | "-"
             | " "
             | \t
             | \r
             | \n
             )
        )
      & ( reverseList
        =   a L
          .   :?L
            & whl'(!arg:%?a ?arg&!a !L:?L)
            & !L
        )
      & ([email protected](!arg:? [?e)&!e)
      & ( rightAlign
        =   string width
          .   !arg:(?width,?string)
            & !width+-1*strlen$!string:?width
            &   whl
              ' ( !width+-1:~<0:?width
                & " " !string:?string
                )
            & str$!string
        )
      & ( minDistance
        =   board pat1 pat2 minWidth pos1 pos2 pattern
          .   !arg:(?board,(=?pat1),(=?pat2))
            & -1:?minWidth
            & "Construct a pattern using a template.
            The pattern finds the smallest distance between any two columns in the input.
            Assumption: all columns have the same width and columns are separated by one or
            more spaces. The function can also be used to find the width of the first column
            by letting pat1 match a new line."
            &
                ' ( ?
                    (   $pat1
                        [?pos1
                        (? " "|`)
                        ()$pat2
                        [?pos2
                        ?
                    &   !pos2+-1*!pos1
                      : ( <!minWidth
                        | ?&!minWidth:<0
                        )
                      : ?minWidth
                    & ~
                    )
                  )
              : (=?pattern)
            & "'pattern', by design, always fails. The interesting part is a side effect:
               the column width."
            & (@(!board:!pattern)|!minWidth)
        )
      & ( numberElementsAndSort
        =   a sum n
          .   0:?sum:?n
            & "An evaluated sum is always sorted. The terms are structured so the sorting
               order is by row and then by column (both part of 'a')."
            &   whl
              ' ( !arg:%?a ?arg
                & 1+!n:?n
                & (!a,!n)+!sum:?sum
                )
            & "return the sorted list (sum) and also the size of a field that can contain
               the highest number."
            & (!sum.strlen$!n+1)
        )
      & ( parseLine
        =     line row columnWidth width col
            , bins val A M Z cell validPat
          .   !arg:(?line,?row,?width,?columnWidth,?bins)
            & 0:?col
            & "Find the cells and create a pair [row,col] for each. Put each pair in a bin.
               There are as many bins as there are different values in cells."
            &   '(? ($!non-empty:?val) ?)
              : (=?validPat)
            &   whl
              ' ( @(!line:?cell [!width ?line)
                & (   @(!cell:!validPat)
                    &   (   !bins:?A (!val.?M) ?Z
                          & !A (!val.(!row.!col) !M) !Z
                        | (!val.!row.!col) !bins
                        )
                      : ?bins
                  |
                  )
                & !columnWidth:?width
                & 1+!col:?col
                )
            & !bins
        )
      & ( parseBoard
        =   board firstColumnWidth columnWidth,row bins line
          .   !arg:?board
            &   (   minDistance
                  $ (str$(\r \n !arg),(=\n),!non-empty)
                , minDistance$(!arg,!non-empty,!non-empty)
                )
              : (?firstColumnWidth,?columnWidth)
            & 0:?row
            & :?bins
            &   whl
              ' ( @(!board:?line \n ?board)
                &     parseLine
                    $ (!line,!row,!firstColumnWidth,!columnWidth,!bins)
                  : ?bins
                & (!bins:|1+!row:?row)
                )
            &     parseLine
                $ (!board,!row,!firstColumnWidth,!columnWidth,!bins)
              : ?bins
        )
      & "Find the first bin with only one pair. Return this pair and the combined pairs in
         all remaining bins."
      & ( isolateStartCell
        =   A begin Z valuedPairs pairs
          .   !arg:?A (?.? [1:?begin) ?Z
            & !A !Z:?arg
            & :?pairs
            &   whl
              ' ( !arg:(?.?valuedPairs) ?arg
                & !valuedPairs !pairs:?pairs
                )
            & (!begin.!pairs)
        )
      & ( display
        =   board solution row col x y n colWidth
          .   !arg:(?board,?solution,?colWidth)
            & out$!board
            & 0:?row
            & -1:?col
            &   whl
              ' ( !solution:((?y.?x),?n)+?solution
                &   whl
                  ' ( !row:<!y
                    & 1+!row:?row
                    & -1:?col
                    & put$\n
                    )
                &   whl
                  ' ( 1+!col:?col:<!x
                    & put$(rightAlign$(!colWidth,))
                    )
                & put$(rightAlign$(!colWidth,!n))
                )
            & put$\n
        )
      & ( solve
        =   A Z x y crumbs pairs X Y solution
          .   !arg:((?y.?x),?crumbs,?pairs)
            & ( !pairs:&(!y.!x) !crumbs
              |     !pairs
                  :   ?A
                      ( (?Y.?X) ?Z
                      &   (!x+-1*!X)*(!y+-1*!Y)
                        : (2|-2)
                      &     solve
                          $ ( (!Y.!X)
                            , (!y.!x) !crumbs
                            , !A !Z
                            )
                        : ?solution
                      )
                & !solution
              )
        )
      & ( isolateStartCell$(parseBoard$!arg):(?begin.?pairs)
        | out$"Sorry, I cannot identify a start cell."&~
        )
      & solve$(!begin,,!pairs):?crumbs
      &   numberElementsAndSort$(reverseList$!crumbs)
        : (?path.?colWidth)
      & display$(!arg,!path,!colWidth)
  )
&     "

      0 0 0
      0   0 0
      0 0 0 0 0 0 0
    0 0 0     0   0
    0   0     0 0 0
    1 0 0 0 0 0 0
        0 0   0
          0 0 0
          "
      "
-----1-0-----
-----0-0-----
----00000----
-----000-----
--0--0-0--0--
00000---00000
--00-----00--
00000---00000
--0--0-0--0--
-----000-----
----00000----
-----0-0-----
-----0-0-----"
  : ?boards
& whl'(!boards:%?board ?boards&Holy-Knight$!board)
& done
);


using System.Collections;
using System.Collections.Generic;
using static System.Console;
using static System.Math;
using static System.Linq.Enumerable;

public class Solver
{
    private static readonly (int dx, int dy)[]
        //other puzzle types elided
        knightMoves = {(1,-2),(2,-1),(2,1),(1,2),(-1,2),(-2,1),(-2,-1),(-1,-2)};

    private (int dx, int dy)[] moves;

    public static void Main()
    {
        var knightSolver = new Solver(knightMoves);
        Print(knightSolver.Solve(true,
            ".000....",
            ".0.00...",
            ".0000000",
            "000..0.0",
            "0.0..000",
            "1000000.",
            "..00.0..",
            "...000.."));

        Print(knightSolver.Solve(true,
            ".....0.0.....",
            ".....0.0.....",
            "....00000....",
            ".....000.....",
            "..0..0.0..0..",
            "00000...00000",
            "..00.....00..",
            "00000...00000",
            "..0..0.0..0..",
            ".....000.....",
            "....00000....",
            ".....0.0.....",
            ".....0.0....."
        ));
    }

    public Solver(params (int dx, int dy)[] moves) => this.moves = moves;

    public int[,] Solve(bool circular, params string[] puzzle)
    {
        var (board, given, count) = Parse(puzzle);
        return Solve(board, given, count, circular);
    }

    public int[,] Solve(bool circular, int[,] puzzle)
    {
        var (board, given, count) = Parse(puzzle);
        return Solve(board, given, count, circular);
    }

    private int[,] Solve(int[,] board, BitArray given, int count, bool circular)
    {
        var (height, width) = (board.GetLength(0), board.GetLength(1));
        bool solved = false;
        for (int x = 0; x < height && !solved; x++) {
            solved = Range(0, width).Any(y => Solve(board, given, circular, (height, width), (x, y), count, (x, y), 1));
            if (solved) return board;
        }
        return null;
    }

    private bool Solve(int[,] board, BitArray given, bool circular,
        (int h, int w) size, (int x, int y) start, int last, (int x, int y) current, int n)
    {
        var (x, y) = current;
        if (x < 0 || x >= size.h || y < 0 || y >= size.w) return false;
        if (board[x, y] < 0) return false;
        if (given[n - 1]) {
            if (board[x, y] != n) return false;
        } else if (board[x, y] > 0) return false;
        board[x, y] = n;
        if (n == last) {
            if (!circular || AreNeighbors(start, current)) return true;
        }
        for (int i = 0; i < moves.Length; i++) {
            var move = moves[i];
            if (Solve(board, given, circular, size, start, last, (x + move.dx, y + move.dy), n + 1)) return true;
        }
        if (!given[n - 1]) board[x, y] = 0;
        return false;

        bool AreNeighbors((int x, int y) p1, (int x, int y) p2) => moves.Any(m => (p2.x + m.dx, p2.y + m.dy).Equals(p1));
    }

    private static (int[,] board, BitArray given, int count) Parse(string[] input)
    {
        (int height, int width) = (input.Length, input[0].Length);
        int[,] board = new int[height, width];
        int count = 0;
        for (int x = 0; x < height; x++) {
            string line = input[x];
            for (int y = 0; y < width; y++) {
                board[x, y] = y < line.Length && char.IsDigit(line[y]) ? line[y] - '0' : -1;
                if (board[x, y] >= 0) count++;
            }
        }
        BitArray given = Scan(board, count, height, width);
        return (board, given, count);
    }

    private static (int[,] board, BitArray given, int count) Parse(int[,] input)
    {
        (int height, int width) = (input.GetLength(0), input.GetLength(1));
        int[,] board = new int[height, width];
        int count = 0;
        for (int x = 0; x < height; x++)
            for (int y = 0; y < width; y++)
                if ((board[x, y] = input[x, y]) >= 0) count++;
        BitArray given = Scan(board, count, height, width);
        return (board, given, count);
    }

    private static BitArray Scan(int[,] board, int count, int height, int width)
    {
        var given = new BitArray(count + 1);
        for (int x = 0; x < height; x++)
            for (int y = 0; y < width; y++)
                if (board[x, y] > 0) given[board[x, y] - 1] = true;
        return given;
    }

    private static void Print(int[,] board)
    {
        if (board == null) {
            WriteLine("No solution");
        } else {
            int w = board.Cast<int>().Where(i => i > 0).Max(i => (int?)Ceiling(Log10(i+1))) ?? 1;
            string e = new string('-', w);
            foreach (int x in Range(0, board.GetLength(0)))
                WriteLine(string.Join(" ", Range(0, board.GetLength(1))
                    .Select(y => board[x, y] < 0 ? e : board[x, y].ToString().PadLeft(w, ' '))));
        }
        WriteLine();
    }

}


struct BoardState
    board::String
    csol::String
    position::Int
end

function move(s::BoardState, dpos)
    buffer = Vector{UInt8}(deepcopy(s.board))
    if s.board[s.position] == '@'
        buffer[s.position] = ' '
    else
        buffer[s.position] = '.'
    end
    newpos = s.position + dpos
    if s.board[newpos] == ' '
        buffer[newpos] = '@'
    else
        buffer[newpos] = '+'
    end
    String(buffer)
end

function push(s::BoardState, dpos)
    newpos = s.position + dpos
    boxpos = newpos + dpos
    if s.board[boxpos] != ' ' && s.board[boxpos] != '.'
        return ""
    end
    buffer = Vector{UInt8}(deepcopy(s.board))
    if s.board[s.position] == '@'
        buffer[s.position] = ' '
    else
        buffer[s.position] = '.'
    end
    if s.board[newpos] == '$'
        buffer[newpos] = '@'
    else
        buffer[newpos] = '+'
    end
    if s.board[boxpos] == ' '
        buffer[boxpos] = '$'
    else
        buffer[boxpos] = '*'
    end
    String(buffer)
end

function solve(board)
    width = findfirst("\n", board[2:end])[1] + 1
    dopt = (u = -width, l = -1, d = width, r = 1)
    visited = Dict(board => true)
    open::Vector{BoardState} = [BoardState(board, "", findfirst("@", board)[1])]
    while length(open) > 0
        s1 = open[1]
        open = open[2:end]
        for dir in keys(dopt)
            newpos = s1.position + dopt[dir]
            x = s1.board[newpos]
            if x == '$' || x == '*'
                newboard = push(s1, dopt[dir])
                if newboard == "" || haskey(visited, newboard)
                    continue
                end
                newsol = s1.csol * uppercase(string(dir))
                if findfirst(r"[\.\+]", newboard) ==  nothing
                    return newsol
                end
            elseif x == ' ' || x == '.'
                newboard = move(s1, dopt[dir])
                if haskey(visited, newboard)
                    continue
                end
                newsol = s1.csol * string(dir)
            else
                continue
            end
            open = push!(open, BoardState(newboard, newsol, newpos))
            visited[newboard] = true
        end
    end
    "No solution" # we should only get here if no solution to the sokoban
end

const testlevel = strip(raw"""
#######
#     #
#     #
#. #  #
#. $$ #
#.$$  #
#.#  @#
#######""")
println("For sokoban level:\n$testlevel\n...solution is :\n$(solve(testlevel))")


// version 1.2.0

import java.util.LinkedList

class Sokoban(board: List<String>) {
    val destBoard: String
    val currBoard: String
    val nCols = board[0].length
    var playerX = 0
    var playerY = 0

    init {
        val destBuf = StringBuilder()
        val currBuf = StringBuilder()
        for (r in 0 until board.size) {
            for (c in 0 until nCols) {
                val ch = board[r][c]
                destBuf.append(if (ch != '$' && ch != '@') ch else ' ')
                currBuf.append(if (ch != '.') ch else ' ')
                if (ch == '@') {
                    playerX = c
                    playerY = r
                }
            }
        }
        destBoard = destBuf.toString()
        currBoard = currBuf.toString()
    }

    fun move(x: Int, y: Int, dx: Int, dy: Int, trialBoard: String): String {
        val newPlayerPos = (y + dy) * nCols + x + dx
        if (trialBoard[newPlayerPos] != ' ') return ""
        val trial = trialBoard.toCharArray()
        trial[y * nCols + x] = ' '
        trial[newPlayerPos] = '@'
        return String(trial)
    }

    fun push(x: Int, y: Int, dx: Int, dy: Int, trialBoard: String): String {
        val newBoxPos = (y + 2 * dy) * nCols + x + 2 * dx
        if (trialBoard[newBoxPos] != ' ') return ""
        val trial = trialBoard.toCharArray()
        trial[y * nCols + x] = ' '
        trial[(y + dy) * nCols + x + dx] = '@'
        trial[newBoxPos] = '$'
        return String(trial)
    }

    fun isSolved(trialBoard: String): Boolean {
        for (i in 0 until trialBoard.length) {
            if ((destBoard[i] == '.') != (trialBoard[i] == '$')) return false
        }
        return true
    }

    fun solve(): String {
        data class Board(val cur: String, val sol: String, val x: Int, val y: Int)
        val dirLabels = listOf('u' to 'U', 'r' to 'R', 'd' to 'D', 'l' to 'L')
        val dirs = listOf(0 to -1, 1 to 0, 0 to 1, -1 to 0)
        val history = mutableSetOf<String>()
        history.add(currBoard)
        val open = LinkedList<Board>()
        open.add(Board(currBoard, "", playerX, playerY))

        while (!open.isEmpty()) {
            val (cur, sol, x, y) = open.poll()
            for (i in 0 until dirs.size) {
                var trial = cur
                val dx = dirs[i].first
                val dy = dirs[i].second

                // are we standing next to a box ?
                if (trial[(y + dy) * nCols + x + dx] == '$') {

                    // can we push it ?
                    trial = push(x, y, dx, dy, trial)
                    if (!trial.isEmpty()) {

                        // or did we already try this one ?
                        if (trial !in history) {
                            val newSol = sol + dirLabels[i].second
                            if (isSolved(trial)) return newSol
                            open.add(Board(trial, newSol, x + dx, y + dy))
                            history.add(trial)
                        }
                    }
                } // otherwise try changing position
                else {
                    trial = move(x, y, dx, dy, trial)
                    if (!trial.isEmpty() && trial !in history) {
                        val newSol = sol + dirLabels[i].first
                        open.add(Board(trial, newSol, x + dx, y + dy))
                        history.add(trial)
                    }
                }
            }
        }
        return "No solution"
    }
}

fun main(args: Array<String>) {
    val level = listOf(
        "#######",
        "#     #",
        "#     #",
        "#. #  #",
        "#. $$ #",
        "#.$$  #",
        "#.#  @#",
        "#######"
    )
    println(level.joinToString("\n"))
    println()
    println(Sokoban(level).solve())
}


#include <vector>
#include <sstream>
#include <iostream>
#include <iterator>
#include <stdlib.h>
#include <string.h>

using namespace std;

struct node
{
    int val;
    unsigned char neighbors;
};

class nSolver
{
public:
    nSolver()
    {
	dx[0] = -1; dy[0] = -2; dx[1] = -1; dy[1] =  2;
	dx[2] =  1; dy[2] = -2; dx[3] =  1; dy[3] =  2;
	dx[4] = -2; dy[4] = -1; dx[5] = -2; dy[5] =  1;
	dx[6] =  2; dy[6] = -1; dx[7] =  2; dy[7] =  1;
    }

    void solve( vector<string>& puzz, int max_wid )
    {
	if( puzz.size() < 1 ) return;
	wid = max_wid; hei = static_cast<int>( puzz.size() ) / wid;
	int len = wid * hei, c = 0; max = len;
	arr = new node[len]; memset( arr, 0, len * sizeof( node ) );

	for( vector<string>::iterator i = puzz.begin(); i != puzz.end(); i++ )
	{
	    if( ( *i ) == "*" ) { max--; arr[c++].val = -1; continue; }
	    arr[c].val = atoi( ( *i ).c_str() );
	    c++;
	}

	solveIt(); c = 0;
	for( vector<string>::iterator i = puzz.begin(); i != puzz.end(); i++ )
	{
	    if( ( *i ) == "." )
	    {
		ostringstream o; o << arr[c].val;
		( *i ) = o.str();
	    }
	    c++;
	}
	delete [] arr;
    }

private:
    bool search( int x, int y, int w )
    {
	if( w > max ) return true;

	node* n = &arr[x + y * wid];
	n->neighbors = getNeighbors( x, y );

	for( int d = 0; d < 8; d++ )
	{
	    if( n->neighbors & ( 1 << d ) )
	    {
		int a = x + dx[d], b = y + dy[d];
		if( arr[a + b * wid].val == 0 )
		{
		    arr[a + b * wid].val = w;
		    if( search( a, b, w + 1 ) ) return true;
		    arr[a + b * wid].val = 0;
		}
	    }
	}
	return false;
    }

    unsigned char getNeighbors( int x, int y )
    {
	unsigned char c = 0; int a, b;
	for( int xx = 0; xx < 8; xx++ )
	{
	    a = x + dx[xx], b = y + dy[xx];
	    if( a < 0 || b < 0 || a >= wid || b >= hei ) continue;
	    if( arr[a + b * wid].val > -1 ) c |= ( 1 << xx );
	}
	return c;
    }

    void solveIt()
    {
	int x, y, z; findStart( x, y, z );
	if( z == 99999 ) { cout << "\nCan't find start point!\n"; return; }
	search( x, y, z + 1 );
    }

    void findStart( int& x, int& y, int& z )
    {
	z = 99999;
	for( int b = 0; b < hei; b++ )
	    for( int a = 0; a < wid; a++ )
		if( arr[a + wid * b].val > 0 && arr[a + wid * b].val < z )
		{
		    x = a; y = b;
		    z = arr[a + wid * b].val;
		}

    }

    int wid, hei, max, dx[8], dy[8];
    node* arr;
};

int main( int argc, char* argv[] )
{
    int wid; string p;
    //p = "* . . . * * * * * . * . . * * * * . . . . . . . . . . * * . * . . * . * * . . . 1 . . . . . . * * * . . * . * * * * * . . . * *"; wid = 8;
    p = "* * * * * 1 * . * * * * * * * * * * . * . * * * * * * * * * . . . . . * * * * * * * * * . . . * * * * * * * . * * . * . * * . * * . . . . . * * * . . . . . * * . . * * * * * . . * * . . . . . * * * . . . . . * * . * * . * . * * . * * * * * * * . . . * * * * * * * * * . . . . . * * * * * * * * * . * . * * * * * * * * * * . * . * * * * * "; wid = 13;
    istringstream iss( p ); vector<string> puzz;
    copy( istream_iterator<string>( iss ), istream_iterator<string>(), back_inserter<vector<string> >( puzz ) );
    nSolver s; s.solve( puzz, wid );
    int c = 0;
    for( vector<string>::iterator i = puzz.begin(); i != puzz.end(); i++ )
    {
	if( ( *i ) != "*" && ( *i ) != "." )
	{
	    if( atoi( ( *i ).c_str() ) < 10 ) cout << "0";
	    cout << ( *i ) << " ";
        }
	else cout << "   ";
	if( ++c >= wid ) { cout << endl; c = 0; }
    }
    cout << endl << endl;
    return system( "pause" );
}


import deques, sets, strutils

type

  Sokoban = object
    destBoard: string
    currBoard: string
    nCols: Natural
    playerX: Natural
    playerY: Natural

  Board = tuple[cur, sol: string; x, y: int]

func initSokoban(board: openArray[string]): Sokoban =
  result.nCols = board[0].len
  for row in 0..board.high:
    for col in 0..<result.nCols:
      let ch = board[row][col]
      result.destBoard.add if ch notin ['$', '@']: ch else: ' '
      result.currBoard.add if ch != '.': ch else: ' '
      if ch == '@':
        result.playerX = col
        result.playerY = row

func move(sokoban: Sokoban; x, y, dx, dy: int; trialBoard: string): string =
  let newPlayerPos = (y + dy) * sokoban.nCols + x + dx
  if trialBoard[newPlayerPos] != ' ': return
  result = trialBoard
  result[y * sokoban.nCols + x] = ' '
  result[newPlayerPos] = '@'

func push(sokoban: Sokoban; x, y, dx, dy: int; trialBoard: string): string =
  let newBoxPos = (y + 2 * dy) * sokoban.nCols + x + 2 * dx
  if trialBoard[newBoxPos] != ' ': return
  result = trialBoard
  result[y * sokoban.nCols + x] = ' '
  result[(y + dy) * sokoban.nCols + x + dx] = '@'
  result[newBoxPos] = '$'

func isSolved(sokoban: Sokoban; trialBoard: string): bool =
  for i in 0..trialBoard.high:
    if (sokoban.destBoard[i] == '.') != (trialBoard[i] == '$'): return false
  result = true

func solve(sokoban: Sokoban): string =
  var history: HashSet[string]
  history.incl sokoban.currBoard
  const Dirs = [(0, -1, 'u', 'U'), (1, 0, 'r', 'R'), (0, 1, 'd', 'D'), (-1, 0, 'l', 'L')]
  var open: Deque[Board]
  open.addLast (sokoban.currBoard, "", sokoban.playerX, sokoban.playerY)

  while open.len != 0:
    let (cur, sol, x, y) = open.popFirst()
    for dir in Dirs:
      var trial = cur
      let dx = dir[0]
      let dy = dir[1]

      # Are we standing next to a box?
      if trial[(y + dy) * sokoban.nCols + x + dx] == '$':
        # Can we push it?
        trial = sokoban.push(x, y, dx, dy, trial)
        if trial.len != 0:
          # Or did we already try this one?
          if trial notin history:
            let newSol = sol & dir[3]
            if sokoban.isSolved(trial): return newSol
            open.addLast (trial, newSol, x + dx, y + dy)
            history.incl trial

      else:
        # Try to change position.
        trial = sokoban.move(x, y, dx, dy, trial)
        if trial.len != 0 and trial notin history:
          let newSol = sol & dir[2]
          open.addLast (trial, newSol, x + dx, y + dy)
          history.incl trial

  result = "no solution"

when isMainModule:

  const Level = ["#######",
                "#     #",
                "#     #",
                "#. #  #",
                "#. $$ #",
                "#.$$  #",
                "#.#  @#",
                "#######"]

  echo Level.join("\n")
  echo()
  echo initSokoban(Level).solve()


type dir = U | D | L | R
type move_t = Move of dir | Push of dir

let letter = function
   | Push(U) -> 'U' | Push(D) -> 'D' | Push(L) -> 'L' | Push(R) -> 'R'
   | Move(U) -> 'u' | Move(D) -> 'd' | Move(L) -> 'l' | Move(R) -> 'r'

let cols = ref 0
let delta = function U -> -(!cols) | D -> !cols | L -> -1 | R -> 1

let store = Hashtbl.create 251
let mark t = Hashtbl.replace store t ()
let marked t = Hashtbl.mem store t

let show ml =
   List.iter (fun c -> print_char (letter c)) (List.rev ml); print_newline()

let gen_moves (x,boxes) bd =
   let empty i = bd.(i) = ' ' && not (List.mem i boxes) in
   let check l dir =
      let dx = delta dir in
      let x1 = x+dx in
      if List.mem x1 boxes then (
         if empty (x1+dx) then Push(dir) :: l else l
      ) else (
         if bd.(x1) = ' ' then Move(dir) :: l else l
      ) in
   (List.fold_left check [] [U; L; R; D])

let do_move (x,boxes) = function
   | Push(d) -> let dx = delta d in
      let x1 = x+dx in let x2 = x1+dx in
      let rec shift = function
         | [] -> failwith "shift"
         | h :: t -> if h = x1 then x2 :: t else h :: shift t in
      x1, List.fast_sort compare (shift boxes)
   | Move(d) -> (x+(delta d)), boxes

let init_pos bd =
   let p = ref 0 in
   let q = ref [] in
   let check i c =
      if c = '$' || c = '*' then q := i::!q
      else if c = '@' then p := i in (
   Array.iteri check bd;
   (!p, List.fast_sort compare !q);
   )

let final_box bd =
   let check (i,l) c = if c = '.' || c = '*' then (i+1,i::l) else (i+1,l) in
   List.fast_sort compare (snd (Array.fold_left check (0,[]) bd))

let array_of_input inp =
   let r = List.length inp and c = String.length (List.hd inp) in
   let a = Array.create (r*c) ' ' in (
   for i = 0 to pred r do
      let s = List.nth inp i in
      for j = 0 to pred c do a.(i*c+j) <- s.[j] done
   done;
   cols := c; a)

let solve b =
   let board = array_of_input b in
   let targets = final_box board in
   let solved pos = targets = snd pos in
   let clear = Array.map (function '#' -> '#' | _ -> ' ') in
   let bdc = clear board in
   let q = Queue.create () in
   let pos1 = init_pos board in
   begin
      mark pos1;
      Queue.add (pos1, []) q;
      while not (Queue.is_empty q) do
         let curr, mhist = Queue.pop q in
         let moves = gen_moves curr bdc in
         let check m =
            let next = do_move curr m in
            if not (marked next) then
            if solved next then (show (m::mhist); exit 0)
            else (mark next; Queue.add (next,m::mhist) q) in
         List.iter check moves
      done;
      print_endline "No solution"
   end;;

let level = ["#######";
             "#     #";
             "#     #";
             "#. #  #";
             "#. $$ #";
             "#.$$  #";
             "#.#  @#";
             "#######"] in
solve level


import std.stdio, std.conv, std.string, std.range, std.algorithm,
       std.typecons, std.typetuple;

struct HolyKnightPuzzle {
    private alias InputCellBaseType = char;
    private enum InputCell : InputCellBaseType { available = '#', unavailable = '.', start='1' }
    private alias Cell = uint;
    private enum : Cell { unknownCell = 0, unavailableCell = Cell.max, startCell=1 } // Special Cell values.

    // Neighbors, [shift row, shift column].
    static struct P { int x, y; }
    alias shifts = TypeTuple!(P(-2, -1), P(2, -1), P(-2, 1), P(2, 1),
                              P(-1, -2), P(1, -2), P(-1, 2), P(1, 2));

    immutable size_t gridWidth, gridHeight;
    private immutable Cell nAvailableCells;
    private /*immutable*/ const InputCell[] flatPuzzle;
    private Cell[] grid; // Flattened mutable game grid.

    @disable this();

    this(in string[] rawPuzzle) pure @safe
    in {
        assert(!rawPuzzle.empty);
        assert(!rawPuzzle[0].empty);
        assert(rawPuzzle.all!(row => row.length == rawPuzzle[0].length)); // Is rectangular.
        assert(rawPuzzle.join.count(InputCell.start) == 1); // Exactly one start point.
    } body {
        //immutable puzzle = rawPuzzle.to!(InputCell[][]);
        immutable puzzle = rawPuzzle.map!representation.array.to!(InputCell[][]);

        gridWidth = puzzle[0].length;
        gridHeight = puzzle.length;
        flatPuzzle = puzzle.join;

        // This counts the start cell too.
        nAvailableCells = flatPuzzle.representation.count!(ic => ic != InputCell.unavailable);

        grid = flatPuzzle
               .map!(ic => ic.predSwitch(InputCell.available,   unknownCell,
                                         InputCell.unavailable, unavailableCell,
                                         InputCell.start,       startCell))
               .array;
    }

    Nullable!(string[][]) solve(size_t width)() pure /*nothrow*/ @safe
    out(result) {
        if (!result.isNull)
            assert(!grid.canFind(unknownCell));
    } body {
        assert(width == gridWidth);

        // Find start position.
        foreach (immutable r; 0 ..  gridHeight)
            foreach (immutable c; 0 .. width)
                if (grid[r * width + c] == startCell &&
                    search!width(r, c, startCell + 1)) {
                    auto result = zip(flatPuzzle, grid) // Not nothrow.
                                  //.map!({p, c} => ...
                                  .map!(pc => (pc[0] == InputCell.available) ?
                                              pc[1].text :
                                              InputCellBaseType(pc[0]).text)
                                  .array
                                  .chunks(width)
                                  .array;
                    return typeof(return)(result);
                }

        return typeof(return)();
    }

    private bool search(size_t width)(in size_t r, in size_t c, in Cell cell) pure nothrow @safe @nogc {
        if (cell > nAvailableCells)
            return true; // One solution found.

        // This doesn't use the Warnsdorff rule.
        foreach (immutable sh; shifts) {
            immutable r2 = r + sh.x,
                      c2 = c + sh.y,
                      pos = r2 * width + c2;
            // No need to test for >= 0 because uint wraps around.
            if (c2 < width && r2 < gridHeight && grid[pos] == unknownCell) {
                grid[pos] = cell;        // Try.
                if (search!width(r2, c2, cell + 1))
                    return true;
                grid[pos] = unknownCell; // Restore.
            }
        }

        return false;
    }
}

void main() @safe {
    // Enum HolyKnightPuzzle to catch malformed puzzles at compile-time.
    enum puzzle1 = ".###....
                    .#.##...
                    .#######
                    ###..#.#
                    #.#..###
                    1######.
                    ..##.#..
                    ...###..".split.HolyKnightPuzzle;

    enum puzzle2 = ".....1.#.....
                    .....#.#.....
                    ....#####....
                    .....###.....
                    ..#..#.#..#..
                    #####...#####
                    ..##.....##..
                    #####...#####
                    ..#..#.#..#..
                    .....###.....
                    ....#####....
                    .....#.#.....
                    .....#.#.....".split.HolyKnightPuzzle;

    foreach (/*enum*/ puzzle; TypeTuple!(puzzle1, puzzle2)) {
        //immutable solution = puzzle.solve!(puzzle.gridWidth);
        enum width = puzzle.gridWidth;
        immutable solution = puzzle.solve!width; // Solved at run-time.
        if (solution.isNull)
            writeln("No solution found for puzzle.\n");
        else
            writefln("One solution:\n%(%-(%2s %)\n%)\n", solution);
    }
}


with GNAT.Sockets;  use GNAT.Sockets;

procedure Socket_Send is
   Client : Socket_Type;
begin
   Initialize;
   Create_Socket  (Socket => Client);
   Connect_Socket (Socket => Client,
                   Server => (Family => Family_Inet,
                              Addr   => Inet_Addr ("127.0.0.1"),
                              Port   => 256));
   String'Write (Stream (Client), "hello socket world");
   Close_Socket (Client);
end Socket_Send;


#!perl
use strict;
use warnings qw(FATAL all);
my @initial = split /\n/, <<'';
#############
#  #        #
# $$$$$$$  @#
#.......    #
#############

#######
#     #
#     #
#. #  #
#. $$ #
#.$$  #
#.#  @#
#######

=for
space is an empty square
# is a wall
@ is the player
$ is a box
. is a goal
+ is the player on a goal
* is a box on a goal
=cut

my $cols = length($initial[0]);
my $initial = join '', @initial;
my $size = length($initial);
die unless $size == $cols * @initial;

sub WALL() { 1 }
sub PLAYER() { 2 }
sub BOX() { 4 }
sub GOAL() { 8 }

my %input = (
	' ' => 0, '#' => WALL, '@' => PLAYER, '$' => BOX,
	'.' => GOAL, '+' => PLAYER|GOAL, '*' => BOX|GOAL,
);
my %output = reverse(%input);

sub packed_initial {
	my $ret = '';
	vec( $ret, $_, 4 ) = $input{substr $initial, $_, 1}
		for( 0 .. $size-1 );
	$ret;
}

sub printable_board {
	my $board = shift;
	my @c = @output{map vec($board, $_, 4), 0 .. $size-1};
	my $ret = '';
	while( my @row = splice @c, 0, $cols ) {
		$ret .= join '', @row, "\n";
	}
	$ret;
}

my $packed = packed_initial();

my @udlr = qw(u d l r);
my @UDLR = qw(U D L R);
my @deltas = (-$cols, +$cols, -1, +1);

my %fseen;
INIT_FORWARD: {
	$initial =~ /(\@|\+)/ or die;
	use vars qw(@ftodo @fnext);
	@ftodo = (["", $packed,  $-[0]]);
	$fseen{$packed} = '';
}

my %rseen;
INIT_REVERSE: {
	my $goal = $packed;
	vec($goal, $ftodo[0][2], 4) -= PLAYER;
	my @u = grep { my $t = vec($goal, $_, 4); $t & GOAL and not $t & BOX } 0 .. $size-1;
	my @b = grep { my $t = vec($goal, $_, 4); $t & BOX and not $t & GOAL } 0 .. $size-1;
	die unless @u == @b;
	vec($goal, $_, 4) += BOX for @u;
	vec($goal, $_, 4) -= BOX for @b;
	use vars qw(@rtodo @rnext);
	FINAL_PLACE: for my $player (0 .. $size-1) {
		next if vec($goal, $player, 4);
		FIND_GOAL: {
			vec($goal, $player + $_, 4) & GOAL and last FIND_GOAL for @deltas;
			next FINAL_PLACE;
		}
		my $a_goal = $goal;
		vec($a_goal, $player, 4) += PLAYER;
		push @rtodo, ["", $a_goal, $player ];
		$rseen{$a_goal} = '';
		#print printable_board($a_goal);
	}
}

my $movelen = -1;
my ($solution);
MAIN: while( @ftodo and @rtodo ) {

	FORWARD: {
		my ($moves, $level, $player) = @{pop @ftodo};
		die unless vec($level, $player, 4) & PLAYER;

		for my $dir_num (0 .. 3) {
			my $delta = $deltas[$dir_num];
			my @loc = map $player + $delta * $_, 0 .. 2;
			my @val = map vec($level, $_, 4), @loc;

			next if $val[1] & WALL or ($val[1] & BOX and $val[2] & (BOX|WALL));

			my $new = $level;
			vec($new, $loc[0], 4) -= PLAYER;
			vec($new, $loc[1], 4) += PLAYER;
			my $nmoves;
			if( $val[1] & BOX ) {
				vec($new, $loc[1], 4) -= BOX;
				vec($new, $loc[2], 4) += BOX;
				$nmoves = $moves . $UDLR[$dir_num];
			} else {
				$nmoves = $moves . $udlr[$dir_num];
			}

			next if exists $fseen{$new};
			$fseen{$new} = $nmoves;

			push @fnext, [ $nmoves, $new, $loc[1] ];

			exists $rseen{$new} or next;
			#print(($val[1] & BOX) ? "Push $UDLR[$dir_num]\n" : "Fwalk $udlr[$dir_num]\n");
			$solution = $new;
			last MAIN;
		}

		last FORWARD if @ftodo;
		use vars qw(*ftodo *fnext);
		(*ftodo, *fnext) = (\@fnext, \@ftodo);
	} # end FORWARD

	BACKWARD: {
		my ($moves, $level, $player) = @{pop @rtodo};
		die "<$level>" unless vec($level, $player, 4) & PLAYER;

		for my $dir_num (0 .. 3) {
			my $delta = $deltas[$dir_num];
			# look behind and in front of the player.
			my @loc = map $player + $delta * $_, -1 .. 1;
			my @val = map vec($level, $_, 4), @loc;

			# unlike the forward solution, we cannot push boxes
			next if $val[0] & (WALL|BOX);
			my $new = $level;
			vec($new, $loc[0], 4) += PLAYER;
			vec($new, $loc[1], 4) -= PLAYER;
			# unlike the forward solution, if we have a box behind us
			# we can *either* pull it or not.  This means there are
			# two "successors" to this board.
			if( $val[2] & BOX ) {
				my $pull = $new;
				vec($pull, $loc[2], 4) -= BOX;
				vec($pull, $loc[1], 4) += BOX;
				goto RWALK if exists $rseen{$pull};
				my $pmoves = $UDLR[$dir_num] . $moves;
				$rseen{$pull} = $pmoves;
				push @rnext, [$pmoves, $pull, $loc[0]];
				goto RWALK unless exists $fseen{$pull};
				print "Doing pull\n";
				$solution = $pull;
				last MAIN;
			}
			RWALK:
			next if exists $rseen{$new}; # next direction.
			my $wmoves = $udlr[$dir_num] . $moves;
			$rseen{$new} = $wmoves;
			push @rnext, [$wmoves, $new, $loc[0]];
			next unless exists $fseen{$new};
			print "Rwalk\n";
			$solution = $new;
			last MAIN;
		}

		last BACKWARD if @rtodo;
		use vars qw(*rtodo *rnext);
		(*rtodo, *rnext) = (\@rnext, \@rtodo);
	} # end BACKWARD
}

if( $solution ) {
	my $fmoves = $fseen{$solution};
	my $rmoves = $rseen{$solution};
	print "Solution found!\n";
	print "Time: ", (time() - $^T), " seconds\n";
	print "Moves: $fmoves $rmoves\n";
	print "Move Length: ", length($fmoves . $rmoves), "\n";
	print "Middle Board: \n", printable_board($solution);
} else {
	print "No solution found!\n";
}
__END__


package main

import "fmt"

var moves = [][2]int{
    {-1, -2}, {1, -2}, {-1, 2}, {1, 2}, {-2, -1}, {-2, 1}, {2, -1}, {2, 1},
}

var board1 = " xxx    " +
    " x xx   " +
    " xxxxxxx" +
    "xxx  x x" +
    "x x  xxx" +
    "sxxxxxx " +
    "  xx x  " +
    "   xxx  "

var board2 = ".....s.x....." +
    ".....x.x....." +
    "....xxxxx...." +
    ".....xxx....." +
    "..x..x.x..x.." +
    "xxxxx...xxxxx" +
    "..xx.....xx.." +
    "xxxxx...xxxxx" +
    "..x..x.x..x.." +
    ".....xxx....." +
    "....xxxxx...." +
    ".....x.x....." +
    ".....x.x....."

func solve(pz [][]int, sz, sx, sy, idx, cnt int) bool {
    if idx > cnt {
        return true
    }
    for i := 0; i < len(moves); i++ {
        x := sx + moves[i][0]
        y := sy + moves[i][1]
        if (x >= 0 && x < sz) && (y >= 0 && y < sz) && pz[x][y] == 0 {
            pz[x][y] = idx
            if solve(pz, sz, x, y, idx+1, cnt) {
                return true
            }
            pz[x][y] = 0
        }
    }
    return false
}

func findSolution(b string, sz int) {
    pz := make([][]int, sz)
    for i := 0; i < sz; i++ {
        pz[i] = make([]int, sz)
        for j := 0; j < sz; j++ {
            pz[i][j] = -1
        }
    }
    var x, y, idx, cnt int
    for j := 0; j < sz; j++ {
        for i := 0; i < sz; i++ {
            switch b[idx] {
            case 'x':
                pz[i][j] = 0
                cnt++
            case 's':
                pz[i][j] = 1
                cnt++
                x, y = i, j
            }
            idx++
        }
    }

    if solve(pz, sz, x, y, 2, cnt) {
        for j := 0; j < sz; j++ {
            for i := 0; i < sz; i++ {
                if pz[i][j] != -1 {
                    fmt.Printf("%02d  ", pz[i][j])
                } else {
                    fmt.Print("--  ")
                }
            }
            fmt.Println()
        }
    } else {
        fmt.Println("Cannot solve this puzzle!")
    }
}

func main() {
    findSolution(board1, 8)
    fmt.Println()
    findSolution(board2, 13)
}


file i, o;
tcpip_connect(i, o, "127.0.0.1", 256, 0);
i.text("hello socket world");


Network_Port = 256
Network_Address = 127.0.0.1
NewData := false
DataReceived =
GoSub, Connection_Init
SendData(socket,"hello socket world")
return

Connection_Init:
OnExit, ExitSub

socket := ConnectToAddress(Network_Address, Network_Port)
if socket = -1
    ExitApp

Process, Exist
DetectHiddenWindows On
ScriptMainWindowId := WinExist("ahk_class AutoHotkey ahk_pid " . ErrorLevel)
DetectHiddenWindows Off

NotificationMsg = 0x5556
OnMessage(NotificationMsg, "ReceiveData")

FD_READ = 1
FD_CLOSE = 32
if DllCall("Ws2_32\WSAAsyncSelect", "UInt", socket, "UInt", ScriptMainWindowId, "UInt", NotificationMsg, "Int", FD_READ|FD_CLOSE)
{
    MsgBox % "WSAAsyncSelect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
    ExitApp
}

return

ConnectToAddress(IPAddress, Port)
{
    VarSetCapacity(wsaData, 32)
    result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData)
    if ErrorLevel
    {
        MsgBox WSAStartup() could not be called due to error %ErrorLevel%. Winsock 2.0 or higher is required.
        return -1
    }
    if result
    {
        MsgBox % "WSAStartup() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        return -1
    }
    AF_INET = 2
    SOCK_STREAM = 1
    IPPROTO_TCP = 6
    socket := DllCall("Ws2_32\socket", "Int", AF_INET, "Int", SOCK_STREAM, "Int", IPPROTO_TCP)
    if socket = -1
    {
        MsgBox % "socket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
        return -1
    }
    SizeOfSocketAddress = 16
    VarSetCapacity(SocketAddress, SizeOfSocketAddress)
    InsertInteger(2, SocketAddress, 0, AF_INET)
    InsertInteger(DllCall("Ws2_32\htons", "UShort", Port), SocketAddress, 2, 2)
    InsertInteger(DllCall("Ws2_32\inet_addr", "Str", IPAddress), SocketAddress, 4, 4)
    if DllCall("Ws2_32\connect", "UInt", socket, "UInt", &SocketAddress, "Int", SizeOfSocketAddress)
    {
        MsgBox % "connect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError") . "?"
        return -1
    }
    return socket
}

ReceiveData(wParam, lParam)
{
    global DataReceived
    global NewData
    socket := wParam
    ReceivedDataSize = 4096
    Loop
    {
        VarSetCapacity(ReceivedData, ReceivedDataSize, 0)
        ReceivedDataLength := DllCall("Ws2_32\recv", "UInt", socket, "Str", ReceivedData, "Int", ReceivedDataSize, "Int", 0)
        if ReceivedDataLength = 0
            ExitApp
        if ReceivedDataLength = -1
        {
            WinsockError := DllCall("Ws2_32\WSAGetLastError")
            if WinsockError = 10035
            {
                DataReceived = %TempDataReceived%
                NewData := true
                return 1
            }
            if WinsockError <> 10054
                MsgBox % "recv() indicated Winsock error " . WinsockError
            ExitApp
        }
        if (A_Index = 1)
            TempDataReceived =
        TempDataReceived = %TempDataReceived%%ReceivedData%
    }
    return 1
}

SendData(wParam,SendData)
{
    socket := wParam
    SendDataSize := VarSetCapacity(SendData)
    SendDataSize += 1
    sendret := DllCall("Ws2_32\send", "UInt", socket, "Str", SendData, "Int", SendDatasize, "Int", 0)
}

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
{
    Loop %pSize%
        DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}

ReceiveProcedure:
    if NewData
        GuiControl, , ReceivedText, %DataReceived%
    NewData := false
Return

ExitSub:
DllCall("Ws2_32\WSACleanup")
ExitApp


-- demo\rosetta\Sokoban.exw
integer w, h    -- (set from parsing the input grid)
sequence moves  --    "", as +/-w and +/-1 (udlr)
string live     --    "", Y if box can go there

function reachable(sequence pushes, string level)
    integer p = find_any("@+",level)
    string ok = repeat('N',length(level))
    ok[p] = 'Y'
    while true do
        p = find('Y',ok)
        if p=0 then exit end if
        ok[p] = 'y'
        for i=1 to length(moves) do
            integer pn = p+moves[i]
            if ok[pn]='N'
            and find(level[pn]," .") then
                ok[pn] = 'Y'
            end if
        end for
    end while
    for i=length(pushes)-1 to 1 by -2 do
        if ok[pushes[i]-pushes[i+1]]!='y' then
            pushes[i..i+1] = {}
        end if
    end for
    return pushes
end function

function pushable(string level)
    sequence res = {}
    for i=1 to length(level) do
        if find(level[i],"$*") then
            if  find(level[i-w]," [email protected]+")
            and find(level[i+w]," [email protected]+") then
                if live[i-w]='Y' then res &= {i,-w} end if
                if live[i+w]='Y' then res &= {i,+w} end if
            end if
            if  find(level[i-1]," [email protected]+")
            and find(level[i+1]," [email protected]+") then
                if live[i-1]='Y' then res &= {i,-1} end if
                if live[i+1]='Y' then res &= {i,+1} end if
            end if
        end if
    end for
    return reachable(res,level)
end function

function solve(string level)
    atom t2 = time()+2
    integer seen = new_dict()
    sequence solution = "No solution.", partial = {}
    sequence todo = {{level,partial,pushable(level)}}, pushes
    while length(todo) do
        sequence t1 = todo[1]
        todo = todo[2..$]
        {level,partial,pushes} = t1
        integer p = find_any("@+",level)
        while length(pushes) do
            integer {s,m} = pushes[1..2]
            pushes = pushes[3..$]
            level[p] = " ."[find(level[p],"@+")]
            level[s] = "@+"[find(level[s],"$*")]
            level[s+m] = "$*"[find(level[s+m]," .")]
            if getd_index(level,seen)=0 then
                sequence np = partial&{s,m}
                if not find('$',level) then
                    solution = np
                    todo = {}
                    pushes = {}
                    exit
                end if
                setd(level,true,seen)
                if time()>t2 then
                    printf(1,"working... (seen %d)\r",dict_size(seen))
                    t2 = time()+2
                end if
                todo = append(todo,{level,np,pushable(level)})
            end if
            level = t1[1] -- (reset)
        end while
    end while
    destroy_dict(seen)
    return solution
end function

procedure plays(string level, sequence solution)
-- This plays push-only solutions (see play() for lurd)
    string res = level
    integer p = find_any("@+",level)
    for i=1 to length(solution) by 2 do
        integer {s,m} = solution[i..i+1] m+=s
        level[p] = " ."[find(level[p],"@+")]
        level[s] = "@+"[find(level[s],"$*")]
        level[m] = "$*"[find(level[m]," .")]
        res &= level
        p = s
    end for
    -- (replacing +0 with 1/2/3 may help in some cases)
    puts(1,join_by(split(res,'\n'),h,floor(80/(w+2))+0))
end procedure

procedure mark_live(integer p, string level)
-- (idea cribbed from the C version)
    if live[p]='N' then
        live[p] = 'Y'
        integer l = length(level)
        if p-w*2>=1 and level[p-w]!='#' and level[p-w*2]!='#' then mark_live(p-w,level) end if
        if p+w*2<=l and level[p+w]!='#' and level[p+w*2]!='#' then mark_live(p+w,level) end if
        if p-2  >=1 and level[p-1]!='#' and level[p-2]  !='#' then mark_live(p-1,level) end if
        if p+2  <=l and level[p+1]!='#' and level[p+2]  !='#' then mark_live(p+1,level) end if
    end if
end procedure

function make_square(string level)
--
-- Sets {h, w, moves, live}, and returns an evened-out/rectangular level
--
    if level[$]!='\n' then level &= '\n' end if -- (for the display)
    sequence lines = split(level,'\n')
    h = length(lines)-1             -- set height (ignore trailing \n)
    sequence ln = repeat(0,h)
    for i=1 to h do
        ln[i] = {length(lines[i]),i}
        for j=1 to length(lines[i]) do
            -- validate each line, why not
            if not find(lines[i,j]," #[email protected]*") then
                crash("invalid input")
            end if
        end for
    end for
    ln = sort(ln)
    w = ln[$][1]+1                  -- set width (==longest, inc \n)
    moves = {-w,+w,-1,+1}           -- and make these (udlr) legal ...
    for i=1 to h do
        integer {l,n} = ln[i], pad = w-1-l
        if pad=0 then exit end if
        lines[n] &= repeat(' ',pad) -- ... by evening up the "grid"
    end for
    level = join(lines,'\n')
    live = join(repeat(repeat('N',w-1),h),'\n')
    for p=1 to length(level) do
        if find(level[p],".+*") then
            mark_live(p,level)
        end if
    end for
    return level
end function

constant input = """
#######
#     #
#     #
#. #  #
#. $$ #
#.$$  #
#.#  @#
#######
"""

atom t0 = time()
string level = make_square(input)
sequence pushset = solve(level)
integer pop = length(pushset)/2
if string(pushset) then
    puts(1,level)
    printf(1,"%s\n",{pushset}) -- ("No Solution.")
else
    printf(1,"solution of %d pushes (%s)\n",{pop,elapsed(time()-t0)})
    plays(level,pushset)
end if


(load "@lib/simul.l")

# Display board
(de display ()
   (disp *Board NIL
      '((This)
         (pack
            (if2 (== This *Pos) (memq This *Goals)
               "+"                   # Player on goal
               "@"                   # Player elsewhere
               (if (: val) "*" ".")  # On gloal
               (or (: val) " ") )    # Elsewhere
            " " ) ) ) )

# Initialize
(de main (Lst)
   (mapc
      '((B L)
         (mapc
            '((This C)
               (case C
                  (" ")
                  ("." (push '*Goals This))
                  ("@" (setq *Pos This))
                  ("$" (=: val C) (push '*Boxes This))
                  (T (=: val C)) ) )
               B L ) )
      (setq *Board (grid (length (car Lst)) (length Lst)))
      (apply mapcar (flip (mapcar chop Lst)) list) )
   (display) )

# Generate possible push-moves
(de pushes ()
   (make
      (for Box *Boxes
         (unless (or (; (west Box) val) (; (east Box) val))
            (when (moves (east Box))
               (link (cons (cons Box (west Box)) *Pos "L" @)) )
            (when (moves (west Box))
               (link (cons (cons Box (east Box)) *Pos "R" @)) ) )
         (unless (or (; (south Box) val) (; (north Box) val))
            (when (moves (north Box))
               (link (cons (cons Box (south Box)) *Pos "D" @)) )
            (when (moves (south Box))
               (link (cons (cons Box (north Box)) *Pos "U" @)) ) ) ) ) )

# Moves of player to destination
(de moves (Dst Hist)
   (or
      (== Dst *Pos)
      (mini length
         (extract
            '((Dir)
               (with ((car Dir) Dst)
                  (cond
                     ((== This *Pos) (cons (cdr Dir)))
                     ((: val))
                     ((memq This Hist))
                     ((moves This (cons Dst Hist))
                        (cons (cdr Dir) @) ) ) ) )
            '((west . "r") (east . "l") (south . "u") (north . "d")) ) ) ) )

# Find solution
(de go (Res)
   (unless (idx '*Hist (sort (copy *Boxes)) T)  # No repeated state
      (if (find '((This) (<> "$" (: val))) *Goals)
         (pick
            '((Psh)
               (setq  # Move
                  *Pos (caar Psh)
                  *Boxes (cons (cdar Psh) (delq *Pos *Boxes)) )
               (put *Pos 'val NIL)
               (put (cdar Psh) 'val "$")
               (prog1 (go (append (cddr Psh) Res))
                  (setq  # Undo move
                     *Pos (cadr Psh)
                     *Boxes (cons (caar Psh) (delq (cdar Psh) *Boxes)) )
                  (put (cdar Psh) 'val NIL)
                  (put (caar Psh) 'val "$") ) )
            (pushes) )
         (display)  # Display solution
         (pack (flip Res)) ) ) )


from array import array
from collections import deque
import psyco

data = []
nrows = 0
px = py = 0
sdata = ""
ddata = ""

def init(board):
    global data, nrows, sdata, ddata, px, py
    data = filter(None, board.splitlines())
    nrows = max(len(r) for r in data)

    maps = {' ':' ', '.': '.', '@':' ', '#':'#', '$':' '}
    mapd = {' ':' ', '.': ' ', '@':'@', '#':' ', '$':'*'}

    for r, row in enumerate(data):
        for c, ch in enumerate(row):
            sdata += maps[ch]
            ddata += mapd[ch]
            if ch == '@':
                px = c
                py = r

def push(x, y, dx, dy, data):
    if sdata[(y+2*dy) * nrows + x+2*dx] == '#' or \
       data[(y+2*dy) * nrows + x+2*dx] != ' ':
        return None

    data2 = array("c", data)
    data2[y * nrows + x] = ' '
    data2[(y+dy) * nrows + x+dx] = '@'
    data2[(y+2*dy) * nrows + x+2*dx] = '*'
    return data2.tostring()

def is_solved(data):
    for i in xrange(len(data)):
        if (sdata[i] == '.') != (data[i] == '*'):
            return False
    return True

def solve():
    open = deque([(ddata, "", px, py)])
    visited = set([ddata])
    dirs = ((0, -1, 'u', 'U'), ( 1, 0, 'r', 'R'),
            (0,  1, 'd', 'D'), (-1, 0, 'l', 'L'))

    lnrows = nrows
    while open:
        cur, csol, x, y = open.popleft()

        for di in dirs:
            temp = cur
            dx, dy = di[0], di[1]

            if temp[(y+dy) * lnrows + x+dx] == '*':
                temp = push(x, y, dx, dy, temp)
                if temp and temp not in visited:
                    if is_solved(temp):
                        return csol + di[3]
                    open.append((temp, csol + di[3], x+dx, y+dy))
                    visited.add(temp)
            else:
                if sdata[(y+dy) * lnrows + x+dx] == '#' or \
                   temp[(y+dy) * lnrows + x+dx] != ' ':
                    continue

                data2 = array("c", temp)
                data2[y * lnrows + x] = ' '
                data2[(y+dy) * lnrows + x+dx] = '@'
                temp = data2.tostring()

                if temp not in visited:
                    if is_solved(temp):
                        return csol + di[2]
                    open.append((temp, csol + di[2], x+dx, y+dy))
                    visited.add(temp)

    return "No solution"

level = """\
#######
#     #
#     #
#. #  #
#. $$ #
#.$$  #
#.#  @#
#######"""

psyco.full()
init(level)
print level, "\n\n", solve()


import Data.Array
       (Array, (//), (!), assocs, elems, bounds, listArray)
import Data.Foldable (forM_)
import Data.List (intercalate, transpose)
import Data.Maybe

type Position = (Int, Int)

type KnightBoard = Array Position (Maybe Int)

toSlot :: Char -> Maybe Int
toSlot '0' = Just 0
toSlot '1' = Just 1
toSlot _ = Nothing

toString :: Maybe Int -> String
toString Nothing = replicate 3 ' '
toString (Just n) = replicate (3 - length nn) ' ' ++ nn
  where
    nn = show n

chunksOf :: Int -> [a] -> [[a]]
chunksOf _ [] = []
chunksOf n xs =
  let (chunk, rest) = splitAt n xs
  in chunk : chunksOf n rest

showBoard :: KnightBoard -> String
showBoard board =
  intercalate "\n" . map concat . transpose . chunksOf (height + 1) . map toString $
  elems board
  where
    (_, (_, height)) = bounds board

toBoard :: [String] -> KnightBoard
toBoard strs = board
  where
    height = length strs
    width = minimum (length <$> strs)
    board =
      listArray ((0, 0), (width - 1, height - 1)) . map toSlot . concat . transpose $
      take width <$> strs

add
  :: Num a
  => (a, a) -> (a, a) -> (a, a)
add (a, b) (x, y) = (a + x, b + y)

within
  :: Ord a
  => ((a, a), (a, a)) -> (a, a) -> Bool
within ((a, b), (c, d)) (x, y) = a <= x && x <= c && b <= y && y <= d

-- Enumerate valid moves given a board and a knight's position.
validMoves :: KnightBoard -> Position -> [Position]
validMoves board position = filter isValid plausible
  where
    bound = bounds board
    plausible =
      add position <$>
      [(1, 2), (2, 1), (2, -1), (-1, 2), (-2, 1), (1, -2), (-1, -2), (-2, -1)]
    isValid pos = within bound pos && maybe False (== 0) (board ! pos)

isSolved :: KnightBoard -> Bool
isSolved = all (maybe True (0 /=))

-- Solve the knight's tour with a simple Depth First Search.
solveKnightTour :: KnightBoard -> Maybe KnightBoard
solveKnightTour board = solve board 1 initPosition
  where
    initPosition = fst $ head $ filter ((== Just 1) . snd) $ assocs board
    solve boardA depth position =
      let boardB = boardA // [(position, Just depth)]
      in if isSolved boardB
           then Just boardB
           else listToMaybe $
                mapMaybe (solve boardB $ depth + 1) $ validMoves boardB position

tourExA :: [String]
tourExA =
  [ " 000    "
  , " 0 00   "
  , " 0000000"
  , "000  0 0"
  , "0 0  000"
  , "1000000 "
  , "  00 0  "
  , "   000  "
  ]

tourExB :: [String]
tourExB =
  [ "-----1-0-----"
  , "-----0-0-----"
  , "----00000----"
  , "-----000-----"
  , "--0--0-0--0--"
  , "00000---00000"
  , "--00-----00--"
  , "00000---00000"
  , "--0--0-0--0--"
  , "-----000-----"
  , "----00000----"
  , "-----0-0-----"
  , "-----0-0-----"
  ]

main :: IO ()
main =
  forM_
    [tourExA, tourExB]
    (\board ->
        case solveKnightTour $ toBoard board of
          Nothing -> putStrLn "No solution.\n"
          Just solution -> putStrLn $ showBoard solution ++ "\n")


Func _HelloWorldSocket()
	TCPStartup()
	$Socket = TCPConnect("127.0.0.1", 256)
	TCPSend($Socket, "Hello World")
	TCPCloseSocket($Socket)
	TCPShutdown()
EndFunc


BEGIN {
    s="/inet/tcp/256/0/0"
    print strftime() |& s
    close(s)
}


      INSTALL @lib$+"SOCKLIB"
      PROC_initsockets

      socket% = FN_tcpconnect("localhost", "256")
      IF socket% <=0 ERROR 100, "Failed to open socket"

      REM Don't use FN_writesocket since an error is expected
      msg$ = "hello socket world"
      SYS `send`, socket%, !^msg$, LEN(msg$), 0 TO result%

      PROC_closesocket(socket%)
      PROC_exitsockets


#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

const char *msg = "hello socket world";

int main()
{
   int i, sock, len, slen;

   struct addrinfo hints, *addrs;
   memset(&hints, 0, sizeof(struct addrinfo));
   hints.ai_family = AF_UNSPEC;
   hints.ai_socktype = SOCK_STREAM;

   if (0 == getaddrinfo("localhost", "256", &hints, &addrs))
   {
       sock = socket(addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
       if ( sock >= 0 )
       {
           if ( connect(sock, addrs->ai_addr, addrs->ai_addrlen) >= 0 )
           {
               const char *pm = msg;
               do
               {
                  len = strlen(pm);
                  slen = send(sock, pm, len, 0);
                  pm += slen;
               } while ((0 <= slen) && (slen < len));
           }
           close(sock);
       }
       freeaddrinfo(addrs);
   }
}


#lang racket
(require data/heap
  "../lib/vector2.rkt" "../lib/queue.rkt" (only-in "../lib/util.rkt" push! tstruct ret awhen))

(define level (list "#######"
                    "#     #"
                    "#     #"
                    "#. #  #"
                    "#. $$ #"
                    "#.$$  #"
                    "#.#  @#"
                    "#######"))
(define (strings->vec2 l) (lists->vec2 (map string->list l)))
;turn everything except walls into distance from goals
(define (clear-level l)
  (ret ([l (vec2-copy l)])
    (define dots (vec2-atsq l #\.))
    (define q (list->q (map (λ (p) (cons p 0)) dots)))
    (let bfs () ;this search has implicit history in the mutated vector2
      (unless (nilq? q)
        (match-define (cons p n) (deq! q))
        (define x ([email protected] l p))
        ;stop if position is either a wall or a previously filled number
        (cond [(or (eq? x #\#) (number? x)) (bfs)]
              [else (vec2! l p n)
                    (for-adj l x [p p] #f (enq! (cons p (add1 n)) q))
                    (bfs)])))))

;corresponds to PicoLisp's move table in "moves", while also adding a push direction mapping
(tstruct move (f d))
(define-values (mu md ml mr LURD)
  (let ()
    (define t (map (λ (x) (cons (car x) (apply pos (cdr x))))
                   '([#\u -1 0] [#\d 1 0] [#\l 0 -1] [#\r 0 1])))
    (define (mv d)
      (define x (assoc d t))
      (move (λ (p) (pos+ p (cdr x))) (car x)))
    (values (mv #\u) (mv #\d) (mv #\l) (mv #\r)
            (λ (d) (char-upcase (car (findf (λ (x) (equal? d (cdr x))) t)))))))

;state = player pos * box poses
(tstruct st (p b))
(define (st= s1 s2) (andmap (λ (b) (member b (st-b s2))) (st-b s1)))
(define (box? p s) (member p (st-b s)))
;calculates value of a state for insertion into priority queue
;value is sum of box distances from goals
(define (value s l) (apply + (map (λ (p) ([email protected] l p)) (st-b s))))
;init state for a level
(define (st0 l) (st (vec2-atq l #\@) (vec2-atsq l #\$)))
(define (make-solution-checker l)
  (define dots (vec2-atsq l #\.))
  (λ (s) (andmap (λ (b) (member b dots)) (st-b s))))

;state after push * lurd history
(tstruct push (st h))
(define (pushes s l)
  (ret ([pushes '()])
    (for ([b (in-list (st-b s))])
      (for-adj l a [p b] #f
        (define d (pos- p b)) ;direction of push
        (define op (pos- b d)) ;where player stands to push
        (define o ([email protected] l op))
        ;make sure push pos and push dest are clear
        (when (and (number? a) (number? o)
                   (not (box? p s)) (not (box? op s)))
          (awhen [@ (moves s op l)]
            (define new-st (st b (cons p (remove b (st-b s)))))
            (push! (push new-st (cons (LURD d) @)) pushes)))))))

;state * goal pos * level -> lurd string
(define (moves s g l)
  (define h '())
  (define q (list->q (list (list (st-p s)))))
  (let bfs ()
    (if (nilq? q)
        #f
        (match-let ([(cons p lurd) (deq! q)])
          (cond [(equal? p g) lurd]
                [(or (char=? ([email protected] l p) #\#) (box? p s) (member p h)) (bfs)]
                [else (push! p h)
                      (for-each (λ (m)
                                  (match-define (move f s) m)
                                  (enq! (cons (f p) (cons s lurd)) q))
                                (list mu md ml mr))
                      (bfs)])))))

(define (sokoban l)
  (define-values (clear s0 solved?)
    (let ([l (strings->vec2 l)])
      (values (clear-level l) (st0 l) (make-solution-checker l))))
  (define h '())
  (tstruct q-elem (s lurd v)) ;priority queue stores state, lurd hist, and value
  (define (elem<= s1 s2) (<= (q-elem-v s1) (q-elem-v s2))) ;compare wrapped values
  ;queue stores a single element at the beginning consisting of:
  ;1. starting state, 2. empty lurd history, 3. value of starting state
  (define q (vector->heap elem<= (vector (q-elem s0 '() (value s0 clear)))))
  (let bfs ()
    (match-define (q-elem s lurd _) (heap-min q))
    (heap-remove-min! q)
    (cond [(solved? s) (list->string (reverse lurd))]
          [(memf (λ (s1) (st= s s1)) h) (bfs)]
          [else (push! s h)
                (for-each (λ (p)
                            (define s (push-st p))
                            (heap-add! q (q-elem s (append (push-h p) lurd) (value s clear))))
                          (pushes s clear))
                (bfs)])))


sub MAIN() {
    my $level = q:to//;
#######
#     #
#     #
#. #  #
#. $$ #
#.$$  #
#.#  @#
#######

    say 'level:';
    print $level;
    say 'solution:';
    say solve($level);
}

class State {
    has Str $.board;
    has Str $.sol;
    has Int $.pos;

    method move(Int $delta --> Str) {
        my $new = $!board;
        if $new.substr($!pos,1) eq '@' {
            substr-rw($new,$!pos,1) = ' ';
        } else {
            substr-rw($new,$!pos,1) = '.';
        }
        my $pos := $!pos + $delta;
        if $new.substr($pos,1) eq ' ' {
            substr-rw($new,$pos,1) = '@';
        } else {
            substr-rw($new,$pos,1) = '+';
        }
        return $new;
    }

    method push(Int $delta --> Str) {
        my $pos := $!pos + $delta;
        my $box := $pos + $delta;
        return '' unless $!board.substr($box,1) eq ' ' | '.';
        my $new = $!board;
        if $new.substr($!pos,1) eq '@' {
            substr-rw($new,$!pos,1) = ' ';
        } else {
            substr-rw($new,$!pos,1) = '.';
        }
        if $new.substr($pos,1) eq '$' {
            substr-rw($new,$pos,1) = '@';
        } else {
            substr-rw($new,$pos,1) = '+';
        }
        if $new.substr($box,1) eq ' ' {
            substr-rw($new,$box,1) = '$';
        } else {
            substr-rw($new,$box,1) = '*';
        }
        return $new;
    }
}

sub solve(Str $start --> Str) {
    my $board = $start;
    my $width = $board.lines[0].chars + 1;
    my @dirs =
        ["u", "U", -$width],
        ["r", "R", 1],
        ["d", "D", $width],
        ["l", "L", -1];

    my %visited = $board => True;

    my $pos = $board.index('@');
    my @open = State.new(:$board, :sol(''), :$pos);
    while @open {
        my $state = @open.shift;
        for @dirs -> [$move, $push, $delta] {
            my $board;
            my $sol;
            my $pos = $state.pos + $delta;
            given $state.board.substr($pos,1) {
                when '$' | '*' {
                    $board = $state.push($delta);
                    next if $board eq "" || %visited{$board};
                    $sol = $state.sol ~ $push;
                    return $sol unless $board ~~ /<[ . + ]>/;
                }
                when ' ' | '.' {
                    $board = $state.move($delta);
                    next if %visited{$board};
                    $sol = $state.sol ~ $move;
                }
                default { next }
            }
            @open.push: State.new: :$board, :$sol, :$pos;
            %visited{$board} = True;
        }
    }
    return "No solution";
}


global nCells, cMap, best
record Pos(r,c)

procedure main(A)
    puzzle := showPuzzle("Input",readPuzzle())
    QMouse(puzzle,findStart(puzzle),&null,0)
    showPuzzle("Output", solvePuzzle(puzzle)) | write("No solution!")
end

procedure readPuzzle()
    # Start with a reduced puzzle space
    p := [[-1],[-1]]
    nCells := maxCols := 0
    every line := !&input do {
        put(p,[: -1 | -1 | gencells(line) | -1 | -1 :])
        maxCols <:= *p[-1]
        }
    every put(p, [-1]|[-1])
    # Now normalize all rows to the same length
    every i := 1 to *p do p[i] := [: !p[i] | (|-1\(maxCols - *p[i])) :]
    return p
end

procedure gencells(s)
    static WS, NWS
    initial {
        NWS := ~(WS := " \t")
        cMap := table()     # Map to/from internal model
        cMap["#"] := -1;  cMap["_"] :=  0
        cMap[-1]  := " "; cMap[0]   := "_"
        }

    s ? while not pos(0) do {
            w := (tab(many(WS))|"", tab(many(NWS))) | break
            w := numeric(\cMap[w]|w)
            if -1 ~= w then nCells +:= 1
            suspend w
            }
end

procedure showPuzzle(label, p)
    write(label," with ",nCells," cells:")
    every r := !p do {
        every c := !r do writes(right((\cMap[c]|c),*nCells+1))
        write()
        }
    return p
end

procedure findStart(p)
    if \p[r := !*p][c := !*p[r]] = 1 then return Pos(r,c)
end

procedure solvePuzzle(puzzle)
    if path := \best then {
        repeat {
            loc := path.getLoc()
            puzzle[loc.r][loc.c] := path.getVal()
            path := \path.getParent() | break
            }
        return puzzle
        }
end

class QMouse(puzzle, loc, parent, val)

    method getVal(); return val; end
    method getLoc(); return loc; end
    method getParent(); return parent; end
    method atEnd(); return nCells = val; end

    method visit(r,c)
        if /best & validPos(r,c) then return Pos(r,c)
    end

    method validPos(r,c)
        v := val+1
        xv := (0 <= puzzle[r][c]) | fail
        if xv = (v|0) then {  # make sure this path hasn't already gone there
            ancestor := self
            while xl := (ancestor := \ancestor.getParent()).getLoc() do
                if (xl.r = r) & (xl.c = c) then fail
            return
            }
    end

initially
    val := val+1
    if atEnd() then return best := self
    QMouse(puzzle, visit(loc.r-2,loc.c-1), self, val)
    QMouse(puzzle, visit(loc.r-2,loc.c+1), self, val)
    QMouse(puzzle, visit(loc.r-1,loc.c+2), self, val)
    QMouse(puzzle, visit(loc.r+1,loc.c+2), self, val)
    QMouse(puzzle, visit(loc.r+2,loc.c+1), self, val)
    QMouse(puzzle, visit(loc.r+2,loc.c-1), self, val)
    QMouse(puzzle, visit(loc.r+1,loc.c-2), self, val)
    QMouse(puzzle, visit(loc.r-1,loc.c-2), self, val)
end


using System;
using System.IO;
using System.Net.Sockets;

class Program {
    static void Main(string[] args) {
        TcpClient tcp = new TcpClient("localhost", 256);
        StreamWriter writer = new StreamWriter(tcp.GetStream());

        writer.Write("hello socket world");
        writer.Flush();

        tcp.Close();
    }
}


//compile with g++ main.cpp -lboost_system -pthread

#include <boost/asio.hpp>

int main()
{
  boost::asio::io_context io_context;
  boost::asio::ip::tcp::socket sock(io_context);
  boost::asio::ip::tcp::resolver resolver(io_context);
  boost::asio::ip::tcp::resolver::query query("localhost", "4321");

  boost::asio::connect(sock, resolver.resolve(query));
  boost::asio::write(sock, boost::asio::buffer("Hello world socket\r\n"));

  return 0;
}


var libsocket = @("lib","socket");
// connect
int socket = libsocket.connect("localhost",256);
// send data
{
   sheet data = (sheet)"hello socket world";
   int datalen = data.size();
   int was = libsocket.send(socket,data,0,datalen);
   // assuming here that all data has been sent (if not, send them in some loop)
}
// close socket
libsocket.close(socket);