Data update

This commit is contained in:
Ingy döt Net 2026-04-30 12:34:36 -04:00
parent 4bb20c9b71
commit cbaf4c4b64
12390 changed files with 318560 additions and 27248 deletions

View file

@ -0,0 +1,233 @@
Const NULL As Any Ptr = 0
' HashTable with open addressing
Type HashTable
Dim As Integer size
Dim As String entries(Any)
End Type
Sub HashInit(Byref ht As HashTable, sz As Integer)
ht.size = sz
Redim ht.entries(0 To sz-1)
For i As Integer = 0 To sz-1
ht.entries(i) = "" ' empty slot marker
Next
End Sub
Function HashString(s As String, tableSize As Integer) As Integer
Dim As Uinteger h = 5381
For i As Integer = 0 To Len(s)-1
h = ((h Shl 5) + h) + Asc(Mid(s,i+1,1)) ' h*33 + c
Next
Return h Mod tableSize
End Function
Sub HashAdd(Byref ht As HashTable, s As String)
Dim As Integer idx = HashString(s, ht.size)
While ht.entries(idx) <> "" And ht.entries(idx) <> s
idx = (idx + 1) Mod ht.size
Wend
ht.entries(idx) = s
End Sub
Function HashContains(Byref ht As HashTable, s As String) As Boolean
Dim As Integer idx = HashString(s, ht.size)
While ht.entries(idx) <> ""
If ht.entries(idx) = s Then Return True
idx = (idx + 1) Mod ht.size
Wend
Return False
End Function
' Sokoban solver
Type State
board As String
moves As String
posic As Integer
End Type
Type DirType
moveStr As String
pushStr As String
dPos As Integer
End Type
Function getChar(s As String, lug As Integer) As String
If lug < 0 Or lug >= Len(s) Then Return "#"
Return Mid(s, lug + 1, 1)
End Function
Function setChar(s As String, lug As Integer, c As String) As String
If lug < 0 Or lug >= Len(s) Then Return s
Return Left(s, lug) & c & Mid(s, lug + 2)
End Function
Function isWall(c As String) As Boolean
Return c = "#" Or c = Chr(10) Or c = ""
End Function
' --- Corner deadlock pruning (discard states where a box is stuck in a non-goal corner) ---
Function isDeadlock(board As String, ancho As Integer) As Boolean
For i As Integer = 0 To Len(board)-1
Dim c As String = Mid(board, i+1, 1)
If c = "$" Then
' Read neighbor cells around the box
Dim izda As String = getChar(board, i-1)
Dim dcha As String = getChar(board, i+1)
Dim up As String = getChar(board, i-(ancho+1))
Dim down As String = getChar(board, i+(ancho+1))
If (isWall(izda) Or isWall(dcha)) And (isWall(up) Or isWall(down)) Then
If getChar(board, i) <> "." Then Return True
End If
End If
Next
Return False
End Function
Function Move(s As State Ptr, dPos As Integer) As String
Dim As Integer newPos = s->posic + dPos
If newPos < 0 Or newPos >= Len(s->board) Then Return ""
Dim As String targetChar = getChar(s->board, newPos)
If isWall(targetChar) Then Return ""
If targetChar <> " " And targetChar <> "." Then Return ""
Dim As String tmp = s->board
Dim As Integer lug = s->posic
Dim As String currentChar = getChar(tmp, lug)
tmp = Iif(currentChar = "@", setChar(tmp, lug, " "), setChar(tmp, lug, "."))
tmp = setChar(tmp, newPos, Iif(targetChar = " ", "@", "+"))
Return tmp
End Function
Function Push(s As State Ptr, dPos As Integer) As String
Dim As Integer newPos = s->posic + dPos
Dim As Integer boxPos = newPos + dPos
If newPos < 0 Or boxPos < 0 Or boxPos >= Len(s->board) Then Return ""
Dim As String boxChar = getChar(s->board, newPos)
Dim As String targetChar = getChar(s->board, boxPos)
If boxChar <> "$" And boxChar <> "*" Then Return ""
If isWall(targetChar) Then Return ""
If targetChar <> " " And targetChar <> "." Then Return ""
Dim As String tmp = s->board
Dim As Integer lug = s->posic
Dim As String currentChar = getChar(tmp, lug)
tmp = Iif(currentChar = "@", setChar(tmp, lug, " "), setChar(tmp, lug, "."))
tmp = setChar(tmp, newPos, Iif(boxChar = "$", "@", "+"))
tmp = setChar(tmp, boxPos, Iif(targetChar = " ", "$", "*"))
Return tmp
End Function
Function isComplete(board As String) As Boolean
Return Instr(board, ".") = 0 And Instr(board, "$") = 0
End Function
Function Solve(board As String) As String
Dim As Integer boardLen = Len(board)
Dim As Integer ancho = Instr(board, Chr(10)) - 1
If ancho <= 0 Then Return "Invalid board"
Dim As DirType dirs(3)
dirs(0).moveStr = "u": dirs(0).pushStr = "U": dirs(0).dPos = -ancho-1
dirs(1).moveStr = "r": dirs(1).pushStr = "R": dirs(1).dPos = 1
dirs(2).moveStr = "d": dirs(2).pushStr = "D": dirs(2).dPos = ancho+1
dirs(3).moveStr = "l": dirs(3).pushStr = "L": dirs(3).dPos = -1
Dim As HashTable visited
HashInit(visited, 200000) ' initial size (tune for fewer collisions)
HashAdd(visited, board)
Dim As Integer playerPos = Instr(board, "@") - 1
If playerPos < 0 Then playerPos = Instr(board, "+") - 1
If playerPos < 0 Then Return "No player"
Dim As State Ptr openStates = Callocate(100000, Sizeof(State))
Dim As Integer head = 0, tail = 0, capacity = 100000
openStates[tail].board = board
openStates[tail].moves = ""
openStates[tail].posic = playerPos
tail += 1
While head < tail
If tail > 1000000 Then
Deallocate(openStates)
Return "Too complex"
End If
Dim As State current = openStates[head]
head += 1
For i As Integer = 0 To 3
Dim As DirType currentDir = dirs(i)
Dim As Integer newPos = current.posic + currentDir.dPos
If newPos < 0 Or newPos >= boardLen Then Continue For
Dim As String targetChar = getChar(current.board, newPos)
If isWall(targetChar) Then Continue For
Dim As String newBoard = ""
Dim As String newSol = current.moves
If targetChar = "$" Or targetChar = "*" Then
newBoard = Push(@current, currentDir.dPos)
If Len(newBoard) > 0 Then newSol += currentDir.pushStr
Elseif targetChar = " " Or targetChar = "." Then
newBoard = Move(@current, currentDir.dPos)
If Len(newBoard) > 0 Then newSol += currentDir.moveStr
End If
If Len(newBoard) > 0 Andalso newBoard <> current.board Then
If isDeadlock(newBoard, ancho) Then Continue For
If isComplete(newBoard) Then
Deallocate(openStates)
Return newSol
End If
If Not HashContains(visited, newBoard) Then
HashAdd(visited, newBoard)
If tail >= capacity Then
capacity += 50000
Dim As State Ptr tmpPtr = Reallocate(openStates, capacity * Sizeof(State))
If tmpPtr = NULL Then
Deallocate(openStates)
Return "Out of memory"
End If
openStates = tmpPtr
End If
openStates[tail].board = newBoard
openStates[tail].moves = newSol
Dim As Integer np = Instr(newBoard, "@") - 1
If np < 0 Then np = Instr(newBoard, "+") - 1
openStates[tail].posic = np
tail += 1
End If
End If
Next
Wend
Deallocate(openStates)
Return "No solution"
End Function
' Main program
Dim level As String = _
"#######" & Chr(10) & _
"# #" & Chr(10) & _
"# #" & Chr(10) & _
"#. # #" & Chr(10) & _
"#. $$ #" & Chr(10) & _
"#.$$ #" & Chr(10) & _
"#.# @#" & Chr(10) & _
"#######"
Print "level:" & Chr(10) & level
Print "Solution:" & Chr(10) & Solve(level)
Sleep

