Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
145
Task/Sokoban/D/sokoban-1.d
Normal file
145
Task/Sokoban/D/sokoban-1.d
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
import std.string, std.typecons, std.exception, std.algorithm;
|
||||
import queue_usage2; // No queue in Phobos 2.064.
|
||||
|
||||
const struct Board {
|
||||
private enum El { floor = ' ', wall = '#', goal = '.',
|
||||
box = '$', player = '@', boxOnGoal='*' }
|
||||
private alias CTable = string;
|
||||
private immutable size_t ncols;
|
||||
private immutable CTable sData, dData;
|
||||
private immutable int playerx, playery;
|
||||
|
||||
this(in string[] board) immutable pure nothrow @safe
|
||||
in {
|
||||
foreach (const row; board) {
|
||||
assert(row.length == board[0].length,
|
||||
"Unequal board rows.");
|
||||
foreach (immutable c; row)
|
||||
assert(c.inPattern(" #.$@*"), "Not valid input");
|
||||
}
|
||||
} body {
|
||||
/*static*/ immutable sMap =
|
||||
[' ':' ', '.':'.', '@':' ', '#':'#', '$':' '];
|
||||
/*static*/ immutable dMap =
|
||||
[' ':' ', '.':' ', '@':'@', '#':' ', '$':'*'];
|
||||
ncols = board[0].length;
|
||||
|
||||
int plx = 0, ply = 0;
|
||||
CTable sDataBuild, dDataBuild;
|
||||
|
||||
foreach (immutable r, const row; board)
|
||||
foreach (immutable c, const ch; row) {
|
||||
sDataBuild ~= sMap[ch];
|
||||
dDataBuild ~= dMap[ch];
|
||||
if (ch == El.player) {
|
||||
plx = c;
|
||||
ply = r;
|
||||
}
|
||||
}
|
||||
|
||||
this.sData = sDataBuild;
|
||||
this.dData = dDataBuild;
|
||||
this.playerx = plx;
|
||||
this.playery = ply;
|
||||
}
|
||||
|
||||
private bool move(in int x, in int y, in int dx,
|
||||
in int dy, ref CTable data)
|
||||
const pure nothrow /*@safe*/ {
|
||||
if (sData[(y + dy) * ncols + x + dx] == El.wall ||
|
||||
data[(y + dy) * ncols + x + dx] != El.floor)
|
||||
return false;
|
||||
|
||||
auto data2 = data.dup;
|
||||
data2[y * ncols + x] = El.floor;
|
||||
data2[(y + dy) * ncols + x + dx] = El.player;
|
||||
data = data2.assumeUnique; // Not enforced.
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool push(in int x, in int y, in int dx,
|
||||
in int dy, ref CTable data)
|
||||
const pure nothrow /*@safe*/ {
|
||||
if (sData[(y + 2 * dy) * ncols + x + 2 * dx] == El.wall ||
|
||||
data[(y + 2 * dy) * ncols + x + 2 * dx] != El.floor)
|
||||
return false;
|
||||
|
||||
auto data2 = data.dup;
|
||||
data2[y * ncols + x] = El.floor;
|
||||
data2[(y + dy) * ncols + x + dx] = El.player;
|
||||
data2[(y + 2 * dy) * ncols + x + 2*dx] = El.boxOnGoal;
|
||||
data = data2.assumeUnique; // Not enforced.
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool isSolved(in CTable data)
|
||||
const pure nothrow @safe @nogc {
|
||||
foreach (immutable i, immutable d; data)
|
||||
if ((sData[i] == El.goal) != (d == El.boxOnGoal))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
string solve() pure nothrow /*@safe*/ {
|
||||
bool[immutable CTable] visitedSet = [dData: true];
|
||||
|
||||
alias Four = Tuple!(CTable, string, int, int);
|
||||
GrowableCircularQueue!Four open;
|
||||
open.push(Four(dData, "", playerx, playery));
|
||||
|
||||
static immutable dirs = [tuple( 0, -1, 'u', 'U'),
|
||||
tuple( 1, 0, 'r', 'R'),
|
||||
tuple( 0, 1, 'd', 'D'),
|
||||
tuple(-1, 0, 'l', 'L')];
|
||||
|
||||
while (!open.empty) {
|
||||
//immutable (cur, cSol, x, y) = open.pop;
|
||||
immutable item = open.pop;
|
||||
immutable cur = item[0];
|
||||
immutable cSol = item[1];
|
||||
immutable x = item[2];
|
||||
immutable y = item[3];
|
||||
|
||||
foreach (immutable di; dirs) {
|
||||
CTable temp = cur;
|
||||
//immutable (dx, dy) = di[0 .. 2];
|
||||
immutable dx = di[0];
|
||||
immutable dy = di[1];
|
||||
|
||||
if (temp[(y + dy) * ncols + x + dx] == El.boxOnGoal) {
|
||||
if (push(x, y, dx, dy, temp) && temp !in visitedSet) {
|
||||
if (isSolved(temp))
|
||||
return cSol ~ di[3];
|
||||
open.push(Four(temp, cSol ~ di[3], x + dx, y + dy));
|
||||
visitedSet[temp] = true;
|
||||
}
|
||||
} else if (move(x, y, dx, dy, temp) && temp !in visitedSet) {
|
||||
if (isSolved(temp))
|
||||
return cSol ~ di[2];
|
||||
open.push(Four(temp, cSol ~ di[2], x + dx, y + dy));
|
||||
visitedSet[temp] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "No solution";
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
import std.stdio, core.memory;
|
||||
GC.disable; // Uses about twice the memory.
|
||||
|
||||
immutable level =
|
||||
"#######
|
||||
# #
|
||||
# #
|
||||
#. # #
|
||||
#. $$ #
|
||||
#.$$ #
|
||||
#.# @#
|
||||
#######";
|
||||
|
||||
immutable b = immutable(Board)(level.splitLines);
|
||||
writeln(level, "\n\n", b.solve);
|
||||
}
|
||||
414
Task/Sokoban/D/sokoban-2.d
Normal file
414
Task/Sokoban/D/sokoban-2.d
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
import core.stdc.stdio: printf, puts, fflush, stdout, putchar;
|
||||
import core.stdc.stdlib: malloc, calloc, realloc, free, alloca, exit;
|
||||
|
||||
enum Cell : ubyte { space, wall, player, box }
|
||||
alias CellIndex = ushort;
|
||||
alias Thash = uint;
|
||||
|
||||
|
||||
/// Board configuration is represented by an array of cell
|
||||
/// indices of player and boxes.
|
||||
struct State { // Variable length struct.
|
||||
Thash h;
|
||||
State* prev, next, qNext;
|
||||
CellIndex[0] c_;
|
||||
|
||||
CellIndex get(in size_t i) inout pure nothrow @nogc {
|
||||
return c_.ptr[i];
|
||||
}
|
||||
|
||||
void set(in size_t i, in CellIndex v) pure nothrow @nogc {
|
||||
c_.ptr[i] = v;
|
||||
}
|
||||
|
||||
CellIndex[] slice(in size_t i, in size_t j) pure nothrow @nogc return {
|
||||
return c_.ptr[i .. j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__gshared Cell[] board;
|
||||
__gshared bool[] goals, live;
|
||||
__gshared size_t w, h, nBoxes, stateSize, blockSize = 32;
|
||||
__gshared State* blockRoot, blockHead, nextLevel, done;
|
||||
__gshared State*[] buckets;
|
||||
__gshared Thash hashSize, fillLimit, filled;
|
||||
|
||||
|
||||
State* newState(State* parent) nothrow @nogc {
|
||||
static State* nextOf(State *s) nothrow @nogc {
|
||||
return cast(State*)(cast(ubyte*)s + stateSize);
|
||||
}
|
||||
|
||||
State* ptr;
|
||||
if (!blockHead) {
|
||||
blockSize *= 2;
|
||||
auto p = cast(State*)malloc(blockSize * stateSize);
|
||||
if (p == null)
|
||||
exit(1);
|
||||
|
||||
p.next = blockRoot;
|
||||
blockRoot = p;
|
||||
ptr = cast(State*)(cast(ubyte*)p + stateSize * blockSize);
|
||||
p = blockHead = nextOf(p);
|
||||
for (auto q = nextOf(p); q < ptr; p = q, q = nextOf(q))
|
||||
p.next = q;
|
||||
p.next = null;
|
||||
}
|
||||
|
||||
ptr = blockHead;
|
||||
blockHead = blockHead.next;
|
||||
ptr.prev = parent;
|
||||
ptr.h = 0;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void unNewState(State* p) nothrow @nogc {
|
||||
p.next = blockHead;
|
||||
blockHead = p;
|
||||
}
|
||||
|
||||
|
||||
/// Mark up positions where a box definitely should not be.
|
||||
void markLive(in size_t c) nothrow @nogc {
|
||||
immutable y = c / w;
|
||||
immutable x = c % w;
|
||||
if (live[c])
|
||||
return;
|
||||
|
||||
live[c] = true;
|
||||
if (y > 1 && board[c - w] != Cell.wall &&
|
||||
board[c - w * 2] != Cell.wall)
|
||||
markLive(c - w);
|
||||
if (y < h - 2 && board[c + w] != Cell.wall &&
|
||||
board[c + w * 2] != Cell.wall)
|
||||
markLive(c + w);
|
||||
if (x > 1 && board[c - 1] != Cell.wall &&
|
||||
board[c - 2] != Cell.wall)
|
||||
markLive(c - 1);
|
||||
if (x < w - 2 && board[c + 1] != Cell.wall &&
|
||||
board[c + 2] != Cell.wall)
|
||||
markLive(c + 1);
|
||||
}
|
||||
|
||||
|
||||
State* parseBoard(in size_t y, in size_t x, in char* s) nothrow @nogc {
|
||||
static T[] myCalloc(T)(in size_t n) nothrow @nogc {
|
||||
auto ptr = cast(T*)calloc(n, T.sizeof);
|
||||
if (ptr == null)
|
||||
exit(1);
|
||||
return ptr[0 .. n];
|
||||
}
|
||||
|
||||
w = x, h = y;
|
||||
board = myCalloc!Cell(w * h);
|
||||
goals = myCalloc!bool(w * h);
|
||||
live = myCalloc!bool(w * h);
|
||||
|
||||
nBoxes = 0;
|
||||
for (int i = 0; s[i]; i++) {
|
||||
switch(s[i]) {
|
||||
case '#':
|
||||
board[i] = Cell.wall;
|
||||
continue;
|
||||
case '.', '+':
|
||||
goals[i] = true;
|
||||
goto case;
|
||||
case '@':
|
||||
continue;
|
||||
case '*':
|
||||
goals[i] = true;
|
||||
goto case;
|
||||
case '$':
|
||||
nBoxes++;
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
enum int intSize = int.sizeof;
|
||||
stateSize = (State.sizeof +
|
||||
(1 + nBoxes) * CellIndex.sizeof +
|
||||
intSize - 1)
|
||||
/ intSize * intSize;
|
||||
|
||||
auto state = null.newState;
|
||||
|
||||
for (CellIndex i = 0, j = 0; i < w * h; i++) {
|
||||
if (goals[i])
|
||||
i.markLive;
|
||||
if (s[i] == '$' || s[i] == '*')
|
||||
state.set(++j, i);
|
||||
else if (s[i] == '@' || s[i] == '+')
|
||||
state.set(0, i);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
/// K&R hash function.
|
||||
void hash(State* s, in size_t nBoxes) pure nothrow @nogc {
|
||||
if (!s.h) {
|
||||
Thash ha = 0;
|
||||
foreach (immutable i; 0 .. nBoxes + 1)
|
||||
ha = s.get(i) + 31 * ha;
|
||||
s.h = ha;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void extendTable() nothrow @nogc {
|
||||
int oldSize = hashSize;
|
||||
|
||||
if (!oldSize) {
|
||||
hashSize = 1024;
|
||||
filled = 0;
|
||||
fillLimit = hashSize * 3 / 4; // 0.75 load factor.
|
||||
} else {
|
||||
hashSize *= 2;
|
||||
fillLimit *= 2;
|
||||
}
|
||||
|
||||
auto ptr = cast(State**)realloc(buckets.ptr,
|
||||
(State*).sizeof * hashSize);
|
||||
if (ptr == null)
|
||||
exit(6);
|
||||
buckets = ptr[0 .. hashSize];
|
||||
buckets[oldSize .. hashSize] = null;
|
||||
|
||||
immutable Thash bits = hashSize - 1;
|
||||
foreach (immutable i; 0 .. oldSize) {
|
||||
auto head = buckets[i];
|
||||
buckets[i] = null;
|
||||
while (head) {
|
||||
auto next = head.next;
|
||||
immutable j = head.h & bits;
|
||||
head.next = buckets[j];
|
||||
buckets[j] = head;
|
||||
head = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
State* lookup(State *s) nothrow @nogc {
|
||||
s.hash(nBoxes);
|
||||
auto f = buckets[s.h & (hashSize - 1)];
|
||||
for (; f; f = f.next) {
|
||||
if (s.slice(0, nBoxes + 1) == f.slice(0, nBoxes + 1))
|
||||
break;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
bool addToTable(State* s) nothrow @nogc {
|
||||
if (s.lookup) {
|
||||
s.unNewState;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filled++ >= fillLimit)
|
||||
extendTable;
|
||||
|
||||
immutable Thash i = s.h & (hashSize - 1);
|
||||
|
||||
s.next = buckets[i];
|
||||
buckets[i] = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool success(in State* s) nothrow @nogc {
|
||||
foreach (immutable i; 1 .. nBoxes + 1)
|
||||
if (!goals[s.get(i)])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
State* moveMe(State* s, in int dy, in int dx) nothrow @nogc {
|
||||
immutable int y = s.get(0) / w;
|
||||
immutable int x = s.get(0) % w;
|
||||
immutable int y1 = y + dy;
|
||||
immutable int x1 = x + dx;
|
||||
immutable int c1 = y1 * w + x1;
|
||||
|
||||
if (y1 < 0 || y1 > h || x1 < 0 || x1 > w || board[c1] == Cell.wall)
|
||||
return null;
|
||||
|
||||
int atBox = 0;
|
||||
foreach (immutable i; 1 .. nBoxes + 1)
|
||||
if (s.get(i) == c1) {
|
||||
atBox = i;
|
||||
break;
|
||||
}
|
||||
|
||||
int c2;
|
||||
if (atBox) {
|
||||
c2 = c1 + dy * w + dx;
|
||||
if (board[c2] == Cell.wall || !live[c2])
|
||||
return null;
|
||||
foreach (immutable i; 1 .. nBoxes + 1)
|
||||
if (s.get(i) == c2)
|
||||
return null;
|
||||
}
|
||||
|
||||
auto n = s.newState;
|
||||
n.slice(1, nBoxes + 1)[] = s.slice(1, nBoxes + 1);
|
||||
|
||||
n.set(0, cast(CellIndex)c1);
|
||||
|
||||
if (atBox)
|
||||
n.set(atBox, cast(CellIndex)c2);
|
||||
|
||||
// Bubble sort.
|
||||
for (size_t i = nBoxes; --i; ) {
|
||||
CellIndex t = 0;
|
||||
foreach (immutable j; 1 .. i) {
|
||||
if (n.get(j) > n.get(j + 1)) {
|
||||
t = n.get(j);
|
||||
n.set(j, n.get(j + 1));
|
||||
n.set(j + 1, t);
|
||||
}
|
||||
}
|
||||
if (!t)
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
bool queueMove(State *s) nothrow @nogc {
|
||||
if (!s || !s.addToTable)
|
||||
return false;
|
||||
|
||||
if (s.success) {
|
||||
"\nSuccess!".puts;
|
||||
done = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
s.qNext = nextLevel;
|
||||
nextLevel = s;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool doMove(State* s) nothrow @nogc {
|
||||
return s.moveMe( 1, 0).queueMove ||
|
||||
s.moveMe(-1, 0).queueMove ||
|
||||
s.moveMe( 0, 1).queueMove ||
|
||||
s.moveMe( 0, -1).queueMove;
|
||||
}
|
||||
|
||||
|
||||
void showBoard(in State* s) nothrow @nogc {
|
||||
static immutable glyphs1 = " #@$", glyphs2 = ".#@$";
|
||||
|
||||
auto ptr = cast(ubyte*)alloca(w * h * ubyte.sizeof);
|
||||
if (ptr == null)
|
||||
exit(5);
|
||||
auto b = ptr[0 .. w * h];
|
||||
b[] = cast(typeof(b))board[];
|
||||
|
||||
b[s.get(0)] = Cell.player;
|
||||
foreach (immutable i; 1 .. nBoxes + 1)
|
||||
b[s.get(i)] = Cell.box;
|
||||
|
||||
foreach (immutable i, immutable bi; b) {
|
||||
putchar((goals[i] ? glyphs2 : glyphs1)[bi]);
|
||||
if (!((1 + i) % w))
|
||||
'\n'.putchar;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void showMoves(in State* s) nothrow @nogc {
|
||||
if (s.prev)
|
||||
s.prev.showMoves;
|
||||
"\n".printf;
|
||||
s.showBoard;
|
||||
}
|
||||
|
||||
int main() nothrow @nogc {
|
||||
// Workaround for @nogc.
|
||||
alias ctEval(alias expr) = expr;
|
||||
|
||||
enum uint problem = 0;
|
||||
|
||||
static if (problem == 0) {
|
||||
auto s = parseBoard(8, 7, ctEval!(
|
||||
"#######"~
|
||||
"# #"~
|
||||
"# #"~
|
||||
"#. # #"~
|
||||
"#. $$ #"~
|
||||
"#.$$ #"~
|
||||
"#.# @#"~
|
||||
"#######"));
|
||||
|
||||
} else static if (problem == 1) {
|
||||
auto s = parseBoard(5, 13, ctEval!(
|
||||
"#############"~
|
||||
"# # #"~
|
||||
"# $$$$$$$ @#"~
|
||||
"#....... #"
|
||||
"#############"));
|
||||
|
||||
} else static if (problem == 2) {
|
||||
auto s = parseBoard(11, 19, ctEval!(
|
||||
" ##### "~
|
||||
" # # "~
|
||||
" # # "~
|
||||
" ### #$## "~
|
||||
" # # "~
|
||||
"### #$## # ######"~
|
||||
"# # ## ##### .#"~
|
||||
"# $ $ ..#"~
|
||||
"##### ### #@## .#"~
|
||||
" # #########"~
|
||||
" ####### "));
|
||||
} else {
|
||||
asset(0, "Not present problem.");
|
||||
}
|
||||
|
||||
s.showBoard;
|
||||
extendTable;
|
||||
s.queueMove;
|
||||
for (int i = 0; !done; i++) {
|
||||
printf("depth %d\r", i);
|
||||
stdout.fflush;
|
||||
|
||||
auto head = nextLevel;
|
||||
for (nextLevel = null; head && !done; head = head.qNext)
|
||||
head.doMove;
|
||||
|
||||
if (!nextLevel) {
|
||||
"No solution?".puts;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
done.showMoves;
|
||||
|
||||
version (none) { // Free all allocated memory.
|
||||
buckets.ptr.free;
|
||||
board.ptr.free;
|
||||
goals.ptr.free;
|
||||
live.ptr.free;
|
||||
|
||||
while (blockRoot) {
|
||||
auto tmp = blockRoot.next;
|
||||
blockRoot.free;
|
||||
blockRoot = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue