September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
|
|
@ -15,9 +15,14 @@ Example:
|
|||
|
||||
Extra credits are available for other interesting designs.
|
||||
|
||||
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 Numbrix puzzle]]
|
||||
* [[Solve the no connection puzzle]]
|
||||
* [[Knight's tour]]
|
||||
<br><br>
|
||||
|
|
|
|||
|
|
@ -1,114 +0,0 @@
|
|||
import std.stdio, std.conv, std.string, std.range, std.algorithm, std.typecons;
|
||||
|
||||
|
||||
struct HopidoPuzzle {
|
||||
private alias InputCellBaseType = char;
|
||||
private enum InputCell : InputCellBaseType { available = '#', unavailable = '.' }
|
||||
private alias Cell = uint;
|
||||
private enum : Cell { unknownCell = 0, unavailableCell = Cell.max } // Special Cell values.
|
||||
|
||||
// Neighbors, [shift row, shift column].
|
||||
private static immutable int[2][8] shifts = [[-2, -2], [2, -2], [-2, 2], [2, 2],
|
||||
[ 0, -3], [0, 3], [-3, 0], [3, 0]];
|
||||
|
||||
private immutable size_t gridWidth, gridHeight;
|
||||
private immutable Cell nAvailableCells;
|
||||
private /*immutable*/ const InputCell[] flatPuzzle;
|
||||
private Cell[] grid; // Flattened mutable game grid.
|
||||
|
||||
@disable this();
|
||||
|
||||
|
||||
this(in string[] rawPuzzle) pure @safe
|
||||
in {
|
||||
assert(!rawPuzzle.empty);
|
||||
assert(!rawPuzzle[0].empty);
|
||||
assert(rawPuzzle.all!(row => row.length == rawPuzzle[0].length)); // Is rectangular.
|
||||
|
||||
// Has at least one start point.
|
||||
assert(rawPuzzle.join.representation.canFind(InputCell.available));
|
||||
} body {
|
||||
//immutable puzzle = rawPuzzle.to!(InputCell[][]);
|
||||
immutable puzzle = rawPuzzle.map!representation.array.to!(InputCell[][]);
|
||||
|
||||
gridWidth = puzzle[0].length;
|
||||
gridHeight = puzzle.length;
|
||||
flatPuzzle = puzzle.join;
|
||||
nAvailableCells = flatPuzzle.representation.count!(ic => ic == InputCell.available);
|
||||
|
||||
grid = flatPuzzle
|
||||
.representation
|
||||
.map!(ic => ic == InputCell.available ? unknownCell : unavailableCell)
|
||||
.array;
|
||||
}
|
||||
|
||||
|
||||
Nullable!(string[][]) solve() pure /*nothrow*/ @safe
|
||||
out(result) {
|
||||
if (!result.isNull)
|
||||
assert(!grid.canFind(unknownCell));
|
||||
} body {
|
||||
// Try all possible start positions.
|
||||
foreach (immutable r; 0 .. gridHeight) {
|
||||
foreach (immutable c; 0 .. gridWidth) {
|
||||
immutable pos = r * gridWidth + c;
|
||||
if (grid[pos] == unknownCell) {
|
||||
immutable Cell startCell = 1; // To lay the first cell value.
|
||||
grid[pos] = startCell; // Try.
|
||||
if (search(r, c, startCell + 1)) {
|
||||
auto result = zip(flatPuzzle, grid)
|
||||
//.map!({p, c} => ...
|
||||
.map!(pc => (pc[0] == InputCell.available) ?
|
||||
pc[1].text :
|
||||
InputCellBaseType(pc[0]).text)
|
||||
.array
|
||||
.chunks(gridWidth)
|
||||
.array;
|
||||
return typeof(return)(result);
|
||||
}
|
||||
grid[pos] = unknownCell; // Restore.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return typeof(return)();
|
||||
}
|
||||
|
||||
|
||||
private bool search(in size_t r, in size_t c, in Cell cell) pure nothrow @safe @nogc {
|
||||
if (cell > nAvailableCells)
|
||||
return true; // One solution found.
|
||||
|
||||
foreach (immutable sh; shifts) {
|
||||
immutable r2 = r + sh[0],
|
||||
c2 = c + sh[1],
|
||||
pos = r2 * gridWidth + c2;
|
||||
// No need to test for >= 0 because uint wraps around.
|
||||
if (c2 < gridWidth && r2 < gridHeight && grid[pos] == unknownCell) {
|
||||
grid[pos] = cell; // Try.
|
||||
if (search(r2, c2, cell + 1))
|
||||
return true;
|
||||
grid[pos] = unknownCell; // Restore.
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void main() @safe {
|
||||
// enum HopidoPuzzle to catch malformed puzzles at compile-time.
|
||||
enum puzzle = ".##.##.
|
||||
#######
|
||||
#######
|
||||
.#####.
|
||||
..###..
|
||||
...#...".split.HopidoPuzzle;
|
||||
|
||||
immutable solution = puzzle.solve; // Solved at run-time.
|
||||
if (solution.isNull)
|
||||
writeln("No solution found.");
|
||||
else
|
||||
writefln("One solution:\n%(%-(%2s %)\n%)", solution);
|
||||
}
|
||||
|
|
@ -1,98 +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 := [[-1],[-1]]
|
||||
nCells := maxCols := 0
|
||||
every line := !&input do {
|
||||
put(p,[: -1 | -1 | gencells(line) | -1 | -1 :])
|
||||
maxCols <:= *p[-1]
|
||||
}
|
||||
every put(p, [-1]|[-1])
|
||||
# Now normalize all rows to the same length
|
||||
every i := 1 to *p do p[i] := [: !p[i] | (|-1\(maxCols - *p[i])) :]
|
||||
return p
|
||||
end
|
||||
|
||||
procedure gencells(s)
|
||||
static WS, NWS
|
||||
initial {
|
||||
NWS := ~(WS := " \t")
|
||||
cMap := table() # Map to/from internal model
|
||||
cMap["#"] := -1; cMap["_"] := 0
|
||||
cMap[-1] := " "; cMap[0] := "_"
|
||||
}
|
||||
|
||||
s ? while not pos(0) do {
|
||||
w := (tab(many(WS))|"", tab(many(NWS))) | break
|
||||
w := numeric(\cMap[w]|w)
|
||||
if -1 ~= w then nCells +:= 1
|
||||
suspend w
|
||||
}
|
||||
end
|
||||
|
||||
procedure showPuzzle(label, p)
|
||||
write(label," with ",nCells," cells:")
|
||||
every r := !p do {
|
||||
every c := !r do writes(right((\cMap[c]|c),*nCells+1))
|
||||
write()
|
||||
}
|
||||
return p
|
||||
end
|
||||
|
||||
procedure findStart(p)
|
||||
if \p[r := !*p][c := !*p[r]] = 1 then return Pos(r,c)
|
||||
end
|
||||
|
||||
procedure solvePuzzle(puzzle)
|
||||
if path := \best then {
|
||||
repeat {
|
||||
loc := path.getLoc()
|
||||
puzzle[loc.r][loc.c] := path.getVal()
|
||||
path := \path.getParent() | break
|
||||
}
|
||||
return puzzle
|
||||
}
|
||||
end
|
||||
|
||||
class QMouse(puzzle, loc, parent, val)
|
||||
|
||||
method getVal(); return val; end
|
||||
method getLoc(); return loc; end
|
||||
method getParent(); return parent; end
|
||||
method atEnd(); return nCells = val; end
|
||||
|
||||
method visit(r,c)
|
||||
if /best & validPos(r,c) then return Pos(r,c)
|
||||
end
|
||||
|
||||
method validPos(r,c)
|
||||
v := val+1
|
||||
xv := (0 <= puzzle[r][c]) | fail
|
||||
if xv = (v|0) then { # make sure this path hasn't already gone there
|
||||
ancestor := self
|
||||
while xl := (ancestor := \ancestor.getParent()).getLoc() do
|
||||
if (xl.r = r) & (xl.c = c) then fail
|
||||
return
|
||||
}
|
||||
end
|
||||
|
||||
initially
|
||||
val := val+1
|
||||
if atEnd() then return best := self
|
||||
QMouse(puzzle, visit(loc.r-3,loc.c), self, val)
|
||||
QMouse(puzzle, visit(loc.r-2,loc.c-2), self, val)
|
||||
QMouse(puzzle, visit(loc.r, loc.c-3), self, val)
|
||||
QMouse(puzzle, visit(loc.r+2,loc.c-2), self, val)
|
||||
QMouse(puzzle, visit(loc.r+3,loc.c), self, val)
|
||||
QMouse(puzzle, visit(loc.r+2,loc.c+2), self, val)
|
||||
QMouse(puzzle, visit(loc.r, loc.c+3), self, val)
|
||||
QMouse(puzzle, visit(loc.r-2,loc.c+2), self, val)
|
||||
end
|
||||
63
Task/Solve-a-Hopido-puzzle/Python/solve-a-hopido-puzzle.py
Normal file
63
Task/Solve-a-Hopido-puzzle/Python/solve-a-hopido-puzzle.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
from sys import stdout
|
||||
|
||||
neighbours = [[2, 2], [-2, 2], [2, -2], [-2, -2], [3, 0], [0, 3], [-3, 0], [0, -3]]
|
||||
cnt = 0
|
||||
pWid = 0
|
||||
pHei = 0
|
||||
|
||||
|
||||
def is_valid(a, b):
|
||||
return -1 < a < pWid and -1 < b < pHei
|
||||
|
||||
|
||||
def iterate(pa, x, y, v):
|
||||
if v > cnt:
|
||||
return 1
|
||||
|
||||
for i in range(len(neighbours)):
|
||||
a = x + neighbours[i][0]
|
||||
b = y + neighbours[i][1]
|
||||
if is_valid(a, b) and pa[a][b] == 0:
|
||||
pa[a][b] = v
|
||||
r = iterate(pa, a, b, v + 1)
|
||||
if r == 1:
|
||||
return r
|
||||
pa[a][b] = 0
|
||||
return 0
|
||||
|
||||
|
||||
def solve(pz, w, h):
|
||||
global cnt, pWid, pHei
|
||||
|
||||
pa = [[-1 for j in range(h)] for i in range(w)]
|
||||
f = 0
|
||||
pWid = w
|
||||
pHei = h
|
||||
for j in range(h):
|
||||
for i in range(w):
|
||||
if pz[f] == "1":
|
||||
pa[i][j] = 0
|
||||
cnt += 1
|
||||
f += 1
|
||||
|
||||
for y in range(h):
|
||||
for x in range(w):
|
||||
if pa[x][y] == 0:
|
||||
pa[x][y] = 1
|
||||
if 1 == iterate(pa, x, y, 2):
|
||||
return 1, pa
|
||||
pa[x][y] = 0
|
||||
|
||||
return 0, pa
|
||||
|
||||
r = solve("011011011111111111111011111000111000001000", 7, 6)
|
||||
if r[0] == 1:
|
||||
for j in range(6):
|
||||
for i in range(7):
|
||||
if r[1][i][j] == -1:
|
||||
stdout.write(" ")
|
||||
else:
|
||||
stdout.write(" {:0{}d}".format(r[1][i][j], 2))
|
||||
print()
|
||||
else:
|
||||
stdout.write("No solution!")
|
||||
21
Task/Solve-a-Hopido-puzzle/Zkl/solve-a-hopido-puzzle.zkl
Normal file
21
Task/Solve-a-Hopido-puzzle/Zkl/solve-a-hopido-puzzle.zkl
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
hi:= // 0==empty cell, X==not a cell
|
||||
#<<<
|
||||
" X 0 0 X 0 0 X
|
||||
0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0
|
||||
X 0 0 0 0 0 X
|
||||
X X 0 0 0 X X
|
||||
X X X 0 X X X";
|
||||
#<<<
|
||||
adjacent:=T( T(-3,0),
|
||||
T(-2,-2), T(-2,2),
|
||||
T(0,-3), T(0,3),
|
||||
T(2,-2), T(2,2),
|
||||
T(3,0) );
|
||||
|
||||
puzzle:=Puzzle(hi,adjacent);
|
||||
puzzle.print_board();
|
||||
puzzle.solve();
|
||||
println();
|
||||
puzzle.print_board();
|
||||
println();
|
||||
Loading…
Add table
Add a link
Reference in a new issue