September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
|
|
@ -58,10 +58,14 @@ Write a program to solve puzzles of this ilk,
|
|||
demonstrating your program by solving the above examples.
|
||||
Extra credit for other interesting examples.
|
||||
|
||||
Related Tasks:
|
||||
|
||||
;Related tasks:
|
||||
* [[A* search algorithm]]
|
||||
* [[Solve a Holy Knight's tour]]
|
||||
* [[Knight's tour]]
|
||||
* [[N-queens problem]]
|
||||
* [[Solve a Hidato puzzle]]
|
||||
* [[Solve a Holy Knight's tour]]
|
||||
* [[Solve a Hopido puzzle]]
|
||||
* [[Solve the no connection puzzle]]
|
||||
* [[Knight's tour]]
|
||||
<br><br>
|
||||
|
|
|
|||
|
|
@ -1,209 +0,0 @@
|
|||
import std.stdio, std.conv, std.string, std.range, std.array, std.typecons, std.algorithm;
|
||||
|
||||
struct {
|
||||
alias BitSet8 = ubyte; // A set of 8 bits.
|
||||
alias Cell = uint;
|
||||
enum : string { unavailableInCell = "#", availableInCell = "." }
|
||||
enum : Cell { unavailableCell = Cell.max, availableCell = 0 }
|
||||
|
||||
this(in string inPuzzle) pure @safe {
|
||||
const rawPuzzle = inPuzzle.splitLines.map!(row => row.split).array;
|
||||
assert(!rawPuzzle.empty);
|
||||
assert(!rawPuzzle[0].empty);
|
||||
assert(rawPuzzle.all!(row => row.length == rawPuzzle[0].length)); // Is rectangular.
|
||||
|
||||
gridWidth = rawPuzzle[0].length;
|
||||
gridHeight = rawPuzzle.length;
|
||||
immutable nMaxCells = gridWidth * gridHeight;
|
||||
grid = new Cell[nMaxCells];
|
||||
auto knownMutable = new bool[nMaxCells + 1];
|
||||
uint nAvailableMutable = nMaxCells;
|
||||
bool[Cell] seenCells; // To avoid duplicate input numbers.
|
||||
|
||||
uint i = 0;
|
||||
foreach (const piece; rawPuzzle.join) {
|
||||
if (piece == unavailableInCell) {
|
||||
nAvailableMutable--;
|
||||
grid[i++] = unavailableCell;
|
||||
continue;
|
||||
} else if (piece == availableInCell) {
|
||||
grid[i] = availableCell;
|
||||
} else {
|
||||
immutable cell = piece.to!Cell;
|
||||
assert(cell > 0 && cell <= nMaxCells);
|
||||
assert(cell !in seenCells);
|
||||
seenCells[cell] = true;
|
||||
knownMutable[cell] = true;
|
||||
grid[i] = cell;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
known = knownMutable.idup;
|
||||
nAvailable = nAvailableMutable;
|
||||
}
|
||||
|
||||
@disable this();
|
||||
|
||||
|
||||
auto solve() pure nothrow @safe @nogc
|
||||
out(result) {
|
||||
if (!result.isNull) {
|
||||
// Can't verify 'result' here because it's const.
|
||||
// assert(!result.get.join.canFind(availableCell.text));
|
||||
|
||||
assert(!grid.canFind(availableCell));
|
||||
auto values = grid.filter!(c => c != unavailableCell);
|
||||
auto interval = iota(reduce!min(values.front, values.dropOne),
|
||||
reduce!max(values.front, values.dropOne) + 1);
|
||||
assert(values.walkLength == interval.length);
|
||||
assert(interval.all!(c => values.count(c) == 1)); // Quadratic.
|
||||
}
|
||||
} body {
|
||||
auto result = grid
|
||||
.map!(c => (c == unavailableCell) ? unavailableInCell : c.text)
|
||||
.chunks(gridWidth);
|
||||
alias OutRange = Nullable!(typeof(result));
|
||||
|
||||
const start = findStart;
|
||||
if (start.isNull)
|
||||
return OutRange();
|
||||
|
||||
search(start.r, start.c, start.cell + 1, 1);
|
||||
if (start.cell > 1) {
|
||||
immutable direction = -1;
|
||||
search(start.r, start.c, start.cell + direction, direction);
|
||||
}
|
||||
|
||||
if (grid.any!(c => c == availableCell))
|
||||
return OutRange();
|
||||
else
|
||||
return OutRange(result);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
bool search(in uint r, in uint c, in Cell cell, in int direction)
|
||||
pure nothrow @safe @nogc {
|
||||
if ((cell > nAvailable && direction > 0) || (cell == 0 && direction < 0) ||
|
||||
(cell == nAvailable && known[cell]))
|
||||
return true; // One solution found.
|
||||
|
||||
immutable neighbors = getNeighbors(r, c);
|
||||
|
||||
if (known[cell]) {
|
||||
foreach (immutable i, immutable rc; shifts) {
|
||||
if (neighbors & (1u << i)) {
|
||||
immutable c2 = c + rc[0],
|
||||
r2 = r + rc[1];
|
||||
if (grid[r2 * gridWidth + c2] == cell)
|
||||
if (search(r2, c2, cell + direction, direction))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (immutable i, immutable rc; shifts) {
|
||||
if (neighbors & (1u << i)) {
|
||||
immutable c2 = c + rc[0],
|
||||
r2 = r + rc[1],
|
||||
pos = r2 * gridWidth + c2;
|
||||
if (grid[pos] == availableCell) {
|
||||
grid[pos] = cell; // Try.
|
||||
if (search(r2, c2, cell + direction, direction))
|
||||
return true;
|
||||
grid[pos] = availableCell; // Restore.
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
BitSet8 getNeighbors(in uint r, in uint c) const pure nothrow @safe @nogc {
|
||||
typeof(return) usable = 0;
|
||||
|
||||
foreach (immutable i, immutable rc; shifts) {
|
||||
immutable c2 = c + rc[0],
|
||||
r2 = r + rc[1];
|
||||
if (c2 >= gridWidth || r2 >= gridHeight)
|
||||
continue;
|
||||
if (grid[r2 * gridWidth + c2] != unavailableCell)
|
||||
usable |= (1u << i);
|
||||
}
|
||||
|
||||
return usable;
|
||||
}
|
||||
|
||||
|
||||
auto findStart() const pure nothrow @safe @nogc {
|
||||
alias Triple = Tuple!(uint,"r", uint,"c", Cell,"cell");
|
||||
Nullable!Triple result;
|
||||
|
||||
auto cell = Cell.max;
|
||||
foreach (immutable r; 0 .. gridHeight) {
|
||||
foreach (immutable c; 0 .. gridWidth) {
|
||||
immutable pos = gridWidth * r + c;
|
||||
if (grid[pos] != availableCell &&
|
||||
grid[pos] != unavailableCell && grid[pos] < cell) {
|
||||
cell = grid[pos];
|
||||
result = Triple(r, c, cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static immutable int[2][4] shifts = [[0, -1], [0, 1], [-1, 0], [1, 0]];
|
||||
immutable uint gridWidth, gridHeight;
|
||||
immutable int nAvailable;
|
||||
immutable bool[] known; // Given known cells of the puzzle.
|
||||
Cell[] grid; // Flattened mutable game grid.
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
// enum NumbrixPuzzle to catch malformed puzzles at compile-time.
|
||||
enum puzzle1 = ". . . . . . . . .
|
||||
. . 46 45 . 55 74 . .
|
||||
. 38 . . 43 . . 78 .
|
||||
. 35 . . . . . 71 .
|
||||
. . 33 . . . 59 . .
|
||||
. 17 . . . . . 67 .
|
||||
. 18 . . 11 . . 64 .
|
||||
. . 24 21 . 1 2 . .
|
||||
. . . . . . . . .".NumbrixPuzzle;
|
||||
|
||||
enum puzzle2 = ". . . . . . . . .
|
||||
. 11 12 15 18 21 62 61 .
|
||||
. 6 . . . . . 60 .
|
||||
. 33 . . . . . 57 .
|
||||
. 32 . . . . . 56 .
|
||||
. 37 . 1 . . . 73 .
|
||||
. 38 . . . . . 72 .
|
||||
. 43 44 47 48 51 76 77 .
|
||||
. . . . . . . . .".NumbrixPuzzle;
|
||||
|
||||
enum puzzle3 = "17 . . . 11 . . . 59
|
||||
. 15 . . 6 . . 61 .
|
||||
. . 3 . . . 63 . .
|
||||
. . . . 66 . . . .
|
||||
23 24 . 68 67 78 . 54 55
|
||||
. . . . 72 . . . .
|
||||
. . 35 . . . 49 . .
|
||||
. 29 . . 40 . . 47 .
|
||||
31 . . . 39 . . . 45".NumbrixPuzzle;
|
||||
|
||||
|
||||
foreach (puzzle; [puzzle1, puzzle2, puzzle3]) {
|
||||
auto solution = puzzle.solve; // Solved at run-time.
|
||||
if (solution.isNull)
|
||||
writeln("No solution found for puzzle.\n");
|
||||
else
|
||||
writefln("One solution:\n%(%-(%2s %)\n%)\n", solution);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,90 +0,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 := []
|
||||
nCells := maxCols := 0
|
||||
every line := !&input do {
|
||||
put(p,[: gencells(line) :])
|
||||
maxCols <:= *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["_"] := 0; 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] = (val|0)); end
|
||||
method visit(r,c); return (/best, validPos(r,c), Pos(r,c)); end
|
||||
|
||||
method validPos(r,c)
|
||||
v := val+1 # number we're looking for
|
||||
xv := puzzle[r,c] | fail
|
||||
if (xv ~= 0) & (xv != v) then fail
|
||||
if xv = (0|v) then {
|
||||
ancestor := self
|
||||
while xl := (ancestor := \ancestor.getParent()).getLoc() do
|
||||
if (xl.r = r) & (xl.c = c) then fail
|
||||
return
|
||||
}
|
||||
end
|
||||
|
||||
initially
|
||||
val := val+1
|
||||
if atEnd() then return best := self
|
||||
QMouse(puzzle, visit(loc.r-1,loc.c) , self, val) # North
|
||||
QMouse(puzzle, visit(loc.r, loc.c+1), self, val) # East
|
||||
QMouse(puzzle, visit(loc.r+1,loc.c), self, val) # South
|
||||
QMouse(puzzle, visit(loc.r, loc.c-1), self, val) # West
|
||||
end
|
||||
98
Task/Solve-a-Numbrix-puzzle/Python/solve-a-numbrix-puzzle.py
Normal file
98
Task/Solve-a-Numbrix-puzzle/Python/solve-a-numbrix-puzzle.py
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
from sys import stdout
|
||||
neighbours = [[-1, 0], [0, -1], [1, 0], [0, 1]]
|
||||
exists = []
|
||||
lastNumber = 0
|
||||
wid = 0
|
||||
hei = 0
|
||||
|
||||
|
||||
def find_next(pa, x, y, z):
|
||||
for i in range(4):
|
||||
a = x + neighbours[i][0]
|
||||
b = y + neighbours[i][1]
|
||||
if wid > a > -1 and hei > b > -1:
|
||||
if pa[a][b] == z:
|
||||
return a, b
|
||||
|
||||
return -1, -1
|
||||
|
||||
|
||||
def find_solution(pa, x, y, z):
|
||||
if z > lastNumber:
|
||||
return 1
|
||||
if exists[z] == 1:
|
||||
s = find_next(pa, x, y, z)
|
||||
if s[0] < 0:
|
||||
return 0
|
||||
return find_solution(pa, s[0], s[1], z + 1)
|
||||
|
||||
for i in range(4):
|
||||
a = x + neighbours[i][0]
|
||||
b = y + neighbours[i][1]
|
||||
if wid > a > -1 and hei > b > -1:
|
||||
if pa[a][b] == 0:
|
||||
pa[a][b] = z
|
||||
r = find_solution(pa, a, b, z + 1)
|
||||
if r == 1:
|
||||
return 1
|
||||
pa[a][b] = 0
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def solve(pz, w, h):
|
||||
global lastNumber, wid, hei, exists
|
||||
|
||||
lastNumber = w * h
|
||||
wid = w
|
||||
hei = h
|
||||
exists = [0 for j in range(lastNumber + 1)]
|
||||
|
||||
pa = [[0 for j in range(h)] for i in range(w)]
|
||||
st = pz.split()
|
||||
idx = 0
|
||||
for j in range(h):
|
||||
for i in range(w):
|
||||
if st[idx] == ".":
|
||||
idx += 1
|
||||
else:
|
||||
pa[i][j] = int(st[idx])
|
||||
exists[pa[i][j]] = 1
|
||||
idx += 1
|
||||
|
||||
x = 0
|
||||
y = 0
|
||||
t = w * h + 1
|
||||
for j in range(h):
|
||||
for i in range(w):
|
||||
if pa[i][j] != 0 and pa[i][j] < t:
|
||||
t = pa[i][j]
|
||||
x = i
|
||||
y = j
|
||||
|
||||
return find_solution(pa, x, y, t + 1), pa
|
||||
|
||||
|
||||
def show_result(r):
|
||||
if r[0] == 1:
|
||||
for j in range(hei):
|
||||
for i in range(wid):
|
||||
stdout.write(" {:0{}d}".format(r[1][i][j], 2))
|
||||
print()
|
||||
else:
|
||||
stdout.write("No Solution!\n")
|
||||
|
||||
print()
|
||||
|
||||
|
||||
r = solve(". . . . . . . . . . . 46 45 . 55 74 . . . 38 . . 43 . . 78 . . 35 . . . . . 71 . . . 33 . . . 59 . . . 17"
|
||||
" . . . . . 67 . . 18 . . 11 . . 64 . . . 24 21 . 1 2 . . . . . . . . . . .", 9, 9)
|
||||
show_result(r)
|
||||
|
||||
r = solve(". . . . . . . . . . 11 12 15 18 21 62 61 . . 6 . . . . . 60 . . 33 . . . . . 57 . . 32 . . . . . 56 . . 37"
|
||||
" . 1 . . . 73 . . 38 . . . . . 72 . . 43 44 47 48 51 76 77 . . . . . . . . . .", 9, 9)
|
||||
show_result(r)
|
||||
|
||||
r = solve("17 . . . 11 . . . 59 . 15 . . 6 . . 61 . . . 3 . . . 63 . . . . . . 66 . . . . 23 24 . 68 67 78 . 54 55"
|
||||
" . . . . 72 . . . . . . 35 . . . 49 . . . 29 . . 40 . . 47 . 31 . . . 39 . . . 45", 9, 9)
|
||||
show_result(r)
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
/// @Author: Alexandre Felipe (o.alexandre.felipe@gmail.com)
|
||||
/// @Date: 2017-May-10
|
||||
///
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// NumbrixSolver ///
|
||||
/// Solve the puzzle, by using system verilog randomization engine ///
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
class NumbrixSolver;
|
||||
rand int solvedBoard[][];
|
||||
int fixedBoard[][];
|
||||
int numCells;
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// Dynamically resize the board accordingly to the size of the reference///
|
||||
/// board ///
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
constraint height {
|
||||
solvedBoard.size == fixedBoard.size;
|
||||
}
|
||||
constraint width {
|
||||
foreach(solvedBoard[i]) solvedBoard[i].size == fixedBoard[i].size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// Fix the positions defined in the input board ///
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
constraint fixed {
|
||||
foreach(solvedBoard[i]) foreach(solvedBoard[i][j])
|
||||
if(fixedBoard[i][j] != 0)solvedBoard[i][j] == fixedBoard[i][j];
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// Ensures that the whole board is filled from the number with numbers ///
|
||||
/// 1,2,3,...,numCells ///
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
constraint range {
|
||||
foreach(solvedBoard[i])foreach(solvedBoard[i][j])
|
||||
solvedBoard[i][j] inside {[1:numCells]};
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// Ensures that there is no repeated number, consequently every number ///
|
||||
/// is present on the board ///
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
constraint uniqueness {
|
||||
foreach(solvedBoard[i1]) foreach(solvedBoard[i1][j1])
|
||||
foreach(solvedBoard[i2]) foreach(solvedBoard[i2][j2])
|
||||
if((i1 != i2) || (j1 != j2)) solvedBoard[i1][j1] != solvedBoard[i2][j2];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// Ensures that exists one direction connecting the numbers in ///
|
||||
/// increasing order ///
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
constraint f_seq {
|
||||
foreach(solvedBoard[i])foreach(solvedBoard[i][j])
|
||||
(solvedBoard[i][j] == (numCells)) ||
|
||||
(solvedBoard[(i < solvedBoard.size-1) ? (i+1): i][j] ==
|
||||
solvedBoard[i][j]+1) ||
|
||||
(solvedBoard[i][(j < solvedBoard[i].size - 1) ? j+1: j] ==
|
||||
solvedBoard[i][j]+1) ||
|
||||
(solvedBoard[(i > 0) ? i-1: i][j] ==
|
||||
solvedBoard[i][j]+1) ||
|
||||
(solvedBoard[i][(j > 0)? j-1:j] ==
|
||||
solvedBoard[i][j]+1);
|
||||
}
|
||||
|
||||
|
||||
function void pre_randomize();
|
||||
// the multiplication is not supported in the constraints
|
||||
numCells = fixedBoard.size * fixedBoard[0].size;
|
||||
endfunction
|
||||
function void printSolvedBoard();
|
||||
foreach(solvedBoard[i]) begin
|
||||
foreach(solvedBoard[j]) begin
|
||||
$write("%4d", solvedBoard[i][j]);
|
||||
end
|
||||
$display("");
|
||||
end
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// SolveNumBrix: A program demonstrating how to use NumbrixSolver class ///
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
program SolveNumbrix;
|
||||
NumbrixSolver board;
|
||||
initial begin
|
||||
board = new;
|
||||
board.fixedBoard = '{
|
||||
'{0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
'{0, 0, 46, 45, 0, 55, 74, 0, 0},
|
||||
'{0, 38, 0, 0, 43, 0, 0, 78, 0},
|
||||
'{0, 35, 0, 0, 0, 0, 0, 71, 0},
|
||||
'{0, 0, 33, 0, 0, 0, 59, 0, 0},
|
||||
'{0, 17, 0, 0, 0, 0, 0, 67, 0},
|
||||
'{0, 18, 0, 0, 11, 0, 0, 64, 0},
|
||||
'{0, 0, 24, 21, 0, 1, 2, 0, 0},
|
||||
'{0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
if(board.randomize()) begin
|
||||
$display("Solution for the Example 1");
|
||||
board.printSolvedBoard();
|
||||
end
|
||||
else begin
|
||||
$display("Failed to solve Example 1");
|
||||
end
|
||||
|
||||
board.fixedBoard = '{
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 11, 12, 15, 18, 21, 62, 61, 0},
|
||||
{0, 6, 0, 0, 0, 0, 0, 60, 0},
|
||||
{0, 33, 0, 0, 0, 0, 0, 57, 0},
|
||||
{0, 32, 0, 0, 0, 0, 0, 56, 0},
|
||||
{0, 37, 0, 1, 0, 0, 0, 73, 0},
|
||||
{0, 38, 0, 0, 0, 0, 0, 72, 0},
|
||||
{0, 43, 44, 47, 48, 51, 76, 77, 0},
|
||||
'{0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
|
||||
if(board.randomize()) begin
|
||||
$display("Solution for the Example 2");
|
||||
board.printSolvedBoard();
|
||||
end
|
||||
else begin
|
||||
$display("Failed to solve Example 2");
|
||||
end
|
||||
$finish;
|
||||
end
|
||||
endprogram
|
||||
58
Task/Solve-a-Numbrix-puzzle/Zkl/solve-a-numbrix-puzzle-1.zkl
Normal file
58
Task/Solve-a-Numbrix-puzzle/Zkl/solve-a-numbrix-puzzle-1.zkl
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// Solve Hidato/Hopido/Numbrix puzzles
|
||||
class Puzzle{ // hold info concerning this puzzle
|
||||
var board, nrows,ncols, cells,
|
||||
start, // (r,c) where 1 is located, Void if no 1
|
||||
terminated, // if board holds highest numbered cell
|
||||
given, // all the pre-loaded cells
|
||||
adj, // a list of (r,c) that are valid next cells
|
||||
;
|
||||
|
||||
fcn print_board{
|
||||
d:=Dictionary(-1," ", 0,"__");
|
||||
foreach r in (board){
|
||||
r.pump(String,'wrap(c){ "%2s ".fmt(d.find(c,c)) }).println();
|
||||
}
|
||||
}
|
||||
fcn init(s,adjacent){
|
||||
adj=adjacent;
|
||||
lines:=s.split("\n");
|
||||
ncols,nrows=lines[0].split().len(),lines.len();
|
||||
board=nrows.pump(List(), ncols.pump(List(),-1).copy);
|
||||
given,start=List(),Void;
|
||||
cells,terminated=0,True;
|
||||
foreach r,row in (lines.enumerate()){
|
||||
foreach c,cell in (row.split().enumerate()){
|
||||
if(cell=="X") continue; // X == not in play, leave at -1
|
||||
cells+=1;
|
||||
val:=cell.toInt();
|
||||
board[r][c]=val;
|
||||
given.append(val);
|
||||
if(val==1) start=T(r,c);
|
||||
}
|
||||
}
|
||||
println("Number of cells = ",cells);
|
||||
if(not given.holds(cells)){ given.append(cells); terminated=False; }
|
||||
given=given.filter().sort();
|
||||
}
|
||||
fcn solve{ //-->Bool
|
||||
if(start) return(_solve(start.xplode()));
|
||||
foreach r,c in (nrows,ncols){
|
||||
if(board[r][c]==0 and _solve(r,c)) return(True);
|
||||
}
|
||||
False
|
||||
}
|
||||
fcn [private] _solve(r,c,n=1, next=0){
|
||||
if(n>given[-1]) return(True);
|
||||
if(not ( (0<=r<nrows) and (0<=c<ncols) )) return(False);
|
||||
if(board[r][c] and board[r][c]!=n) return(False);
|
||||
if(terminated and 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;
|
||||
foreach i,j in (adj){ if(self.fcn(r+i,c+j,n+1, next)) return(True) }
|
||||
board[r][c]=back;
|
||||
False
|
||||
}
|
||||
} // Puzzle
|
||||
37
Task/Solve-a-Numbrix-puzzle/Zkl/solve-a-numbrix-puzzle-2.zkl
Normal file
37
Task/Solve-a-Numbrix-puzzle/Zkl/solve-a-numbrix-puzzle-2.zkl
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
hi1:= // 0==empty cell, X==not a cell
|
||||
#<<<
|
||||
"0 0 0 0 0 0 0 0 0
|
||||
0 0 46 45 0 55 74 0 0
|
||||
0 38 0 0 43 0 0 78 0
|
||||
0 35 0 0 0 0 0 71 0
|
||||
0 0 33 0 0 0 59 0 0
|
||||
0 17 0 0 0 0 0 67 0
|
||||
0 18 0 0 11 0 0 64 0
|
||||
0 0 24 21 0 1 2 0 0
|
||||
0 0 0 0 0 0 0 0 0";
|
||||
#<<<
|
||||
|
||||
hi2:= // 0==empty cell, X==not a cell
|
||||
#<<<
|
||||
"0 0 0 0 0 0 0 0 0
|
||||
0 11 12 15 18 21 62 61 0
|
||||
0 6 0 0 0 0 0 60 0
|
||||
0 33 0 0 0 0 0 57 0
|
||||
0 32 0 0 0 0 0 56 0
|
||||
0 37 0 1 0 0 0 73 0
|
||||
0 38 0 0 0 0 0 72 0
|
||||
0 43 44 47 48 51 76 77 0
|
||||
0 0 0 0 0 0 0 0 0";
|
||||
#<<<
|
||||
adjacent:=T( T(-1,0),
|
||||
T( 0,-1), T( 0,1),
|
||||
T( 1,0) );
|
||||
|
||||
foreach hi in (T(hi1,hi2)){
|
||||
puzzle:=Puzzle(hi); puzzle.adjacent=adjacent;
|
||||
puzzle.print_board();
|
||||
puzzle.solve();
|
||||
println();
|
||||
puzzle.print_board();
|
||||
println();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue