#include <iostream>
#include <sstream>
#include <iterator>
#include <vector>

//------------------------------------------------------------------------------
using namespace std;

//------------------------------------------------------------------------------
struct node
{
    int val;
    unsigned char neighbors;
};
//------------------------------------------------------------------------------
class hSolver
{
public:
    hSolver()
    {
	dx[0] = -1; dx[1] = 0; dx[2] = 1; dx[3] = -1; dx[4] = 1; dx[5] = -1; dx[6] = 0; dx[7] = 1;
	dy[0] = -1; dy[1] = -1; dy[2] = -1; dy[3] = 0; dy[4] = 0; dy[5] = 1; dy[6] = 1; 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 = 0;
	arr = new node[len]; memset( arr, 0, len * sizeof( node ) );
	weHave = new bool[len + 1]; memset( weHave, 0, len + 1 );

	for( vector<string>::iterator i = puzz.begin(); i != puzz.end(); i++ )
	{
	    if( ( *i ) == "*" ) {    arr[c++].val = -1; continue; }
	    arr[c].val = atoi( ( *i ).c_str() );
	    if( arr[c].val > 0 ) weHave[arr[c].val] = true;
	    if( max < arr[c].val ) max = arr[c].val;
	    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;
	delete [] weHave;
    }

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 );
	if( weHave[w] )
	{
	    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 == w )
		    if( search( a, b, w + 1 ) ) return true;
		}
	    }
	    return false;
	}

	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 m = -1, a, b;
	for( int yy = -1; yy < 2; yy++ )
	    for( int xx = -1; xx < 2; xx++ )
	    {
		if( !yy && !xx ) continue;
		m++; a = x + xx, b = y + yy;
		if( a < 0 || b < 0 || a >= wid || b >= hei ) continue;
		if( arr[a + b * wid].val > -1 ) c |= ( 1 << m );
	    }
	return c;
    }

    void solveIt()
    {
	int x, y; findStart( x, y );
	if( x < 0 ) { cout << "\nCan't find start point!\n"; return; }
	search( x, y, 2 );
    }

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

    int wid, hei, max, dx[8], dy[8];
    node* arr;
    bool* weHave;
};
//------------------------------------------------------------------------------
int main( int argc, char* argv[] )
{
    int wid;
    string p = ". 33 35 . . * * * . . 24 22 . * * * . . . 21 . . * * . 26 . 13 40 11 * * 27 . . . 9 . 1 * * * . . 18 . . * * * * * . 7 . . * * * * * * 5 ."; wid = 8;
    //string p = "54 . 60 59 . 67 . 69 . . 55 . . 63 65 . 72 71 51 50 56 62 . * * * * . . . 14 * * 17 . * 48 10 11 * 15 . 18 . 22 . 46 . * 3 . 19 23 . . 44 . 5 . 1 33 32 . . 43 7 . 36 . 27 . 31 42 . . 38 . 35 28 . 30"; wid = 9;
    //string p = ". 58 . 60 . . 63 66 . 57 55 59 53 49 . 65 . 68 . 8 . . 50 . 46 45 . 10 6 . * * * . 43 70 . 11 12 * * * 72 71 . . 14 . * * * 30 39 . 15 3 17 . 28 29 . . 40 . . 19 22 . . 37 36 . 1 20 . 24 . 26 . 34 33"; wid = 9;

    istringstream iss( p ); vector<string> puzz;
    copy( istream_iterator<string>( iss ), istream_iterator<string>(), back_inserter<vector<string> >( puzz ) );
    hSolver 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 std.stdio, std.array, std.conv, std.algorithm, std.string;

int[][] board;
int[] given, start;

void setup(string s) {
    auto lines = s.splitLines;
    auto cols = lines[0].split.length;
    auto rows = lines.length;
    given.length = 0;

    board = new int[][](rows + 2, cols + 2);
    foreach (row; board)
        row[] = -1;

    foreach (r, row; lines) {
        foreach (c, cell; row.split) {
            switch (cell) {
                case "__":
                    board[r + 1][c + 1] = 0;
                    break;
                case ".":
                    break;
                default:
                    int val = cell.to!int;
                    board[r + 1][c + 1] = val;
                    given ~= val;
                    if (val == 1)
                        start = [r + 1, c + 1];
            }
        }
    }
    given.sort();
}

bool solve(int r, int c, int n, int next = 0) {
    if (n > given.back)
        return true;

    if (board[r][c] && board[r][c] != n)
        return false;

    if (board[r][c] == 0 && given[next] == n)
        return false;

    int back = board[r][c];

    board[r][c] = n;
    foreach (i; -1 .. 2)
        foreach (j; -1 .. 2)
            if (solve(r + i, c + j, n + 1, next + (back == n)))
                return true;

    board[r][c] = back;
    return false;
}

void printBoard() {
    foreach (row; board) {
        foreach (c; row)
            writef(c == -1 ? " . " : c ? "%2d " : "__ ", c);
        writeln;
    }
}

void main() {
    auto hi = "__ 33 35 __ __  .  .  .
                __ __ 24 22 __  .  .  .
                __ __ __ 21 __ __  .  .
                __ 26 __ 13 40 11  .  .
                27 __ __ __  9 __  1  .
                 .  . __ __ 18 __ __  .
                 .  .  .  . __  7 __ __
                 .  .  .  .  .  .  5 __";

    hi.setup;
    printBoard;
    "\nFound:".writeln;
    solve(start[0], start[1], 1);
    printBoard;
}


# Solve a Hidato Like Puzzle with Warnsdorff like logic applied
#
defmodule HLPsolver do
  defmodule Cell do
    defstruct value: -1, used: false, adj: []
  end

  def solve(str, adjacent, print_out\\true) do
    board = setup(str)
    if print_out, do: print(board, "Problem:")
    {start, _} = Enum.find(board, fn {_,cell} -> cell.value==1 end)
    board = set_adj(board, adjacent)
    zbl = for %Cell{value: n} <- Map.values(board), into: %{}, do: {n, true}
    try do
      solve(board, start, 1, zbl, map_size(board))
      IO.puts "No solution"
    catch
      {:ok, result} -> if print_out, do: print(result, "Solution:"),
                                   else: result
    end
  end

  defp solve(board, position, seq_num, zbl, goal) do
    value = board[position].value
    cond do
      value > 0 and value != seq_num -> nil
      value == 0 and zbl[seq_num] -> nil
      true ->
        cell = %Cell{board[position] | value: seq_num, used: true}
        board = %{board | position => cell}
        if seq_num == goal, do: throw({:ok, board})
        Enum.each(wdof(board, cell.adj), fn pos ->
          solve(board, pos, seq_num+1, zbl, goal)
        end)
    end
  end

  defp setup(str) do
    lines = String.strip(str) |> String.split(~r/(\n|\r\n|\r)/) |> Enum.with_index
    for {line,i} <- lines, {char,j} <- Enum.with_index(String.split(line)),
        :error != Integer.parse(char), into: %{} do
          {n,_} = Integer.parse(char)
          {{i,j}, %Cell{value: n}}
        end
  end

  defp set_adj(board, adjacent) do
    Enum.reduce(Map.keys(board), board, fn {x,y},map ->
      adj = Enum.map(adjacent, fn {i,j} -> {x+i, y+j} end)
            |> Enum.reduce([], fn pos,acc -> if board[pos], do: [pos | acc], else: acc end)
      Map.update!(map, {x,y}, fn cell -> %Cell{cell | adj: adj} end)
    end)
  end

  defp wdof(board, adj) do              # Warnsdorf's rule
    Enum.reject(adj, fn pos -> board[pos].used end)
    |> Enum.sort_by(fn pos ->
         Enum.count(board[pos].adj, fn p -> not board[p].used end)
       end)
  end

  def print(board, title) do
    IO.puts "\n#{title}"
    {xmin, xmax} = Map.keys(board) |> Enum.map(fn {x,_} -> x end) |> Enum.min_max
    {ymin, ymax} = Map.keys(board) |> Enum.map(fn {_,y} -> y end) |> Enum.min_max
    len = map_size(board) |> to_char_list |> length
    space = String.duplicate(" ", len)
    Enum.each(xmin..xmax, fn x ->
      Enum.map_join(ymin..ymax, " ", fn y ->
        case Map.get(board, {x,y}) do
          nil  -> space
          cell -> to_string(cell.value) |> String.rjust(len)
        end
      end)
      |> IO.puts
    end)
  end
end


-module( solve_hidato_puzzle ).

-export( [create/2, solve/1, task/0] ).

-compile({no_auto_import,[max/2]}).

create( Grid_list, Number_list ) ->
        Squares = lists:flatten( [create_column(X, Y) || {X, Y} <- Grid_list] ),
	lists:foldl( fun store/2, dict:from_list(Squares), Number_list ).

print( Grid_list ) when is_list(Grid_list) -> print( create(Grid_list, []) );
print( Grid_dict ) ->
    Max_x = max_x( Grid_dict ),
    Max_y = max_y( Grid_dict ),
    Print_row = fun (Y) -> [print(X, Y, Grid_dict) || X <- lists:seq(1, Max_x)], io:nl() end,
    [Print_row(Y) || Y <- lists:seq(1, Max_y)].

solve( Dict ) ->
    {find_start, [Start]} = {find_start, dict:fold( fun start/3, [], Dict )},
    Max = dict:size( Dict ),
    {stop_ok, {Max, Max, [Stop]}} = {stop_ok, dict:fold( fun stop/3, {Max, 0, []}, Dict )},
    My_pid = erlang:self(),
    erlang:spawn( fun() -> path(Start, Stop, Dict, My_pid, []) end ),
    receive
    {grid, Grid, path, Path} -> {Grid, Path}
    end.

task() ->
    %% Square is {X, Y}, N}. N = 0 for empty square. These are created if not present.
    %% Leftmost column is X=1. Top row is Y=1.
    %% Optimised for the example, grid is a list of {X, {Y_min, Y_max}}.
    %% When there are holes, X is repeated as many times as needed with two new Y values each time.
    Start = {{7,5}, 1},
    Stop = {{5,4}, 40},
    Grid_list = [{1, {1,5}}, {2, {1,5}}, {3, {1,6}}, {4, {1,6}}, {5, {1,7}}, {6, {3,7}}, {7, {5,8}}, {8, {7,8}}],
    Number_list = [Start, Stop, {{1,5}, 27}, {{2,1}, 33}, {{2,4}, 26}, {{3,1}, 35}, {{3,2}, 24},
                {{4,2}, 22}, {{4,3}, 21}, {{4,4}, 13}, {{5,5}, 9}, {{5,6}, 18}, {{6,4}, 11}, {{6,7}, 7}, {{7,8}, 5}],
    Grid = create( Grid_list, Number_list ),
    io:fwrite( "Start grid~n" ),
    print( Grid ),
    {New_grid, Path} = solve( create(Grid_list, Number_list) ),
    io:fwrite( "Start square ~p, Stop square ~p.~nPath ~p~n", [Start, Stop, Path] ),
    print( New_grid ).

create_column( X, {Y_min, Y_max} ) -> [{{X, Y}, 0} || Y <- lists:seq(Y_min, Y_max)].

is_filled( Dict ) -> [] =:= dict:fold( fun keep_0_square/3, [], Dict ).

keep_0_square( Key, 0, Acc ) -> [Key | Acc];
keep_0_square(  _Key, _Value, Acc ) -> Acc.

max( Position, Keys ) ->
    [Square | _T] = lists:reverse( lists:keysort(Position, Keys) ),
    Square.

max_x( Dict ) ->
    {X, _Y} = max( 1, dict:fetch_keys(Dict) ),
    X.

max_y( Dict ) ->
    {_X, Y} = max( 2, dict:fetch_keys(Dict) ),
    Y.

neighbourhood( Square, Dict ) ->
        Potentials = neighbourhood_potential_squares( Square ),
	neighbourhood_squares( dict:find(Square, Dict), Potentials, Dict ).

neighbourhood_potential_squares( {X, Y} ) -> [{Sx, Sy} || Sx <- [X-1, X, X+1], Sy <- [Y-1, Y, Y+1], {X, Y} =/= {Sx, Sy}].

neighbourhood_squares( {ok, Value}, Potentials, Dict ) ->
        Square_values = lists:flatten( [neighbourhood_square_value(X, dict:find(X, Dict)) || X <- Potentials] ),
        Next_value = Value + 1,
        neighbourhood_squares_next_value( lists:keyfind(Next_value, 2, Square_values), Square_values, Next_value ).

neighbourhood_squares_next_value( {Square, Value}, _Square_values, Value ) -> [{Square, Value}];
neighbourhood_squares_next_value( false, Square_values, Value ) -> [{Square, Value} || {Square, Y} <- Square_values, Y =:= 0].

neighbourhood_square_value( Square, {ok, Value} ) -> [{Square, Value}];
neighbourhood_square_value( _Square, error ) -> [].

path( Square, Square, Dict, Pid, Path ) -> path_correct( is_filled(Dict), Pid, [Square | Path], Dict );
path( Square, Stop, Dict, Pid, Path ) ->
    Reversed_path = [Square | Path],
    Neighbours = neighbourhood( Square, Dict ),
    [erlang:spawn( fun() -> path(Next_square, Stop, dict:store(Next_square, Value, Dict), Pid, Reversed_path) end ) || {Next_square, Value} <- Neighbours].