View file

@ -0,0 +1,108 @@
require "map"
require "list"
class board
function __construct(public cur, public sol, public x, public y) end
end
class sokoban
function __construct(brd)
self.dest_board = ""
self.curr_board = ""
self.ncols = #brd[1]
self.player_x = 0
self.player_y = 0
for r = 1, #brd do
for c = 1, self.ncols do
local ch = brd[r][c]
self.dest_board ..= (ch != "$" and ch != "@") ? ch : " "
self.curr_board ..= (ch != ".") ? ch : " "
if ch == "@" then
self.player_x = c - 1
self.player_y = r - 1
end
end
end
end
function move(x, y, dx, dy, trial_board)
local new_player_pos = (y + dy) * self.ncols + x + dx + 1
if trial_board[new_player_pos] != " " then return "" end
local trial = trial_board:split("")
trial[y * self.ncols + x + 1] = " "
trial[new_player_pos] = "@"
return trial:concat("")
end
function push(x, y, dx, dy, trial_board)
local new_box_pos = (y + 2 * dy) * self.ncols + x + 2 * dx + 1
if trial_board[new_box_pos] != " " then return "" end
local trial = trial_board:split("")
trial[y * self.ncols + x + 1] = " "
trial[(y + dy) * self.ncols + x + dx + 1] = "@"
trial[new_box_pos] = "$"
return trial:concat("")
end
function is_solved(trial_board)
for i = 1, #trial_board do
if (self.dest_board[i] == ".") != (trial_board[i] == "$") then return false end
end
return true
end
function solve()
local dir_labels = { {"u", "U"}, {"r", "R"}, {"d", "D"}, {"l", "L"} }
local dirs = { {0, -1}, {1, 0}, {0, 1}, {-1, 0} }
local history = new set()
history:add(self.curr_board)
local open = new dlist()
open:push(new board(self.curr_board, "", self.player_x, self.player_y))
while !open:empty() do
local b = open:remove(1)
for i = 1, #dirs do
local trial = b.cur
local dx = dirs[i][1]
local dy = dirs[i][2]
-- Are we standing next to a box ?
if trial[(b.y + dy) * self.ncols + b.x + dx + 1] == "$" then
-- Can we push it ?
trial = self:push(b.x, b.y, dx, dy, trial)
if trial != "" then
-- Or did we already try this one ?
if !history:contains(trial) then
local newsol = b.sol .. dir_labels[i][2]
if self:is_solved(trial) then return newsol end
open:push(new board(trial, newsol, b.x + dx, b.y + dy))
history:add(trial)
end
end
else -- otherwise try changing position
trial = self:move(b.x, b.y, dx, dy, trial)
if trial != "" and !history:contains(trial) then
local newsol = b.sol .. dir_labels[i][1]
open:push(new board(trial, newsol, b.x + dx, b.y + dy))
history:add(trial)
end
end
end
end
return "No solution"
end
end
local level = {
"#######",
"# #",
"# #",
"#. # #",
"#. $$ #",
"#.$$ #",
"#.# @#",
"#######"
}
print(level:concat("\n"))
print()
print(new sokoban(level):solve())

View file

@ -0,0 +1,175 @@
struct Board {
cur string
sol string
xir int
yir int
}
struct Direction {
dxir int
dyir int
}
struct Queue {
mut:
data []Board
}
fn (mut que Queue) push(brd Board) {
que.data << brd
}
fn (mut que Queue) pop() ?Board {
if que.data.len == 0 { return none }
item := que.data[0]
que.data = que.data[1..]
return item
}
fn (que Queue) is_empty() bool {
return que.data.len == 0
}
struct Sokoban {
n_cols int
dest_board string
curr_board string
player_x int
player_y int
}
fn new_sokoban(board []string) Sokoban {
n_cols := board[0].len
mut dest_buf := []u8{}
mut curr_buf := []u8{}
mut player_x := 0
mut player_y := 0
for ral in 0 .. board.len {
for cal in 0 .. n_cols {
ch := board[ral][cal]
dest_buf << if ch != `$` && ch != `@` { ch } else { ` ` }
curr_buf << if ch != `.` { ch } else { ` ` }
if ch == `@` {
player_x = cal
player_y = ral
}
}
}
return Sokoban{
n_cols: n_cols
dest_board: dest_buf.bytestr()
curr_board: curr_buf.bytestr()
player_x: player_x
player_y: player_y
}
}
fn (skn Sokoban) move(xir int, yir int, dxir int, dyir int, trial_board string) string {
new_pos := (yir + dyir) * skn.n_cols + xir + dxir
if trial_board[new_pos] != ` ` { return "" }
mut trial := trial_board.bytes()
trial[yir * skn.n_cols + xir] = ` `
trial[new_pos] = `@`
return trial.bytestr()
}
fn (skn Sokoban) push(xir int, yir int, dxir int, dyir int, trial_board string) string {
new_box_pos := (yir + 2 * dyir) * skn.n_cols + xir + 2 * dxir
if trial_board[new_box_pos] != ` ` { return "" }
mut trial := trial_board.bytes()
trial[yir * skn.n_cols + xir] = ` `
trial[(yir + dyir) * skn.n_cols + xir + dxir] = `@`
trial[new_box_pos] = `$`
return trial.bytestr()
}
fn (skn Sokoban) is_solved(trial_board string) bool {
for ial in 0 .. trial_board.len {
if (skn.dest_board[ial] == `.`) != (trial_board[ial] == `$`) { return false }
}
return true
}
fn (skn Sokoban) solve() string {
dir_labels := [`u`, `r`, `d`, `l`]
dir_labels_caps := [`U`, `R`, `D`, `L`]
dirs := [
Direction{dxir: 0, dyir: -1},
Direction{dxir: 1, dyir: 0},
Direction{dxir: 0, dyir: 1},
Direction{dxir: -1, dyir: 0},
]
mut trial := ""
mut open := Queue{}
mut history := map[string]bool{}
history[skn.curr_board] = true
open.push(Board{
cur: skn.curr_board
sol: ""
xir: skn.player_x
yir: skn.player_y
})
for !open.is_empty() {
cur_board := open.pop() or { break }
cur := cur_board.cur
sol := cur_board.sol
xir := cur_board.xir
yir := cur_board.yir
for i in 0 .. dirs.len {
dxir := dirs[i].dxir
dyir := dirs[i].dyir
trial = cur
if trial[(yir + dyir) * skn.n_cols + xir + dxir] == `$` {
trial = skn.push(xir, yir, dxir, dyir, trial)
if trial != "" && !history[trial] {
new_sol := sol + dir_labels_caps[i].str()
if skn.is_solved(trial) { return new_sol }
open.push(Board{
cur: trial
sol: new_sol
xir: xir + dxir
yir: yir + dyir
})
history[trial] = true
}
}
else
{
trial = skn.move(xir, yir, dxir, dyir, trial)
if trial != "" && !history[trial] {
new_sol := sol + dir_labels[i].str()
open.push(Board{
cur: trial
sol: new_sol
xir: xir + dxir
yir: yir + dyir
})
history[trial] = true
}
}
}
}
return "No solution"
}
fn main() {
level := [
"#######",
"# #",
"# #",
"#. # #",
"#. $$ #",
"#.$$ #",
"#.# @#",
"#######",
]
for line in level {
println(line)
}
println("")
sokoban := new_sokoban(level)
println(sokoban.solve())
}