path_correct( true, Pid, Path, Dict ) -> Pid ! {grid, Dict, path, lists:reverse( Path )};
path_correct( false, _Pid, _Path, _Dict ) -> dead_end.

print( X, Y, Dict ) -> print_number( dict:find({X, Y}, Dict) ).

print_number( {ok, 0} ) -> io:fwrite( "~3s", ["."] ); % . is less distracting than 0
print_number( {ok, Value} ) -> io:fwrite( "~3b", [Value] );
print_number( error ) -> io:fwrite( "~3s", [" "] ).

start( Key, 1, Acc ) -> [Key | Acc]; % Allow check that we only have one key with value 1.
start( _Key, _Value, Acc ) -> Acc.

stop( Key, Max, {Max, Max_found, Stops} ) -> {Max, erlang:max(Max, Max_found), [Key | Stops]}; % Allow check that we only have one key with value Max.
stop( _Key, Value, {Max, Max_found, Stops} ) -> {Max, erlang:max(Value, Max_found), Stops}. % Allow check that Max is Max.

store( {Key, Value}, Dict ) -> dict:store( Key, Value, Dict ).


package main

import (
    "fmt"
    "sort"
    "strconv"
    "strings"
)

var board [][]int
var start, given []int

func setup(input []string) {
    /* This task is not about input validation, so
       we're going to trust the input to be valid */
    puzzle := make([][]string, len(input))
    for i := 0; i < len(input); i++ {
        puzzle[i] = strings.Fields(input[i])
    }
    nCols := len(puzzle[0])
    nRows := len(puzzle)
    list := make([]int, nRows*nCols)
    board = make([][]int, nRows+2)
    for i := 0; i < nRows+2; i++ {
        board[i] = make([]int, nCols+2)
        for j := 0; j < nCols+2; j++ {
            board[i][j] = -1
        }
    }
    for r := 0; r < nRows; r++ {
        row := puzzle[r]
        for c := 0; c < nCols; c++ {
            switch cell := row[c]; cell {
            case "_":
                board[r+1][c+1] = 0
            case ".":
                break
            default:
                val, _ := strconv.Atoi(cell)
                board[r+1][c+1] = val
                list = append(list, val)
                if val == 1 {
                    start = append(start, r+1, c+1)
                }
            }
        }
    }
    sort.Ints(list)
    given = make([]int, len(list))
    for i := 0; i < len(given); i++ {
        given[i] = list[i]
    }
}

func solve(r, c, n, next int) bool {
    if n > given[len(given)-1] {
        return true
    }

    back := board[r][c]
    if back != 0 && back != n {
        return false
    }

    if back == 0 && given[next] == n {
        return false
    }

    if back == n {
        next++
    }

    board[r][c] = n
    for i := -1; i < 2; i++ {
        for j := -1; j < 2; j++ {
            if solve(r+i, c+j, n+1, next) {
                return true
            }
        }
    }

    board[r][c] = back
    return false
}

func printBoard() {
    for _, row := range board {
        for _, c := range row {
            switch {
            case c == -1:
                fmt.Print(" . ")
            case c > 0:
                fmt.Printf("%2d ", c)
            default:
                fmt.Print("__ ")
            }
        }
        fmt.Println()
    }
}

func main() {
    input := []string{
        "_ 33 35 _ _ . . .",
        "_ _ 24 22 _ . . .",
        "_ _ _ 21 _ _ . .",
        "_ 26 _ 13 40 11 . .",
        "27 _ _ _ 9 _ 1 .",
        ". . _ _ 18 _ _ .",
        ". . . . _ 7 _ _",
        ". . . . . . 5 _",
    }
    setup(input)
    printBoard()
    fmt.Println("\nFound:")
    solve(start[0], start[1], 1, 0)
    printBoard()
}


{-# LANGUAGE TupleSections #-}
{-# LANGUAGE Rank2Types #-}

import qualified Data.IntMap as I
import Data.IntMap (IntMap)
import Data.List
import Data.Maybe
import Data.Time.Clock

data BoardProblem = Board
  { cells :: IntMap (IntMap Int)
  , endVal :: Int
  , onePos :: (Int, Int)
  , givens :: [Int]
  } deriving (Show, Eq)

tupIns x y v m = I.insert x (I.insert y v (I.findWithDefault I.empty x m)) m

tupLookup x y m = I.lookup x m >>= I.lookup y

makeBoard =
  (\x ->
      x
      { givens = dropWhile (<= 1) $ sort $ givens x
      }) .
  foldl' --'
    f
    (Board I.empty 0 (0, 0) []) .
  concatMap (zip [0 ..]) . zipWith (\y w -> map (y, ) $ words w) [0 ..]
  where
    f bd (x, (y, v)) =
      if v == "."
        then bd
        else Board
               (tupIns x y (read v) (cells bd))
               (if read v > endVal bd
                  then read v
                  else endVal bd)
               (if v == "1"
                  then (x, y)
                  else onePos bd)
               (read v : givens bd)

hidato brd = listToMaybe $ h 2 (cells brd) (onePos brd) (givens brd)
  where
    h nval pmap (x, y) gs
      | nval == endVal brd = [pmap]
      | nval == head gs =
        if null nvalAdj
          then []
          else h (nval + 1) pmap (fst $ head nvalAdj) (tail gs)
      | not $ null nvalAdj = h (nval + 1) pmap (fst $ head nvalAdj) gs
      | otherwise = hEmptyAdj
      where
        around =
          [ (x - 1, y - 1)
          , (x, y - 1)
          , (x + 1, y - 1)
          , (x - 1, y)
          , (x + 1, y)
          , (x - 1, y + 1)
          , (x, y + 1)
          , (x + 1, y + 1)
          ]
        lkdUp = map (\(x, y) -> ((x, y), tupLookup x y pmap)) around
        nvalAdj = filter ((== Just nval) . snd) lkdUp
        hEmptyAdj =
          concatMap
            (\((nx, ny), _) -> h (nval + 1) (tupIns nx ny nval pmap) (nx, ny) gs) $
          filter ((== Just 0) . snd) lkdUp

printCellMap cellmap = putStrLn $ concat strings
  where
    maxPos = xyBy I.findMax maximum
    minPos = xyBy I.findMin minimum
    xyBy :: (forall a. IntMap a -> (Int, a)) -> ([Int] -> Int) -> (Int, Int)
    xyBy a b = (fst (a cellmap), b $ map (fst . a . snd) $ I.toList cellmap)
    strings =
      map
        f
        [ (x, y)
        | y <- [snd minPos .. snd maxPos]
        , x <- [fst minPos .. fst maxPos] ]
    f (x, y) =
      let z =
            if x == fst maxPos
              then "\n"
              else " "
      in case tupLookup x y cellmap of
           Nothing -> "  " ++ z
           Just n ->
             (if n < 10
                then ' ' : show n
                else show n) ++
             z

main = do
  let sampleBoard = makeBoard sample
  printCellMap $ cells sampleBoard
  printCellMap $ fromJust $ hidato sampleBoard

sample =
  [ " 0 33 35  0  0"
  , " 0  0 24 22  0"
  , " 0  0  0 21  0  0"
  , " 0 26  0 13 40 11"
  , "27  0  0  0  9  0  1"
  , ".  .   0  0 18  0  0"
  , ".  .  .  .   0  7  0  0"
  , ".  .  .  .  .  .   5  0"
  ]


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]]
    nCells := maxCols := 0
    every line := !&input do {
        put(p,[: -1 | gencells(line) | -1 :])
        maxCols <:= *p[-1]
        }
    put(p, [-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) = puzzle[loc.r][loc.c]; end
    method goNorth(); return visit(loc.r-1,loc.c);   end
    method goNE();    return visit(loc.r-1,loc.c+1); end
    method goEast();  return visit(loc.r,  loc.c+1); end
    method goSE();    return visit(loc.r+1,loc.c+1); end
    method goSouth(); return visit(loc.r+1,loc.c);   end
    method goSW();    return visit(loc.r+1,loc.c-1); end
    method goWest();  return visit(loc.r,  loc.c-1); end
    method goNW();    return visit(loc.r-1,loc.c-1); end

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

    method validPos(r,c)
        xv := puzzle[r][c]
        if xv = (val+1) then return
        if xv = 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 +:= 1
    if atEnd() then return best := self
    QMouse(puzzle, goNorth(), self, val)
    QMouse(puzzle, goNE(),    self, val)
    QMouse(puzzle, goEast(),  self, val)
    QMouse(puzzle, goSE(),    self, val)
    QMouse(puzzle, goSouth(), self, val)
    QMouse(puzzle, goSW(),    self, val)
    QMouse(puzzle, goWest(),  self, val)
    QMouse(puzzle, goNW(),    self, val)
end


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Hidato {

    private static int[][] board;
    private static int[] given, start;

    public static void main(String[] args) {
        String[] input = {"_ 33 35 _ _ . . .",
            "_ _ 24 22 _ . . .",
            "_ _ _ 21 _ _ . .",
            "_ 26 _ 13 40 11 . .",
            "27 _ _ _ 9 _ 1 .",
            ". . _ _ 18 _ _ .",
            ". . . . _ 7 _ _",
            ". . . . . . 5 _"};

        setup(input);
        printBoard();
        System.out.println("\nFound:");
        solve(start[0], start[1], 1, 0);
        printBoard();
    }

    private static void setup(String[] input) {
        /* This task is not about input validation, so
           we're going to trust the input to be valid */

        String[][] puzzle = new String[input.length][];
        for (int i = 0; i < input.length; i++)
            puzzle[i] = input[i].split(" ");

        int nCols = puzzle[0].length;
        int nRows = puzzle.length;

        List<Integer> list = new ArrayList<>(nRows * nCols);

        board = new int[nRows + 2][nCols + 2];
        for (int[] row : board)
            for (int c = 0; c < nCols + 2; c++)
                row[c] = -1;

        for (int r = 0; r < nRows; r++) {
            String[] row = puzzle[r];
            for (int c = 0; c < nCols; c++) {
                String cell = row[c];
                switch (cell) {
                    case "_":
                        board[r + 1][c + 1] = 0;
                        break;
                    case ".":
                        break;
                    default:
                        int val = Integer.parseInt(cell);
                        board[r + 1][c + 1] = val;
                        list.add(val);
                        if (val == 1)
                            start = new int[]{r + 1, c + 1};
                }
            }
        }
        Collections.sort(list);
        given = new int[list.size()];
        for (int i = 0; i < given.length; i++)
            given[i] = list.get(i);
    }

    private static boolean solve(int r, int c, int n, int next) {
        if (n > given[given.length - 1])
            return true;

        if (board[r][c] != 0 && board[r][c] != n)
            return false;

        if (board[r][c] == 0 && given[next] == n)
            return false;

        int back = board[r][c];
        if (back == n)
            next++;

        board[r][c] = n;
        for (int i = -1; i < 2; i++)
            for (int j = -1; j < 2; j++)
                if (solve(r + i, c + j, n + 1, next))
                    return true;

        board[r][c] = back;
        return false;
    }

    private static void printBoard() {
        for (int[] row : board) {
            for (int c : row) {
                if (c == -1)
                    System.out.print(" . ");
                else
                    System.out.printf(c > 0 ? "%2d " : "__ ", c);
            }
            System.out.println();
        }
    }
}


module Hidato

export hidatosolve, printboard, hidatoconfigure

function hidatoconfigure(str)
    lines = split(str, "\n")
    nrows, ncols = length(lines), length(split(lines[1], r"\s+"))
    board = fill(-1, (nrows, ncols))
    presets = Vector{Int}()
    starts = Vector{CartesianIndex{2}}()
    maxmoves = 0
    for (i, line) in enumerate(lines), (j, s) in enumerate(split(strip(line), r"\s+"))
        c = s[1]
        if c == '_' || (c == '0' && length(s) == 1)
            board[i, j] = 0
            maxmoves += 1
        elseif c == '.'
            continue
        else # numeral, get 2 digits
            board[i, j] = parse(Int, s)
            push!(presets, board[i, j])
            if board[i, j] == 1
                push!(starts, CartesianIndex(i, j))
            end
            maxmoves += 1
        end
    end
    board, maxmoves, sort!(presets), length(starts) == 1 ? starts : findall(x -> x == 0, board)
end

function hidatosolve(board, maxmoves, movematrix, fixed, row, col, sought)
    if sought > maxmoves
        return true
    elseif (0 != board[row, col] != sought) || (board[row, col] == 0 && sought in fixed)
        return false
    end
    backnum = board[row, col] == sought ? sought : 0
    board[row, col] = sought # try board with this cell set to next number
    for move in movematrix
        i, j = row + move[1], col + move[2]
        if (0 < i <= size(board)[1]) && (0 < j <= size(board)[2]) &&
            hidatosolve(board, maxmoves, movematrix, fixed, i, j, sought + 1)
            return true
        end
    end
    board[row, col] = backnum # return board to original state
    false
end

function printboard(board, emptysquare= "__ ", blocked = "   ")
    d = Dict(-1 => blocked, 0 => emptysquare, -2 => "\n")
    map(x -> d[x] = rpad(lpad(string(x), 2), 3), 1:maximum(board))
    println(join([d[i] for i in hcat(board, fill(-2, size(board)[1]))'], ""))
end

end  # module


// version 1.2.0

lateinit var board: List<IntArray>
lateinit var given: IntArray
lateinit var start: IntArray

fun setUp(input: List<String>) {
    val nRows = input.size
    val puzzle = List(nRows) { input[it].split(" ") }
    val nCols = puzzle[0].size
    val list = mutableListOf<Int>()
    board = List(nRows + 2) { IntArray(nCols + 2) { -1 } }
    for (r in 0 until nRows) {
        val row = puzzle[r]
        for (c in 0 until nCols) {
            val cell = row[c]
            if (cell == "_") {
                board[r + 1][c + 1] = 0
            }
            else if (cell != ".") {
                val value = cell.toInt()
                board[r + 1][c + 1] = value
                list.add(value)
                if (value == 1) start = intArrayOf(r + 1, c + 1)
            }
        }
    }
    list.sort()
    given = list.toIntArray()
}

fun solve(r: Int, c: Int, n: Int, next: Int): Boolean {
    if (n > given[given.lastIndex]) return true
    val back = board[r][c]
    if (back != 0 && back != n) return false
    if (back == 0 && given[next] == n) return false
    var next2 = next
    if (back == n) next2++
    board[r][c] = n
    for (i in -1..1)
        for (j in -1..1)
            if (solve(r + i, c + j, n + 1, next2)) return true
    board[r][c] = back
    return false
}

fun printBoard() {
    for (row in board) {
        for (c in row) {
            if (c == -1)
                print(" . ")
            else
                print(if (c > 0) "%2d ".format(c) else "__ ")
        }
        println()
    }
}

fun main(args: Array<String>) {
    var input = listOf(
        "_ 33 35 _ _ . . .",
        "_ _ 24 22 _ . . .",
        "_ _ _ 21 _ _ . .",
        "_ 26 _ 13 40 11 . .",
        "27 _ _ _ 9 _ 1 .",
        ". . _ _ 18 _ _ .",
        ". . . . _ 7 _ _",
        ". . . . . . 5 _"
    )
    setUp(input)
    printBoard()
    println("\nFound:")
    solve(start[0], start[1], 1, 0)
    printBoard()
}


/*Hidato.mathprog, part of KuKu by Nigel Galloway

  Find a solution to a Hidato problem

  [email protected]
  April 1st., 2011
*/

param ZBLS;
param ROWS;
param COLS;
param D := 1;
set ROWSR := 1..ROWS;
set COLSR := 1..COLS;
set ROWSV := (1-D)..(ROWS+D);
set COLSV := (1-D)..(COLS+D);
param Iz{ROWSR,COLSR}, integer, default 0;
set ZBLSV := 1..(ZBLS+1);
set ZBLSR := 1..ZBLS;

var BR{ROWSV,COLSV,ZBLSV}, binary;

void0{r in ROWSV, z in ZBLSR,c in (1-D)..0}: BR[r,c,z] = 0;
void1{r in ROWSV, z in ZBLSR,c in (COLS+1)..(COLS+D)}: BR[r,c,z] = 0;
void2{c in COLSV, z in ZBLSR,r in (1-D)..0}: BR[r,c,z] = 0;
void3{c in COLSV, z in ZBLSR,r in (ROWS+1)..(ROWS+D)}: BR[r,c,z] = 0;
void4{r in ROWSV,c in (1-D)..0}: BR[r,c,ZBLS+1] = 1;
void5{r in ROWSV,c in (COLS+1)..(COLS+D)}: BR[r,c,ZBLS+1] = 1;
void6{c in COLSV,r in (1-D)..0}: BR[r,c,ZBLS+1] = 1;
void7{c in COLSV,r in (ROWS+1)..(ROWS+D)}: BR[r,c,ZBLS+1] = 1;

Izfree{r in ROWSR, c in COLSR, z in ZBLSR : Iz[r,c] = -1}: BR[r,c,z] = 0;
Iz1{Izr in ROWSR, Izc in COLSR, r in ROWSR, c in COLSR, z in ZBLSR : Izr=r and Izc=c and Iz[Izr,Izc]=z}: BR[r,c,z] = 1;

rule1{z in ZBLSR}: sum{r in ROWSR, c in COLSR} BR[r,c,z] = 1;
rule2{r in ROWSR, c in COLSR}: sum{z in ZBLSV} BR[r,c,z] = 1;
rule3{r in ROWSR, c in COLSR, z in ZBLSR}: BR[0,0,z+1] + BR[r-1,c-1,z+1] + BR[r-1,c,z+1] + BR[r-1,c+1,z+1] + BR[r,c-1,z+1] + BR[r,c+1,z+1] + BR[r+1,c-1,z+1] + BR[r+1,c,z+1] + BR[r+1,c+1,z+1] - BR[r,c,z] >= 0;

solve;

for {r in ROWSR} {
    for {c in COLSR} {
        printf " %2d", sum{z in ZBLSR} BR[r,c,z]*z;
    }
    printf "\n";
}
data;

param ROWS := 8;
param COLS := 8;
param ZBLS := 40;
param
Iz: 1   2   3   4   5   6   7   8 :=
 1  .  33  35   .   .  -1  -1  -1
 2  .   .  24  22   .  -1  -1  -1
 3  .   .   .  21   .   .  -1  -1
 4  .  26   .  13  40  11  -1  -1
 5 27   .   .   .   9   .   1  -1
 6 -1  -1   .   .  18   .   .  -1
 7 -1  -1  -1  -1   .   7   .   .
 8 -1  -1  -1  -1  -1  -1   5   .
 ;

 end;


ClearAll[NeighbourQ, CellDistance, VisualizeHidato, HiddenSingle, \
NakedN, HiddenN, ChainSearch, HidatoSolve, Cornering, ValidPuzzle, \
GapSearch, ReachDelete, GrowNeighbours]
NeighbourQ[cell1_, cell2_] := (CellDistance[cell1, cell2] === 1)
ValidPuzzle[cells_List, cands_List] :=
 MemberQ[cands, {1}] \[And] MemberQ[cands, {Length[cells]}] \[And]
  Length[cells] == Length[candidates] \[And]
  MinMax[Flatten[cands]] === {1,
    Length[cells]} \[And] (Union @@ cands === Range[Length[cells]])
CellDistance[cell1_, cell2_] := ChessboardDistance[cell1, cell2]
VisualizeHidato[cells_List, cands_List] := Module[{grid, nums, cb, hx},
  grid = {EdgeForm[Thick],
    MapThread[
     If[Length[#2] > 1, {FaceForm[],
        Rectangle[#1]}, {FaceForm[LightGray],
        Rectangle[#1]}] &, {cells, cands}]};
  nums =
   MapThread[
    If[Length[#1] == 1, Text[Style[First[#1], 16], #2 + 0.5 {1, 1}],
      Text[
       Tooltip[Style[Length[#1], Red, 10], #1], #2 +
        0.5 {1, 1}]] &, {cands, cells}];
  cb = CoordinateBounds[cells];
  Graphics[{grid, nums}, PlotRange -> cb + {{-0.5, 1.5}, {-0.5, 1.5}},
    ImageSize -> 60 (1 + cb[[1, 2]] - cb[[1, 1]])]
  ]
HiddenSingle[cands_List] := Module[{singles, newcands = cands},
  singles = Cases[Tally[Flatten[cands]], {_, 1}];
  If[Length[singles] > 0,
   singles = Sort[singles[[All, 1]]];
   newcands =
    If[ContainsAny[#, singles], Intersection[#, singles], #] & /@
     newcands;
   newcands
   ,
   cands
   ]
  ]
HiddenN[cands_List, n_Integer?(# > 1 &)] := Module[{tmp, out},
  tmp = cands;
  tmp = Join @@ MapIndexed[{#1, First[#2]} &, tmp, {2}];
  tmp = Transpose /@ GatherBy[tmp, First];
  tmp[[All, 1]] = tmp[[All, 1, 1]];
  tmp = Select[tmp, 2 <= Length[Last[#]] <= n &];
  If[Length[tmp] > 0,
   tmp = Transpose /@ Subsets[tmp, {n}];
   tmp[[All, 2]] = Union @@@ tmp[[All, 2]];
   tmp = Select[tmp, Length[Last[#]] == n &];
   If[Length[tmp] > 0,
    (* for each tmp {cands,
    cells} in each of the cells delete everything except the cands *)

        out = cands;
    Do[
     Do[
      out[[c]] = Select[out[[c]], MemberQ[t[[1]], #] &];
      ,
      {c, t[[2]]}
      ]
     ,
     {t, tmp}
     ];
    out
    ,
    cands
    ]
   ,
   cands
   ]
  ]
NakedN[cands_List, n_Integer?(# > 1 &)] := Module[{tmp, newcands, ids},
  tmp = {Range[Length[cands]], cands}\[Transpose];
  tmp = Select[tmp, 2 <= Length[Last[#]] <= n &];
  If[Length[tmp] > 0,
   tmp = Transpose /@ Subsets[tmp, {n}];
   tmp[[All, 2]] = Union @@@ tmp[[All, 2]];
   tmp = Select[tmp, Length[Last[#]] == n &];
   If[Length[tmp] > 0,
    newcands = cands;
    Do[
     ids = Complement[Range[Length[newcands]], t[[1]]];
     newcands[[ids]] =
      DeleteCases[newcands[[ids]],
       Alternatives @@ t[[2]], \[Infinity]];
     ,
     {t, tmp}
     ];
    newcands
    ,
    cands
    ]
   ,
   cands
   ]
  ]
Cornering[cells_List, cands_List] :=
 Module[{newcands, neighbours, filled, neighboursfiltered, cellid,
   filledneighours, begin, end, beginend},
  filled = Flatten[MapIndexed[If[Length[#1] == 1, #2, {}] &, cands]];
  begin = If[MemberQ[cands, {1}], {}, {1}];
  end = If[MemberQ[cands, {Length[cells]}], {}, {Length[cells]}];
  beginend = Join[begin, end];
  neighbours = Outer[NeighbourQ, cells, cells, 1];
  neighbours =
   Association[
    MapIndexed[
     First[#2] -> {Complement[Flatten[Position[#1, True]], filled],
        Intersection[Flatten[Position[#1, True]], filled]} &,
     neighbours]];
  KeyDropFrom[neighbours, filled];
  neighbours = Select[neighbours, Length[First[#]] == 1 &];
  If[Length[neighbours] > 0,
   newcands = cands;
   neighbours = KeyValueMap[List, neighbours];
   Do[
    cellid = n[[1]];
    filledneighours = n[[2, 2]];
    filledneighours = Join @@ cands[[filledneighours]];
    filledneighours =
     Union[filledneighours - 1, filledneighours + 1];
    filledneighours = Union[filledneighours, beginend];
    newcands[[cellid]] =
     Intersection[newcands[[cellid]], filledneighours];
    ,
    {n, neighbours}
    ];
   newcands
   ,
   cands
   ]
  ]
ChainSearch[cells_, cands_] := Module[{neighbours, sols, out},
  neighbours = Outer[NeighbourQ, cells, cells, 1];
  neighbours =
   Association[
    MapIndexed[First[#2] -> Flatten[Position[#1, True]] &,
     neighbours]];
  sols = Reap[ChainSearch[neighbours, cands, {}];][[2]];
  If[Length[sols] > 0,
   sols = sols[[1]];
   If[Length[sols] > 1,
    Print["multiple solutions found, showing first"];
    ];
   sols = First[sols];
   out = cands;
   out[[sols]] = List /@ Range[Length[out]];
   out
   ,
   cands
   ]
  ]
ChainSearch[neighbours_, cands_List, solcellids_List] :=
 Module[{largest, largestid, next, poss},
  largest = Length[solcellids];
  largestid = Last[solcellids, 0];
  If[largest < Length[cands],
   next = largest + 1;
   poss =
    Flatten[MapIndexed[If[MemberQ[#1, next], First[#2], {}] &, cands]];
   If[Length[poss] > 0,
    If[largest > 0,
     poss = Intersection[poss, neighbours[largestid]];
     ];
    poss = Complement[poss, solcellids]; (* can't be in previous path*)

        If[Length[poss] > 0, (* there are 'next' ones iterate over,
     calling this function *)
     Do[
      ChainSearch[neighbours, cands, Append[solcellids, p]]
      ,
      {p, poss}
      ]
     ]
    ,
    Print["There should be a next!"];
    Abort[];
    ]
   ,
   Sow[solcellids] (*
   we found a solution with this ordering of cells *)
   ]
  ]
GrowNeighbours[neighbours_, set_List] :=
 Module[{lastdone, ids, newneighbours, old},
  old = Join @@ set[[All, All, 1]];
  lastdone = Last[set];
  ids = lastdone[[All, 1]];
  newneighbours = Union @@ (neighbours /@ ids);
  newneighbours = Complement[newneighbours, old]; (*only new ones*)

  If[Length[newneighbours] > 0,
   Append[set, Thread[{newneighbours, lastdone[[1, 2]] + 1}]]
   ,
   set
   ]
  ]
ReachDelete[cells_List, cands_List, neighbours_, startid_] :=
 Module[{seed, distances, val, newcands},
  If[MatchQ[cands[[startid]], {_}],
   val = cands[[startid, 1]];
   seed = {{{startid, 0}}};
   distances =
    Join @@ FixedPoint[GrowNeighbours[neighbours, #] &, seed];
   If[Length[distances] > 0,
    distances = Select[distances, Last[#] > 0 &];
    If[Length[distances] > 0,
     newcands = cands;
     distances[[All, 2]] =
      Transpose[
       val + Outer[Times, {-1, 1}, distances[[All, 2]] - 1]];
     Do[newcands[[\[CurlyPhi][[1]]]] =
        Complement[newcands[[\[CurlyPhi][[1]]]],
         Range @@ \[CurlyPhi][[2]]];
      , {\[CurlyPhi], distances}
      ];
     newcands
     ,
     cands
     ]
    ,
    cands
    ]
   ,
   Print["invalid starting point for neighbour search"];
   Abort[];
   ]
  ]
GapSearch[cells_List, cands_List] :=
 Module[{givensid, givens, neighbours},
  givensid = Flatten[Position[cands, {_}]];
  givens = {cells[[givensid]], givensid,
     Flatten[cands[[givensid]]]}\[Transpose];
  If[Length[givens] > 0,
   givens = SortBy[givens, Last];
   givens = Split[givens, Last[#2] == Last[#1] + 1 &];
   givens = If[Length[#] <= 2, #, #[[{1, -1}]]] & /@ givens;
   If[Length[givens] > 0,
    givens = Join @@ givens;
    If[Length[givens] > 0,
     neighbours = Outer[NeighbourQ, cells, cells, 1];
     neighbours =
      Association[
       MapIndexed[First[#2] -> Flatten[Position[#1, True]] &,
        neighbours]];
     givens = givens[[All, 2]];
     Fold[ReachDelete[cells, #1, neighbours, #2] &, cands, givens]
     ,
     cands
     ]
    ,
    cands
    ]
   ,
   cands
   ]
  ]
HidatoSolve[cells_List, cands_List] :=
 Module[{newcands = cands, old},
  If[ValidPuzzle[cells, cands] \[Or] 1 == 1,
   old = -1;
   newcands = GapSearch[cells, newcands];
   While[old =!= newcands,
    old = newcands;
    newcands = GapSearch[cells, newcands];
    If[old === newcands,
     newcands = HiddenSingle[newcands];
     If[old === newcands,
      newcands = NakedN[newcands, 2];
      newcands = HiddenN[newcands, 2];
      If[old === newcands,
       newcands = NakedN[newcands, 3];
       newcands = HiddenN[newcands, 3];
       If[old === newcands,
        newcands = Cornering[cells, newcands];
        If[old === newcands,
         newcands = NakedN[newcands, 4];
         newcands = HiddenN[newcands, 4];
         If[old === newcands,
          newcands = NakedN[newcands, 5];
          newcands = HiddenN[newcands, 5];
          If[old === newcands,
           newcands = NakedN[newcands, 6];
           newcands = HiddenN[newcands, 6];
           If[old === newcands,
            newcands = NakedN[newcands, 7];
            newcands = HiddenN[newcands, 7];
            If[old === newcands,
             newcands = NakedN[newcands, 8];
             newcands = HiddenN[newcands, 8];
             ]
            ]
           ]
          ]
         ]
        ]
       ]
      ]
     ]
    ];
   If[Length[Flatten[newcands]] > Length[newcands], (*
    if not solved do a depth-first brute force search*)

    newcands = ChainSearch[cells, newcands];
    ];
   (*[email protected][cells,newcands];*)
   newcands
   ,
   Print[
    "There seems to be something wrong with your Hidato puzzle. Check \
if the begin and endpoints are given, the cells and candidates have \
the same length, all the numbers are among the \
candidates\[Ellipsis]"]
   ]
  ]
cells = {{1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8}, {2, 4}, {2, 5}, {2,
   6}, {2, 7}, {2, 8}, {3, 3}, {3, 4}, {3, 5}, {3, 6}, {3, 7}, {3,
   8}, {4, 3}, {4, 4}, {4, 5}, {4, 6}, {4, 7}, {4, 8}, {5, 2}, {5,
   3}, {5, 4}, {5, 5}, {5, 6}, {5, 7}, {5, 8}, {6, 2}, {6, 3}, {6,
   4}, {6, 5}, {6, 6}, {7, 1}, {7, 2}, {7, 3}, {7, 4}, {8, 1}, {8,
   2}}; (* cartesian coordinates of the cells *)
candidates =
 ConstantArray[[email protected][cells],
  Length[
   cells]]; (* all the cells start with candidates 1 through 40 *)

hints = {
   {{1, 4}, {27}},
   {{2, 5}, {26}},
   {{7, 1}, {5}},
   {{6, 2}, {7}},
   {{5, 3}, {18}},
   {{5, 4}, {9}},
   {{5, 5}, {40}},
   {{6, 5}, {11}},
   {{4, 5}, {13}},
   {{4, 6}, {21}},
   {{4, 7}, {22}},
   {{3, 7}, {24}},
   {{3, 8}, {35}},
   {{2, 8}, {33}},
   {{7, 4}, {1}}
   };
indices = Flatten[Position[cells, #] & /@ hints[[All, 1]]];
candidates[[indices]] = hints[[All, 2]];
VisualizeHidato[cells, candidates]
out = HidatoSolve[cells, candidates];
VisualizeHidato[cells, out]


import strutils, algorithm, sequtils, strformat

type Hidato = object
       board: seq[seq[int]]
       given: seq[int]
       start: (int, int)

proc initHidato(s: string): Hidato =
  var lines = s.splitLines()
  let cols = lines[0].splitWhitespace().len()
  let rows = lines.len()
  result.board = newSeqWith(rows + 2, newSeq[int](cols + 2))  # Make room for borders.

  for i in 0 .. result.board.high:
    for j in 0 .. result.board[0].high:
      result.board[i][j] = -1

  for r, row in lines:
    for c, cell in row.splitWhitespace().pairs():
      case cell
      of "__" :
        result.board[r + 1][c + 1] = 0
        continue
      of "." :
        continue
      else :
        let val = parseInt(cell)
        result.board[r + 1][c + 1] = val
        result.given.add(val)
        if val == 1:
          result.start = (r + 1, c + 1)
  result.given.sort()

proc solve(hidato: var Hidato; r, c, n: int; next = 0): bool =
  if n > hidato.given[^1]:
    return true
  if hidato.board[r][c] < 0:
    return false
  if hidato.board[r][c] > 0 and hidato.board[r][c] != n:
    return false
  if hidato.board[r][c] == 0 and hidato.given[next] == n:
    return false

  let back = hidato.board[r][c]
  hidato.board[r][c] = n
  for i in -1 .. 1:
    for j in -1 .. 1:
      if back == n:
        if hidato.solve(r + i, c + j, n + 1, next + 1): return true
      else:
        if hidato.solve(r + i, c + j, n + 1, next): return true
  hidato.board[r][c] = back
  result = false

proc print(hidato: Hidato) =
  for row in hidato.board:
    for val in row:
      stdout.write if val == -1: " . " elif val == 0: "__ " else: &"{val:2} "
    writeLine(stdout, "")

const Hi = """
__ 33 35 __ __  .  .  .
__ __ 24 22 __  .  .  .
__ __ __ 21 __ __  .  .
__ 26 __ 13 40 11  .  .
27 __ __ __  9 __  1  .
 .  . __ __ 18 __ __  .
 .  .  .  . __  7 __ __
 .  .  .  .  .  .  5 __"""

var hidato = initHidato(Hi)
hidato.print()
echo("")
echo("Found:")
discard hidato.solve(hidato.start[0], hidato.start[1], 1)
hidato.print()


with javascript_semantics
sequence board, warnsdorffs, knownx, knowny

integer width, height, limit, nchars, tries
string fmt, blank

constant ROW = 1, COL = 2
constant moves = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}}

function onboard(integer row, integer col)
    return row>=1 and row<=height and col>=nchars and col<=nchars*width
end function

procedure init_warnsdorffs()
integer nrow,ncol
    for row=1 to height do
        for col=nchars to nchars*width by nchars do
            for move=1 to length(moves) do
                nrow = row+moves[move][ROW]
                ncol = col+moves[move][COL]*nchars
                if onboard(nrow,ncol)
                and board[nrow][ncol]='_' then
                    warnsdorffs[nrow][ncol] += 1
                end if
            end for
        end for
    end for
end procedure

function solve(integer row, integer col, integer n)
integer nrow, ncol
    tries+= 1
    if n>limit then return 1 end if
    if knownx[n] then
        for move=1 to length(moves) do
            nrow = row+moves[move][ROW]
            ncol = col+moves[move][COL]*nchars
            if nrow = knownx[n]
            and ncol = knowny[n] then
                if solve(nrow,ncol,n+1) then return 1 end if
                exit
            end if
        end for
        return 0
    end if
    sequence wmoves = {}
    for move=1 to length(moves) do
        nrow = row+moves[move][ROW]
        ncol = col+moves[move][COL]*nchars
        if onboard(nrow,ncol)
        and board[nrow][ncol]='_' then
            wmoves = append(wmoves,{warnsdorffs[nrow][ncol],nrow,ncol})
        end if
    end for
    wmoves = sort(wmoves)
    -- avoid creating orphans
    if length(wmoves)<2 or wmoves[2][1]>1 then
        for m=1 to length(wmoves) do
            {?,nrow,ncol} = wmoves[m]
            warnsdorffs[nrow][ncol] -= 1
        end for
        for m=1 to length(wmoves) do
            {?,nrow,ncol} = wmoves[m]
            board[nrow][ncol-nchars+1..ncol] = sprintf(fmt,n)
            if solve(nrow,ncol,n+1) then return 1 end if
            board[nrow][ncol-nchars+1..ncol] = blank
        end for
        for m=1 to length(wmoves) do
            {?,nrow,ncol} = wmoves[m]
            warnsdorffs[nrow][ncol] += 1
        end for
    end if
    return 0
end function

procedure Hidato(sequence s, integer w, integer h, integer lim)
integer y, ch, ch2, k
atom t0 = time()
    s = split(s,'\n')
    width = w
    height = h
    nchars = length(sprintf(" %d",lim))
    fmt = sprintf(" %%%dd",nchars-1)
    blank = repeat('_',nchars)
    board = repeat(repeat(' ',width*nchars),height)
    knownx = repeat(0,lim)
    knowny = repeat(0,lim)
    limit = 0
    for x=1 to height do
        for y=nchars to width*nchars by nchars do
            if y>length(s[x]) then
                ch = '.'
            else
                ch = s[x][y]
            end if
            if ch='_' then
                limit += 1
            elsif ch!='.' then
                k = ch-'0'
                ch2 = s[x][y-1]
                if ch2!=' ' then
                    k += (ch2-'0')*10
                    board[x][y-1] = ch2
                end if
                knownx[k] = x
                knowny[k] = y
                limit += 1
            end if
            board[x][y] = ch
        end for
    end for
    warnsdorffs = repeat(repeat(0,width*nchars),height)
    init_warnsdorffs()
    tries = 0
    if solve(knownx[1],knowny[1],2) then
        puts(1,join(board,"\n"))
        printf(1,"\nsolution found in %d tries (%3.2fs)\n",{tries,time()-t0})
    else
        puts(1,"no solutions found\n")
    end if
end procedure

constant board1 = """
 __ 33 35 __ __ .. .. ..
 __ __ 24 22 __ .. .. ..
 __ __ __ 21 __ __ .. ..
 __ 26 __ 13 40 11 .. ..
 27 __ __ __  9 __  1 ..
 .. .. __ __ 18 __ __ ..
 .. .. .. .. __  7 __ __
 .. .. .. .. .. ..  5 __"""
Hidato(board1,8,8,40)

constant board2 = """
 . 4 .
 _ 7 _
 1 _ _"""
Hidato(board2,3,3,7)

constant board3 = """
  1  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  . 74
  .  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .  _  .
  .  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  .  .  _  _  ."""
Hidato(board3,50,3,74)

constant board4 = """
 54 __ 60 59 __ 67 __ 69 __
 __ 55 __ __ 63 65 __ 72 71
 51 50 56 62 __ .. .. .. ..
 __ __ __ 14 .. .. 17 __ ..
 48 10 11 .. 15 __ 18 __ 22
 __ 46 __ ..  3 __ 19 23 __
 __ 44 __  5 __  1 33 32 __
 __ 43  7 __ 36 __ 27 __ 31
 42 __ __ 38 __ 35 28 __ 30"""
Hidato(board4,9,9,72)

constant board5 = """
 __ 58 __ 60 __ __ 63 66 __
 57 55 59 53 49 __ 65 __ 68
 __  8 __ __ 50 __ 46 45 __
 10  6 __ .. .. .. __ 43 70
 __ 11 12 .. .. .. 72 71 __
 __ 14 __ .. .. .. 30 39 __
 15  3 17 __ 28 29 __ __ 40
 __ __ 19 22 __ __ 37 36 __
  1 20 __ 24 __ 26 __ 34 33"""
Hidato(board5,9,9,72)

constant board6 = """
  1 __ .. .. .. __ __ .. .. .. __ __ .. .. .. __ __ .. .. .. __ __ .. .. .. __ __ .. .. .. __ __ .. .. .. __ __ .. .. .. __ __ .. .. .. 82
 .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ ..
 .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. .. __ .. __ .. ..
 __ __ __ .. .. __ __ __ .. .. __ __ __ .. .. __ __ __ .. .. __ __ __ .. .. __ __ __ .. .. __ __ __ .. .. __ __ __ .. .. __ __ __ .. .. .."""
Hidato(board6,46,4,82)


(load "@lib/simul.l")

(de hidato (Lst)
   (let Grid (grid (length (maxi length Lst)) (length Lst))
      (mapc
         '((G L)
            (mapc
               '((This Val)
                  (nond
                     (Val
                        (with (: 0 1 1) (con (: 0 1)))    # Cut off west
                        (with (: 0 1 -1) (set (: 0 1)))   # east
                        (with (: 0 -1 1) (con (: 0 -1)))  # south
                        (with (: 0 -1 -1) (set (: 0 -1))) # north
                        (set This) )
                     ((=T Val) (=: val Val)) ) )
               G L ) )
         Grid
         (apply mapcar (reverse Lst) list) )
      (let Todo
         (by '((This) (: val)) sort
            (mapcan '((Col) (filter '((This) (: val)) Col))
               Grid ) )
         (let N 1
            (with (pop 'Todo)
               (recur (N Todo)
                  (unless (> (inc 'N) (; Todo 1 val))
                     (find
                        '((Dir)
                           (with (Dir This)
                              (cond
                                 ((= N (: val))
                                    (if (cdr Todo) (recurse N @) T) )
                                 ((not (: val))
                                    (=: val N)
                                    (or (recurse N Todo) (=: val NIL)) ) ) ) )
                        (quote
                           west east south north
                           ((X) (or (south (west X)) (west (south X))))
                           ((X) (or (north (west X)) (west (north X))))
                           ((X) (or (south (east X)) (east (south X))))
                           ((X) (or (north (east X)) (east (north X)))) ) ) ) ) ) ) )
      (disp Grid 0
         '((This)
            (if (: val) (align 3 @) "   ") ) ) ) )


board = []
given = []
start = None

def setup(s):
    global board, given, start
    lines = s.splitlines()
    ncols = len(lines[0].split())
    nrows = len(lines)
    board = [[-1] * (ncols + 2) for _ in xrange(nrows + 2)]

    for r, row in enumerate(lines):
        for c, cell in enumerate(row.split()):
            if cell == "__" :
                board[r + 1][c + 1] = 0
                continue
            elif cell == ".":
                continue # -1
            else:
                val = int(cell)
                board[r + 1][c + 1] = val
                given.append(val)
                if val == 1:
                    start = (r + 1, c + 1)
    given.sort()

def solve(r, c, n, next=0):
    if n > given[-1]:
        return True
    if board[r][c] and board[r][c] != n:
        return False
    if board[r][c] == 0 and given[next] == n:
        return False

    back = 0
    if board[r][c] == n:
        next += 1
        back = n

    board[r][c] = n
    for i in xrange(-1, 2):
        for j in xrange(-1, 2):
            if solve(r + i, c + j, n + 1, next):
                return True
    board[r][c] = back
    return False

def print_board():
    d = {-1: "  ", 0: "__"}
    bmax = max(max(r) for r in board)
    form = "%" + str(len(str(bmax)) + 1) + "s"
    for r in board[1:-1]:
        print "".join(form % d.get(c, str(c)) for c in r[1:-1])

hi = """\
__ 33 35 __ __  .  .  .
__ __ 24 22 __  .  .  .
__ __ __ 21 __ __  .  .
__ 26 __ 13 40 11  .  .
27 __ __ __  9 __  1  .
 .  . __ __ 18 __ __  .
 .  .  .  . __  7 __ __
 .  .  .  .  .  .  5 __"""

setup(hi)
print_board()
solve(start[0], start[1], 1)
print
print_board()


package main

import (
    "fmt"
    big "github.com/ncw/gmp"
)

// returns true if k is a sequence member, false otherwise
func a(k int64) bool {
    if k == 1 {
        return false
    }
    bk := big.NewInt(k)
    for m := uint(1); m < uint(k); m++ {
        n := big.NewInt(1)
        n.Lsh(n, m)
        n.Add(n, bk)
        if n.ProbablyPrime(15) {
            return false
        }
    }
    return true
}

func main() {
    count := 0
    k := int64(1)
    for count < 5 {
        if a(k) {
            fmt.Printf("%d ", k)
            count++
        }
        k += 2
    }
    fmt.Println()
}


using Lazy
using Primes

a(k) = all(m -> !isprime(k + big"2"^m), 1:k-1)

A033939 = @>> Lazy.range(2) filter(isodd) filter(a)

println(take(5, A033939))   # List: (773 2131 2491 4471 5101)


use strict;
use warnings;
use bigint;
use ntheory 'is_prime';

my $cnt;
LOOP: for my $k (2..1e10) {
    next unless 1 == $k % 2;
    for my $m (1..$k-1) {
        next LOOP if is_prime $k + (1<<$m)
    }
    print "$k ";
    last if ++$cnt == 5;
}


#lang racket
(require math/array)

;#f = not a legal position, #t = blank position
(define board
  (array
   #[#[#t 33 35 #t #t #f #f #f]
     #[#t #t 24 22 #t #f #f #f]
     #[#t #t #t 21 #t #t #f #f]
     #[#t 26 #t 13 40 11 #f #f]
     #[27 #t #t #t  9 #t  1 #f]
     #[#f #f #t #t 18 #t #t #f]
     #[#f #f #f #f #t  7 #t #t]
     #[#f #f #f #f #f #f  5 #t]]))

;filters elements with the predicate, returning the element and its indices
(define (array-indices-of a f)
  (for*/list ([i (range 0 (vector-ref (array-shape a) 0))]
              [j (range 0 (vector-ref (array-shape a) 1))]
              #:when (f (array-ref a (vector i j))))
    (list (array-ref a (vector i j)) i j)))

;returns a list, each element is a list of the number followed by i and j indices
;sorted ascending by number
(define (goal-list v) (sort (array-indices-of v number?) (λ (a b) (< (car a) (car b)))))

;every direction + start position that's on the board
(define (legal-moves a i0 j0)
  (for*/list ([i (range (sub1 i0) (+ i0 2))]
              [j (range (sub1 j0) (+ j0 2))]
              ;cartesian product -1..1 and -1..1, except 0 0
              #:when (and (not (and (= i i0) (= j j0)))
                          ;make sure it's on the board
                          (<= 0 i (sub1 (vector-ref (array-shape a) 0)))
                          (<= 0 j (sub1 (vector-ref (array-shape a) 1)))
                          ;make sure it's an actual position too (the real board isn't square)
                          (array-ref a (vector i j))))
    (cons i j)))

;find path through array, returning list of coords from start to finish
(define (hidato-path a)
  ;get starting position as first goal
  (match-let ([(cons (list n i j) goals) (goal-list a)])
    (let hidato ([goals goals] [n n] [i i] [j j] [path '()])
      (match goals
        ;no more goals, return path
        ['() (reverse (cons (cons i j) path))]
        ;get next goal
        [(cons (list n-goal i-goal j-goal) _)
         (let ([move (cons i j)])
           ;already visiting a spot or taking too many moves to reach the next goal is no good
           (cond [(or (member move path) (> n n-goal)) #f]
                 ;taking the right number of moves to be at the goal square is good
                 ;so go to the next goal
                 [(and (= n n-goal) (= i i-goal) (= j j-goal))
                  (hidato (cdr goals) n i j path)]
                 ;depth first search using every legal move to find next goal
                 [else (ormap (λ (m) (hidato goals (add1 n) (car m) (cdr m) (cons move path)))
                              (legal-moves a i j))]))]))))

;take a path and insert it into the array
(define (put-path a path)
  (let ([a (array->mutable-array a)])
    (for ([n (range 1 (add1 (length path)))] [move path])
      (array-set! a (vector (car move) (cdr move)) n))
    a))

;main function
(define (hidato board) (put-path board (hidato-path board)))


my @adjacent = [-1, -1], [-1, 0], [-1, 1],
               [ 0, -1],          [ 0, 1],
               [ 1, -1], [ 1, 0], [ 1, 1];

solveboard q:to/END/;
        __ 33 35 __ __ .. .. ..
        __ __ 24 22 __ .. .. ..
        __ __ __ 21 __ __ .. ..
        __ 26 __ 13 40 11 .. ..
        27 __ __ __  9 __  1 ..
        .. .. __ __ 18 __ __ ..
        .. .. .. .. __  7 __ __
        .. .. .. .. .. ..  5 __
        END

sub solveboard($board) {
    my $max = +$board.comb(/\w+/);
    my $width = $max.chars;

    my @grid;
    my @known;
    my @neigh;
    my @degree;

    @grid = $board.lines.map: -> $line {
        [ $line.words.map: { /^_/ ?? 0 !! /^\./ ?? Rat !! $_ } ]
    }

    sub neighbors($y,$x --> List) {
        eager gather for @adjacent {
            my $y1 = $y + .[0];
            my $x1 = $x + .[1];
            take [$y1,$x1] if defined @grid[$y1][$x1];
        }
    }

    for ^@grid -> $y {
        for ^@grid[$y] -> $x {
            if @grid[$y][$x] -> $v {
                @known[$v] = [$y,$x];
            }
            if @grid[$y][$x].defined {
                @neigh[$y][$x] = neighbors($y,$x);
                @degree[$y][$x] = +@neigh[$y][$x];
            }
        }
    }
    print "\e[0H\e[0J";

    my $tries = 0;

    try_fill 1, @known[1];

    sub try_fill($v, $coord [$y,$x] --> Bool) {
        return True if $v > $max;
        $tries++;

        my $old = @grid[$y][$x];

        return False if +$old and $old != $v;
        return False if @known[$v] and @known[$v] !eqv $coord;

        @grid[$y][$x] = $v;               # conjecture grid value

        print "\e[0H";                    # show conjectured board
        for @grid -> $r {
            say do for @$r {
                when Rat { ' ' x $width }
                when 0   { '_' x $width }
                default  { .fmt("%{$width}d") }
            }
        }

        my @neighbors = @neigh[$y][$x][];

        my @degrees;
        for @neighbors -> \n [$yy,$xx] {
            my $d = --@degree[$yy][$xx];  # conjecture new degrees
            push @degrees[$d], n;         # and categorize by degree
        }

        for @degrees.grep(*.defined) -> @ties {
            for @ties.reverse {           # reverse works better for this hidato anyway
                return True if try_fill $v + 1, $_;
            }
        }

        for @neighbors -> [$yy,$xx] {
            ++@degree[$yy][$xx];          # undo degree conjectures
        }

        @grid[$y][$x] = $old;             # undo grid value conjecture
        return False;
    }

    say "$tries tries";
}


with javascript_semantics
atom t0 = time()
include mpfr.e

mpz z = mpz_init()
function a(integer k)
    if k=1 then return false end if
    for m=1 to k-1 do
        mpz_ui_pow_ui(z,2,m)
        mpz_add_si(z,z,k)
        if mpz_prime(z) then return false end if
    end for
    return true
end function

integer k = 1, count = 0
while count<5 do
    if a(k) then
        printf(1,"%d ",k)
        count += 1
    end if
    k += 2
end while
printf(1,"\n")
?elapsed(time()-t0)


import "./gmp" for Mpz

// returns true if k is a sequence member, false otherwise
var a = Fn.new { |k|
    if (k == 1) return false
    for (m in 1...k) {
        var n = Mpz.one.lsh(m).add(k)
        if (n.probPrime(15) > 0) return false
    }
    return true
}

var count = 0
var k = 1
while (count < 5) {
    if (a.call(k)) {
        System.write("%(k) ")
        count = count + 1
    }
    k = k + 2
}
System.print()


/*REXX program solves a  Numbrix (R) puzzle, it also displays the puzzle and solution.  */
maxR=0;    maxC=0;    maxX=0;     minR=9e9;      minC=9e9;    minX=9e9;    cells=0;    @.=
parse arg xxx;        PZ='Hidato puzzle'         /*get the cell definitions from the CL.*/
xxx=translate(xxx, , "/\;:_", ',')               /*also allow other characters as comma.*/

               do  while xxx\='';  parse var  xxx    r c   marks  ','  xxx
                   do  while marks\='';          [email protected].r.c
                   parse var marks  x  marks
                   if datatype(x,'N')  then do;  x=x/1                     /*normalize X*/
                                                 if x<0  then PZ= 'Numbrix puzzle'
                                                 x=abs(x)                  /*use  │x│   */
                                            end
                   minR=min(minR,r);  maxR=max(maxR,r); minC=min(minC,c); maxC=max(maxC,c)
                   if x==1   then do;  !r=r;  !c=c;  end              /*the START cell. */
                   if _\=='' then call err "cell at" r c 'is already occupied with:'  _
                   @.r.c=x;   c=c+1;    cells=cells+1                 /*assign a mark.  */
                   if x==.              then iterate                  /*is a hole?  Skip*/
                   if \datatype(x,'W')  then call err 'illegal marker specified:' x
                   minX=min(minX,x);    maxX=max(maxX,x)              /*min and max  X. */
                   end   /*while marks¬='' */
               end       /*while xxx  ¬='' */
call show                                        /* [↓]  is used for making fast moves. */
Nr = '0  1   0  -1    -1   1   1  -1'            /*possible  row     for the next move. */
Nc = '1  0  -1   0     1  -1   1  -1'            /*   "      column   "   "    "    "   */
pMoves=words(Nr) -4*(left(PZ,1)=='N')            /*is this to be a Numbrix puzzle ?     */
  do i=1  for pMoves;   Nr.i=word(Nr,i);   Nc.i=word(Nc,i);   end     /*for fast moves. */
if \next(2,!r,!c)  then call err  'No solution possible for this'   PZ    "puzzle."
say 'A solution for the'   PZ    "exists.";      say;                     call show
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
err:  say;    say '***error*** (from' PZ"): "    arg(1);        say;          exit 13
/*──────────────────────────────────────────────────────────────────────────────────────*/
next: procedure expose @. Nr. Nc. cells pMoves;  parse arg #,r,c;   ##=#+1
           do t=1  for pMoves                                   /* [↓]  try some moves. */
           parse value  r+Nr.t c+Nc.t  with nr nc               /*next move coördinates.*/
           if @.nr.nc==.  then do;                @.nr.nc=#     /*let's try this move.  */
                               if #==cells        then leave    /*is this the last move?*/
                               if next(##,nr,nc)  then return 1
                               @.nr.nc=.                        /*undo the above move.  */
                               iterate                          /*go & try another move.*/
                               end
           if @.nr.nc==#  then do                               /*this a fill-in move ? */
                               if #==cells        then return 1 /*this is the last move.*/
                               if next(##,nr,nc)  then return 1 /*a fill-in move.       */
                               end
           end   /*t*/
      return 0                                                  /*this ain't working.   */
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: if maxR<1 | maxC<1  then call err  'no legal cell was specified.'
      if minX<1           then call err  'no  1  was specified for the puzzle start'
      w=max(2,length(cells));  do    r=maxR  to minR  by -1; _=
                                  do c=minC  to maxC;        _=_ right(@.r.c,w); end /*c*/
                               say _
                               end   /*r*/
      say;    return


# Solve a Hidato Puzzle
#
class Hidato
  Cell = Struct.new(:value, :used, :adj)
  ADJUST = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]

  def initialize(board, pout=true)
    @board = []
    board.each_line do |line|
      @board << line.split.map{|n| Cell[Integer(n), false] rescue nil} + [nil]
    end
    @board << []                                # frame (Sentinel value : nil)
    @board.each_with_index do |row, x|
      row.each_with_index do |cell, y|
        if cell
          @sx, @sy = x, y  if cell.value==1     # start position
          cell.adj = ADJUST.map{|dx,dy| [x+dx,y+dy]}.select{|xx,yy| @board[xx][yy]}
        end
      end
    end
    @xmax = @board.size - 1
    @ymax = @board.map(&:size).max - 1
    @end  = @board.flatten.compact.size
    puts to_s('Problem:')  if pout
  end

  def solve
    @zbl = Array.new(@end+1, false)
    @board.flatten.compact.each{|cell| @zbl[cell.value] = true}
    puts (try(@board[@sx][@sy], 1) ? to_s('Solution:') : "No solution")
  end

  def try(cell, seq_num)
    return true  if seq_num > @end
    return false if cell.used
    value = cell.value
    return false if value > 0 and value != seq_num
    return false if value == 0 and @zbl[seq_num]
    cell.used = true
    cell.adj.each do |x, y|
      if try(@board[x][y], seq_num+1)
        cell.value = seq_num
        return true
      end
    end
    cell.used = false
  end

  def to_s(msg=nil)
    str = (0[email protected]).map do |x|
      (0[email protected]).map{|y| "%3s" % (([email protected][x][y]) ? c.value : c)}.join
    end
    (msg ? [msg] : []) + str + [""]
  end
end


use std::cmp::{max, min};
use std::fmt;
use std::ops;

#[derive(Debug, Clone, PartialEq)]
struct Board {
    cells: Vec<Vec<Option<u32>>>,
}

impl Board {
    fn new(initial_board: Vec<Vec<u32>>) -> Self {
        let b = initial_board
            .iter()
            .map(|r| {
                r.iter()
                    .map(|c| if *c == u32::MAX { None } else { Some(*c) })
                    .collect()
            })
            .collect();

        Board { cells: b }
    }

    fn height(&self) -> usize {
        self.cells.len()
    }

    fn width(&self) -> usize {
        self.cells[0].len()
    }
}
impl ops::Index<(usize, usize)> for Board {
    type Output = Option<u32>;

    fn index(&self, (y, x): (usize, usize)) -> &Self::Output {
        &self.cells[y][x]
    }
}
impl ops::IndexMut<(usize, usize)> for Board {
    /// Returns a mutable reference to an cell for a given 'x' 'y' coordinates
    fn index_mut(&mut self, (y, x): (usize, usize)) -> &mut Option<u32> {
        &mut self.cells[y][x]
    }
}

impl fmt::Display for Board {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let output: Vec<String> = self
            .cells
            .iter()
            .map(|r| {
                let mut row = String::default();

                r.iter().for_each(|c| match c {
                    None => row.push_str(format!("{:>2} ", " ").as_ref()),
                    Some(c) if c == &0 => row.push_str(format!("{:>2} ", ".").as_ref()),
                    Some(c) => row.push_str(format!("{:>2} ", c).as_ref()),
                });
                row
            })
            .collect();

        write!(f, "{}", output.join("\n"))
    }
}

/// Structure for holding puzzle related information.
#[derive(Clone, Debug)]
struct Puzzle {
    /// The state of the board.
    board: Board,

    /// All the numbers which were given at puzzle setup:
    /// the numbers which cannot be changed during solving the puzzle.
    fixed: Vec<u32>,

    /// Position of the first number (1).
    start: (usize, usize),
}

impl Puzzle {
    /// Creates a new puzzle
    /// * `initial_board` contains the  layout and the startin position.
    ///
    /// - Simple numbers in the `initial_board` are considered as "fixed",
    /// aka the solving does not change them
    ///
    /// - As the board can be non-rectangular, all cells which are invalid or cannot be used
    /// are marked with u32::MAX in the `initial_board`
    fn new(initial_board: Vec<Vec<u32>>) -> Self {
        let mut s: (usize, usize) = (0, 0);
        let mut f = initial_board
            .iter()
            .enumerate()
            .flat_map(|(y, r)| r.iter().enumerate().map(move |(x, c)| (y, x, *c)))
            .filter(|(_, _, c)| (1..u32::MAX).contains(c))
            .fold(Vec::new(), |mut fixed, (y, x, c)| {
                fixed.push(c);
                if c == 1 {
                    // store the position of the start
                    s = (y, x)
                };
                fixed
            });

        f.sort_unstable();

        Puzzle {
            board: Board::new(initial_board),
            fixed: f,
            start: s,
        }
    }

    pub fn print_board(&self) {
        println!("{}", self.board);
    }

    fn solver(&mut self, current: (usize, usize), n: &u32, mut next: usize) -> bool {
        // reached the last number, solving successful
        if n > self.fixed.last().unwrap() {
            return true;
        }

        // check for exit conditions
        match self.board[current] {
            // cell outside of the board
            None => return false,

            //cell is already has a number in it
            Some(c) if c != 0 && c != *n => return false,

            //cell is empty, but the to be placed number is already matching the next fixed number
            Some(c) if c == 0 && self.fixed[next] == *n => return false,

            // continue
            _ => (),
        }

        let mut backup: u32 = 0;
        if self.board[current] == Some(*n) {
            backup = *n;
            next += 1;
        }

        self.board[current] = Some(*n);

        for y in (max(current.0, 1) - 1)..=min(current.0 + 1, self.board.height() - 1) {
            for x in (max(current.1, 1) - 1)..=min(current.1 + 1, self.board.width() - 1) {
                if self.solver((y, x), &(n + 1), next) {
                    return true;
                }
            }
        }

        // unsuccessful branch, restore original value
        self.board[current] = Some(backup);
        false
    }

    pub fn solve(&mut self) {
        let start = self.start;
        self.solver(start, &1, 0);
    }
}

fn main() {
    let input = vec![
        vec![0, 33, 35, 0, 0, u32::MAX, u32::MAX, u32::MAX],
        vec![0, 0, 24, 22, 0, u32::MAX, u32::MAX, u32::MAX],
        vec![0, 0, 0, 21, 0, 0, u32::MAX, u32::MAX],
        vec![0, 26, 0, 13, 40, 11, u32::MAX, u32::MAX],
        vec![27, 0, 0, 0, 9, 0, 1, u32::MAX],
        vec![u32::MAX, u32::MAX, 0, 0, 18, 0, 0, u32::MAX],
        vec![u32::MAX, u32::MAX, u32::MAX, u32::MAX, 0, 7, 0, 0],
        vec![
            u32::MAX,
            u32::MAX,
            u32::MAX,
            u32::MAX,
            u32::MAX,
            u32::MAX,
            5,
            0,
        ],
    ];

    let mut p = Puzzle::new(input);
    p.print_board();
    p.solve();
    println!("\nSolution:");
    p.print_board();
}


$ include "seed7_05.s7i";

var set of integer: given is {};
var array array integer: board is 0 times 0 times 0;
var integer: startRow is 0;
var integer: startColumn is 0;

const proc: setup (in array string: input) is func
  local
    var integer: r is 0;
    var integer: c is 0;
    var array string: row is 0 times "";
    var string: cell is "";
    var integer: value is 0;
  begin
    board := (length(input) + 2) times 0 times 0;
    for key r range input do
      row := split(input[r], " ");
      board[r + 1] := (length(row) + 2) times - 1;
      for key c range row do
        cell := row[c];
        if cell = "_" then
          board[r + 1][c + 1] := 0;
        elsif cell[1] in {'0' .. '9'} then
          value := integer parse cell;
          board[r + 1][c + 1] := value;
          incl(given, value);
          if value = 1 then
            startRow := r + 1;
            startColumn := c + 1;
          end if;
        end if;
      end for;
    end for;
    board[1] := (length(row) + 2) times - 1;
    board[length(input) + 2] := (length(row) + 2) times - 1;
  end func;

const func boolean: solve (in integer: r, in integer: c, in integer: n) is func
  result
    var boolean: solved is FALSE;
  local
    var integer: back is 0;
    var integer: i is 0;
    var integer: j is 0;
  begin
    if n > max(given) then
      solved := TRUE;
    elsif board[r][c] = 0 and n not in given or board[r][c] = n then
      back := board[r][c];
      board[r][c] := n;
      for i range -1 to 1 until solved do
        for j range -1 to 1 until solved do
          solved := solve(r + i, c + j, n + 1);
        end for;
      end for;
      if not solved then
        board[r][c] := back;
      end if;
    end if;
  end func;

const proc: printBoard is func
  local
    var integer: r is 0;
    var integer: c is 0;
  begin
    for key r range board do
      for c range board[r] do
        if c = -1 then
          write(" . ");
        elsif c > 0 then
          write(c lpad 2 <& " ");
        else
          write("__ ");
        end if;
      end for;
      writeln;
    end for;
  end func;

const proc: main is func
  local
    const array string: input is [] ("_ 33 35 _ _ . . .",
                                     "_ _ 24 22 _ . . .",
                                     "_ _ _ 21 _ _ . .",
                                     "_ 26 _ 13 40 11 . .",
                                     "27 _ _ _ 9 _ 1 .",
                                     ". . _ _ 18 _ _ .",
                                     ". . . . _ 7 _ _",
                                     ". . . . . . 5 _");
  begin
    setup(input);
    printBoard;
    writeln;
    if solve(startRow, startColumn, 1) then
      writeln("Found:");
      printBoard;
    end if;
  end func;


def input:
'__ 33 35 __ __  .  .  .
 __ __ 24 22 __  .  .  .
 __ __ __ 21 __ __  .  .
 __ 26 __ 13 40 11  .  .
 27 __ __ __  9 __  1  .
  .  . __ __ 18 __ __  .
  .  .  .  . __  7 __ __
  .  .  .  .  .  .  5 __';

templates hidato
  composer setup
    data givenInput <[<={}|{row: <row>, col: <col>}>*]> local
    @: {row: 1, col: 1, givenInput:[]};
    { board: [ <line>+ ], given: [email protected] -> \[i](<~={}> { n: $i, $...} !\) }
    rule line: [ <cell>+ ] (<'\n '>?) (..|@: {row: [email protected]::raw + 1, col: 1};)
    rule cell: <open|blocked|given> (<' '>?) (@.col: [email protected]::raw + 1;)
    rule open: <'__'> -> 0
    rule blocked: <' \.'> -> -1
    rule given: (<' '>?) (def given: <INT>;)
      ($given -> ..|@.givenInput: [email protected]::length+1..$ -> {};)
      ($given -> @.givenInput($): { row: [email protected], col: [email protected] };)
      $given
  end setup

  templates solve
    when <~{row: <[email protected]::length>, col: <[email protected](1)::length>}> do !VOID
    when <{ n: <[email protected](last).n>, row: <[email protected](last).row>, col: <[email protected](last).col> }> do [email protected] !
    when <?([email protected]($.row; $.col) <~=0|=$.n>)> do !VOID
    when <?([email protected]($.row; $.col) <=0>)?([email protected]($.next) <=$.n>)> do !VOID
    otherwise
      def guess: $;
      def back: [email protected]($.row; $.col);
      def next: $ -> \(when <{n: <=$back>}> do $.next::raw + 1! otherwise $.next!\);
      @hidato.board($.row; $.col): $.n::raw;
      0..8 -> { next: $next, n: $guess.n::raw + 1, row: $guess.row::raw + $ ~/ 3 - 1, col: $guess.col::raw + $ mod 3 - 1 } -> #
      @hidato.board($.row; $.col): $back;
  end solve

  @: $ -> setup;
  { next: 1, [email protected](1)... } -> solve !
end hidato

$input -> hidato -> '$... -> '$... -> ' $ -> \(when <=-1> do ' .' ! when <10..> do '$;' ! otherwise ' $;' !\);';
';
' ->!OUT::write


proc init {initialConfiguration} {
    global grid max filled
    set max 1
    set y 0
    foreach row [split [string trim $initialConfiguration "\n"] "\n"] {
	set x 0
	set rowcontents {}
	foreach cell $row {
	    if {![string is integer -strict $cell]} {set cell -1}
	    lappend rowcontents $cell
	    set max [expr {max($max, $cell)}]
	    if {$cell > 0} {
		dict set filled $cell [list $y $x]
	    }
	    incr x
	}
	lappend grid $rowcontents
	incr y
    }
}

proc findseps {} {
    global max filled
    set result {}
    for {set i 1} {$i < $max-1} {incr i} {
	if {[dict exists $filled $i]} {
	    for {set j [expr {$i+1}]} {$j <= $max} {incr j} {
		if {[dict exists $filled $j]} {
		    if {$j-$i > 1} {
			lappend result [list $i $j [expr {$j-$i}]]
		    }
		    break
		}
	    }
	}
    }
    return [lsort -integer -index 2 $result]
}

proc makepaths {sep} {
    global grid filled
    lassign $sep from to len
    lassign [dict get $filled $from] y x
    set result {}
    foreach {dx dy} {-1 -1  -1 0  -1 1  0 -1  0 1  1 -1  1 0  1 1} {
	discover [expr {$x+$dx}] [expr {$y+$dy}] [expr {$from+1}] $to \
	    [list [list $from $x $y]] $grid
    }
    return $result
}
proc discover {x y n limit path model} {
    global filled
    # Check for illegal
    if {[lindex $model $y $x] != 0} return
    upvar 1 result result
    lassign [dict get $filled $limit] ly lx
    # Special case
    if {$n == $limit-1} {
	if {abs($x-$lx)<=1 && abs($y-$ly)<=1 && !($lx==$x && $ly==$y)} {
	    lappend result [lappend path [list $n $x $y] [list $limit $lx $ly]]
	}
	return
    }
    # Check for impossible
    if {abs($x-$lx) > $limit-$n || abs($y-$ly) > $limit-$n} return
    # Recursive search
    lappend path [list $n $x $y]
    lset model $y $x $n
    incr n
    foreach {dx dy} {-1 -1  -1 0  -1 1  0 -1  0 1  1 -1  1 0  1 1} {
	discover [expr {$x+$dx}] [expr {$y+$dy}] $n $limit $path $model
    }
}

proc applypath {path} {
    global grid filled
    puts "Found unique path for [lindex $path 0 0] -> [lindex $path end 0]"
    foreach cell [lrange $path 1 end-1] {
	lassign $cell n x y
	lset grid $y $x $n
	dict set filled $n [list $y $x]
    }
}

proc printgrid {} {
    global grid max
    foreach row $grid {
	foreach cell $row {
	    puts -nonewline [format " %*s" [string length $max] [expr {
		$cell==-1 ? "." : $cell
	    }]]
	}
	puts ""
    }
}

proc solveHidato {initialConfiguration} {
    init $initialConfiguration
    set limit [llength [findseps]]
    while {[llength [set seps [findseps]]] && [incr limit -1]>=0} {
	foreach sep $seps {
	    if {[llength [set paths [makepaths $sep]]] == 1} {
		applypath [lindex $paths 0]
		break
	    }
	}
    }
    puts ""
    printgrid
}


import "/sort" for Sort
import "/fmt" for Fmt

var board = []
var given = []
var start = []

var setUp = Fn.new { |input|
    var nRows = input.count
    var puzzle = List.filled(nRows, null)
    for (i in 0...nRows) puzzle[i] = input[i].split(" ")
    var nCols = puzzle[0].count
    var list = []
    board = List.filled(nRows+2, null)
    for (i in 0...board.count) board[i] = List.filled(nCols+2, -1)
    for (r in 0...nRows) {
        var row = puzzle[r]
        for (c in 0...nCols) {
            var cell = row[c]
            if (cell == "_") {
                board[r + 1][c + 1] = 0
            } else if (cell != ".") {
                var value = Num.fromString(cell)
                board[r + 1][c + 1] = value
                list.add(value)
                if (value == 1) start = [r + 1, c + 1]
            }
        }
    }
    Sort.quick(list)
    given = list
}

var solve // recursive
solve = Fn.new { |r, c, n, next|
    if (n > given[-1]) return true
    var back = board[r][c]
    if (back != 0 && back != n) return false
    if (back == 0 && given[next] == n) return false
    var next2 = next
    if (back == n) next2 = next2 + 1
    board[r][c] = n
    for (i in -1..1) {
        for (j in -1..1) if (solve.call(r + i, c + j, n + 1, next2)) return true
    }
    board[r][c] = back
    return false
}

var printBoard = Fn.new {
    for (row in board) {
        for (c in row) {
            if (c == -1) {
                System.write(" . ")
            } else if (c > 0) {
                Fmt.write("$2d ", c)
            } else {
                System.write("__ ")
            }
        }
        System.print()
    }
}

var input = [
    "_ 33 35 _ _ . . .",
    "_ _ 24 22 _ . . .",
    "_ _ _ 21 _ _ . .",
    "_ 26 _ 13 40 11 . .",
    "27 _ _ _ 9 _ 1 .",
    ". . _ _ 18 _ _ .",
    ". . . . _ 7 _ _",
    ". . . . . . 5 _"
]
setUp.call(input)
printBoard.call()
System.print("\nFound:")
solve.call(start[0], start[1], 1, 0)
printBoard.call()


hi:=  // 0==empty cell, X==not a cell
#<<<
 "0  33  35   0   0   X   X   X
  0   0  24  22   0   X   X   X
  0   0   0  21   0   0   X   X
  0  26   0  13  40  11   X   X
 27   0   0   0   9   0   1   X
  X   X   0   0  18   0   0   X
  X   X   X   X   0   7   0   0
  X   X   X   X   X   X   5   0";
#<<<

board,given,start:=setup(hi);
print_board(board);
solve(board,given, start.xplode(), 1);
println();
print_board(board);


[String] data
V nrows = 0
V px = 0
V py = 0
V sdata = ‘’
V ddata = ‘’

F init(board)
   :data = board.split("\n")
   :nrows = max(:data.map(r -> r.len))

   V maps = [‘ ’ = ‘ ’, ‘.’ = ‘.’, ‘@’ = ‘ ’, ‘#’ = ‘#’, ‘$’ = ‘ ’]
   V mapd = [‘ ’ = ‘ ’, ‘.’ = ‘ ’, ‘@’ = ‘@’, ‘#’ = ‘ ’, ‘$’ = ‘*’]

   L(row) :data
      V r = L.index
      L(ch) row
         V c = L.index
         :sdata ‘’= maps[ch]
         :ddata ‘’= mapd[ch]
         I ch == ‘@’
            :px = c
            :py = r

F push(x, y, dx, dy, &data)
   I :sdata[(y + 2 * dy) * :nrows + x + 2 * dx] == ‘#’
     | data[(y + 2 * dy) * :nrows + x + 2 * dx] != ‘ ’
      data = ‘’
      R

   data[y * :nrows + x] = ‘ ’
   data[(y + dy) * :nrows + x + dx] = ‘@’
   data[(y + 2 * dy) * :nrows + x + 2 * dx] = ‘*’

F is_solved(data)
   L(i) 0 .< data.len
      I (:sdata[i] == ‘.’) != (data[i] == ‘*’)
         R 0B
   R 1B

F solve()
   V open = Deque([(:ddata, ‘’, :px, :py)])
   V visited = Set([:ddata])
   V dirs = ((0, -1, ‘u’, ‘U’), ( 1, 0, ‘r’, ‘R’),
             (0,  1, ‘d’, ‘D’), (-1, 0, ‘l’, ‘L’))

   L !open.empty
      V (cur, csol, x, y) = open.pop_left()

      L(di) dirs
         V temp = copy(cur)
         V (dx, dy) = (di[0], di[1])

         I temp[(y + dy) * :nrows + x + dx] == ‘*’
            push(x, y, dx, dy, &temp)
            I temp != ‘’ & temp !C visited
               I is_solved(temp)
                  R csol‘’di[3]
               open.append((temp, csol‘’di[3], x + dx, y + dy))
               visited.add(temp)
         E
            I :sdata[(y + dy) * :nrows + x + dx] == ‘#’ | temp[(y + dy) * :nrows + x + dx] != ‘ ’
               L.continue

            temp[y * :nrows + x] = ‘ ’
            temp[(y + dy) * :nrows + x + dx] = ‘@’

            I temp !C visited
               I is_solved(temp)
                  R csol‘’di[2]
               open.append((temp, csol‘’di[2], x + dx, y + dy))
               visited.add(temp)

   R ‘No solution’

V level =
|‘#######
  #     #
  #     #
  #. #  #
  #. $$ #
  #.$$  #
  #.#  @#
  #######’

init(level)
print(level"\n\n"solve())


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <assert.h>
#include <stdbool.h>

int w, h, n_boxes;
uint8_t *board, *goals, *live;

typedef uint16_t cidx_t;
typedef uint32_t hash_t;

/* board configuration is represented by an array of cell indices
   of player and boxes */
typedef struct state_t state_t;

struct state_t { // variable length
	hash_t h;
	state_t *prev, *next, *qnext;
	cidx_t c[];
};

size_t state_size, block_size = 32;
state_t *block_root, *block_head;

inline
state_t* newstate(state_t *parent) {
	inline state_t* next_of(state_t *s) {
		return (void*)((uint8_t*)s + state_size);
	}

	state_t *ptr;
	if (!block_head) {
		block_size *= 2;
		state_t *p = malloc(block_size * state_size);
		assert(p);
		p->next = block_root;
		block_root = p;
		ptr = (void*)((uint8_t*)p + state_size * block_size);
		p = block_head = next_of(p);
		state_t *q;
		for (q = next_of(p); q < ptr; p = q, q = next_of(q))
			p->next = q;
		p->next = NULL;
	}

	ptr = block_head;
	block_head = block_head->next;

	ptr->prev = parent;
	ptr->h = 0;
	return ptr;
}

inline
void unnewstate(state_t *p) {
	p->next = block_head;
	block_head = p;
}

enum { space, wall, player, box };

#define E "\033["
const char * const glyph1[] = { " ", "#", E"[email protected]"E"m", E"33m$"E"m"};
const char * const glyph2[] = { E"32m."E"m", "#", E"[email protected]"E"m", E"32m$"E"m"};
#undef E

// mark up positions where a box definitely should not be
void mark_live(const int c)
{
	const int y = c / w, x = c % w;
	if (live[c]) return;

	live[c] = 1;
	if (y > 1 && board[c - w] != wall && board[c - w * 2] != wall)
		mark_live(c - w);
	if (y < h - 2 && board[c + w] != wall && board[c + w * 2] != wall)
		mark_live(c + w);
	if (x > 1 && board[c - 1] != wall && board[c - 2] != wall)
		mark_live(c - 1);
	if (x < w - 2 && board[c + 1] != wall && board[c + 2] != wall)
		mark_live(c + 1);
}

state_t *parse_board(const int y, const int x, const char *s)
{
	w = x, h = y;
	board = calloc(w * h, sizeof(uint8_t));
	assert(board);
	goals = calloc(w * h, sizeof(uint8_t));
	assert(goals);
	live  = calloc(w * h, sizeof(uint8_t));
	assert(live);

	n_boxes = 0;
	for (int i = 0; s[i]; i++) {
		switch(s[i]) {
		case '#':	board[i] = wall;
				continue;

		case '.':	// fallthrough
		case '+':	goals[i] = 1; // fallthrough
		case '@':	continue;

		case '*':	goals[i] = 1; // fallthrough
		case '$':	n_boxes++;
				continue;
		default:	continue;
		}
	}

	const int is = sizeof(int);
	state_size = (sizeof(state_t) + (1 + n_boxes) * sizeof(cidx_t) + is - 1)
			/ is * is;

	state_t *state = newstate(NULL);

	for (int i = 0, j = 0; i < w * h; i++) {
		if (goals[i]) mark_live(i);
		if (s[i] == '$' || s[i] == '*')
			state->c[++j] = i;
		else if (s[i] == '@' || s[i] == '+')
			state->c[0] = i;
	}

	return state;
}

void show_board(const state_t *s)
{
	unsigned char b[w * h];
	memcpy(b, board, w * h);

	b[ s->c[0] ] = player;
	for (int i = 1; i <= n_boxes; i++)
		b[ s->c[i] ] = box;

	for (int i = 0; i < w * h; i++) {
		printf((goals[i] ? glyph2 : glyph1)[ b[i] ]);
		if (! ((1 + i) % w))
			putchar('\n');
	}
}

// K&R hash function
inline
void hash(state_t *s)
{
	if (!s->h) {
		register hash_t ha = 0;
		cidx_t *p = s->c;
		for (int i = 0; i <= n_boxes; i++)
			ha = p[i] + 31 * ha;
		s->h = ha;
	}
}

state_t **buckets;
hash_t hash_size, fill_limit, filled;

void extend_table()
{
	int old_size = hash_size;

	if (!old_size) {
		hash_size = 1024;
		filled = 0;
		fill_limit = hash_size * 3 / 4; // 0.75 load factor
	} else {
		hash_size *= 2;
		fill_limit *= 2;
	}

	buckets = realloc(buckets, sizeof(state_t*) * hash_size);
	assert(buckets);

	// rehash
	memset(buckets + old_size, 0, sizeof(state_t*) * (hash_size - old_size));

	const hash_t bits = hash_size - 1;
	for (int i = 0; i < old_size; i++) {
		state_t *head = buckets[i];
		buckets[i] = NULL;
		while (head) {
			state_t *next = head->next;
			const int j = head->h & bits;
			head->next = buckets[j];
			buckets[j] = head;
			head = next;
		}
	}
}

state_t *lookup(state_t *s)
{
	hash(s);
	state_t *f = buckets[s->h & (hash_size - 1)];
	for (; f; f = f->next) {
		if (//(f->h == s->h) &&
			!memcmp(s->c, f->c, sizeof(cidx_t) * (1 + n_boxes)))
			break;
	}

	return f;
}

bool add_to_table(state_t *s)
{
	if (lookup(s)) {
		unnewstate(s);
		return false;
	}

	if (filled++ >= fill_limit)
		extend_table();

	hash_t i = s->h & (hash_size - 1);

	s->next = buckets[i];
	buckets[i] = s;
	return true;
}

bool success(const state_t *s)
{
	for (int i = 1; i <= n_boxes; i++)
		if (!goals[s->c[i]]) return false;
	return true;
}

state_t *move_me(state_t *s, const int dy, const int dx)
{
	const int y = s->c[0] / w;
	const int x = s->c[0] % w;
	const int y1 = y + dy;
	const int x1 = x + dx;
	const int c1 = y1 * w + x1;

	if (y1 < 0 || y1 > h || x1 < 0 || x1 > w
			|| board[c1] == wall)
		return NULL;

	int at_box = 0;
	for (int i = 1; i <= n_boxes; i++) {
		if (s->c[i] == c1) {
			at_box = i;
			break;
		}
	}

	int c2;
	if (at_box) {
		c2 = c1 + dy * w + dx;
		if (board[c2] == wall || !live[c2])
			return NULL;
		for (int i = 1; i <= n_boxes; i++)
			if (s->c[i] == c2) return NULL;
	}

	state_t *n = newstate(s);
	memcpy(n->c + 1, s->c + 1, sizeof(cidx_t) * n_boxes);

	cidx_t *p = n->c;
	p[0] = c1;

	if (at_box) p[at_box] = c2;

	// leet bubble sort
	for (int i = n_boxes; --i; ) {
		cidx_t t = 0;
		for (int j = 1; j < i; j++) {
			if (p[j] > p[j + 1])
				t = p[j], p[j] = p[j+1], p[j+1] = t;
		}
		if (!t) break;
	}

	return n;
}

state_t *next_level, *done;

bool queue_move(state_t *s)
{
	if (!s || !add_to_table(s))
		return false;

	if (success(s)) {
		puts("\nSuccess!");
		done = s;
		return true;
	}

	s->qnext = next_level;
	next_level = s;
	return false;
}

bool do_move(state_t *s)
{
	return     queue_move(move_me(s,  1,  0))
		|| queue_move(move_me(s, -1,  0))
		|| queue_move(move_me(s,  0,  1))
		|| queue_move(move_me(s,  0, -1));
}

void show_moves(const state_t *s)
{
	if (s->prev)
		show_moves(s->prev);
	usleep(200000);
	printf("\033[H");
	show_board(s);
}

int main()
{
	state_t *s = parse_board(

#define BIG 0

#if BIG == 0
		8, 7,
		"#######"
		"#     #"
		"#     #"
		"#. #  #"
		"#. $$ #"
		"#.$$  #"
		"#.#  @#"
		"#######"

#elif BIG == 1
		5, 13,
		"#############"
		"#  #        #"
		"# $$$$$$$  @#"
		"#.......    #"
		"#############"

#elif BIG == 2
		5, 13,
		"#############"
		"#... #      #"
		"#.$$$$$$$  @#"
		"#...        #"
		"#############"

#else
		11, 19,
		"    #####          "
		"    #   #          "
		"    #   #          "
		"  ### #$##         "
		"  #      #         "
		"### #$## #   ######"
		"#   # ## #####   .#"
		"# $   $         ..#"
		"##### ### #@##   .#"
		"    #     #########"
		"    #######        "
#endif
			);

	show_board(s);
	extend_table();
	queue_move(s);
	for (int i = 0; !done; i++) {
		printf("depth %d\r", i);
		fflush(stdout);

		state_t *head = next_level;
		for (next_level = NULL; head && !done; head = head->qnext)
			do_move(head);

		if (!next_level) {
			puts("no solution?");
			return 1;
		}
	}

	printf("press any key to see moves\n");
	getchar(), puts("\033[H\033[J");
	show_moves(done);

#if 0
	free(buckets);
	free(board);
	free(goals);
	free(live);

	while (block_root) {
		void *tmp = block_root->next;
		free(block_root);
		block_root = tmp;
	}
#endif

	return 0;
}


using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SokobanSolver
{
    public class SokobanSolver
    {
        private class Board
        {
            public string Cur { get; internal set; }
            public string Sol { get; internal set; }
            public int X { get; internal set; }
            public int Y { get; internal set; }

            public Board(string cur, string sol, int x, int y)
            {
                Cur = cur;
                Sol = sol;
                X = x;
                Y = y;
            }
        }

        private string destBoard, currBoard;
        private int playerX, playerY, nCols;

        SokobanSolver(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][c];

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

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

        private string Move(int x, int y, int dx, int dy, string trialBoard)
        {

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

            if (trialBoard[newPlayerPos] != ' ')
                return null;

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

            return new string(trial);
        }

        private string Push(int x, int y, int dx, int dy, string trialBoard)
        {

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

            if (trialBoard[newBoxPos] != ' ')
                return null;

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

            return new string(trial);
        }

        private bool IsSolved(string trialBoard)
        {
            for (int i = 0; i < trialBoard.Length; i++)
                if ((destBoard[i] == '.')
                        != (trialBoard[i] == '$'))
                    return false;
            return true;
        }

        private string Solve()
        {
            char[,] dirLabels = { { 'u', 'U' }, { 'r', 'R' }, { 'd', 'D' }, { 'l', 'L' } };
            int[,] dirs = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } };
            ISet<string> history = new HashSet<string>();
            LinkedList<Board> open = new LinkedList<Board>();

            history.Add(currBoard);
            open.AddLast(new Board(currBoard, string.Empty, playerX, playerY));

            while (!open.Count.Equals(0))
            {
                Board item = open.First();
                open.RemoveFirst();
                string cur = item.Cur;
                string sol = item.Sol;
                int x = item.X;
                int y = item.Y;

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

                    // are we standing next to a box ?
                    if (trial[(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.AddLast(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.AddLast(new Board(trial, newSol, x + dx, y + dy));
                            history.Add(trial);
                        }
                    }
                }
            }
            return "No solution";
        }

        public static void Main(string[] a)
        {
            string level = "#######," +
                           "#     #," +
                           "#     #," +
                           "#. #  #," +
                           "#. $$ #," +
                           "#.$$  #," +
                           "#.#  @#," +
                           "#######";
            System.Console.WriteLine("Level:\n");
            foreach (string line in level.Split(','))
            {
                System.Console.WriteLine(line);
            }
            System.Console.WriteLine("\nSolution:\n");
            System.Console.WriteLine(new SokobanSolver(level.Split(',')).Solve());
        }
    }
}


#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <regex>
#include <tuple>
#include <set>
#include <array>
using namespace std;

class Board
{
public:
  vector<vector<char>> sData, dData;
  int px, py;

  Board(string b)
  {
    regex pattern("([^\\n]+)\\n?");
    sregex_iterator end, iter(b.begin(), b.end(), pattern);

    int w = 0;
    vector<string> data;
    for(; iter != end; ++iter){
      data.push_back((*iter)[1]);
      w = max(w, (*iter)[1].length());
    }

    for(int v = 0; v < data.size(); ++v){
      vector<char> sTemp, dTemp;
      for(int u = 0; u < w; ++u){
        if(u > data[v].size()){
          sTemp.push_back(' ');
          dTemp.push_back(' ');
        }else{
          char s = ' ', d = ' ', c = data[v][u];

          if(c == '#')
            s = '#';
          else if(c == '.' || c == '*' || c == '+')
            s = '.';

          if(c == '@' || c == '+'){
            d = '@';
            px = u;
            py = v;
          }else if(c == '$' || c == '*')
            d = '*';

          sTemp.push_back(s);
          dTemp.push_back(d);
        }
      }

      sData.push_back(sTemp);
      dData.push_back(dTemp);
    }
  }

  bool move(int x, int y, int dx, int dy, vector<vector<char>> &data)
  {
    if(sData[y+dy][x+dx] == '#' || data[y+dy][x+dx] != ' ')
      return false;

    data[y][x] = ' ';
    data[y+dy][x+dx] = '@';

    return true;
  }

  bool push(int x, int y, int dx, int dy, vector<vector<char>> &data)
  {
    if(sData[y+2*dy][x+2*dx] == '#' || data[y+2*dy][x+2*dx] != ' ')
      return false;

    data[y][x] = ' ';
    data[y+dy][x+dx] = '@';
    data[y+2*dy][x+2*dx] = '*';

    return true;
  }

  bool isSolved(const vector<vector<char>> &data)
  {
    for(int v = 0; v < data.size(); ++v)
      for(int u = 0; u < data[v].size(); ++u)
        if((sData[v][u] == '.') ^ (data[v][u] == '*'))
          return false;
    return true;
  }

  string solve()
  {
    set<vector<vector<char>>> visited;
    queue<tuple<vector<vector<char>>, string, int, int>> open;

    open.push(make_tuple(dData, "", px, py));
    visited.insert(dData);

    array<tuple<int, int, char, char>, 4> dirs;
    dirs[0] = make_tuple(0, -1, 'u', 'U');
    dirs[1] = make_tuple(1, 0, 'r', 'R');
    dirs[2] = make_tuple(0, 1, 'd', 'D');
    dirs[3] = make_tuple(-1, 0, 'l', 'L');

    while(open.size() > 0){
      vector<vector<char>> temp, cur = get<0>(open.front());
      string cSol = get<1>(open.front());
      int x = get<2>(open.front());
      int y = get<3>(open.front());
      open.pop();

      for(int i = 0; i < 4; ++i){
        temp = cur;
        int dx = get<0>(dirs[i]);
        int dy = get<1>(dirs[i]);

        if(temp[y+dy][x+dx] == '*'){
          if(push(x, y, dx, dy, temp) && (visited.find(temp) == visited.end())){
            if(isSolved(temp))
              return cSol + get<3>(dirs[i]);
            open.push(make_tuple(temp, cSol + get<3>(dirs[i]), x+dx, y+dy));
            visited.insert(temp);
          }
        }else if(move(x, y, dx, dy, temp) && (visited.find(temp) == visited.end())){
          if(isSolved(temp))
            return cSol + get<2>(dirs[i]);
          open.push(make_tuple(temp, cSol + get<2>(dirs[i]), x+dx, y+dy));
          visited.insert(temp);
        }
      }
    }

    return "No solution";
  }
};

int main()
{
  string level =
    "#######\n"
    "#     #\n"
    "#     #\n"
    "#. #  #\n"
    "#. $$ #\n"
    "#.$$  #\n"
    "#.#  @#\n"
    "#######";

  Board b(level);

  cout << level << endl << endl << b.solve() << endl;
  return 0;
}