15 puzzle solver: Difference between revisions

Content added Content deleted
No edit summary
Line 2,322: Line 2,322:
run() = (N0[1] = 8; _n[1] = 1; N2[1] = 0xfe169b4c0a73d852; solve(0))
run() = (N0[1] = 8; _n[1] = 1; N2[1] = 0xfe169b4c0a73d852; solve(0))
run()
run()
</lang> {{output}} <pre>
</lang>
{{output}} <pre>
next iteration, _n[1] will be 2...
next iteration, _n[1] will be 2...
next iteration, _n[1] will be 3...
next iteration, _n[1] will be 3...
Line 2,332: Line 2,333:
Solution found in 52 moves:
Solution found in 52 moves:
rrrulddluuuldrurdddrullulurrrddldluurddlulurruldrdrd
rrrulddluuuldrurdddrullulurrrddldluurddlulurruldrdrd
</pre>

=={{header|Lua}}==
<lang Lua>
#!/usr/bin/lua
--[[
Solve 3X3 sliding tile puzzle using Astar on Lua. Requires 3mb and
millions of recursions.
by RMM 2020-may-1
]]--

local SOLUTION_LIMIT, MAX_F_VALUE = 100,100
local NR, NC, RCSIZE = 4,4,4*4
local Up, Down, Right, Left = 'u','d','r','l'
local G_cols = {} -- goal columns
local G_rows = {} -- goal rows
local C_cols = {} -- current cols
local C_rows = {} -- current rows
local Goal = {}
local Tiles = {} -- the puzzle
local Solution = {} -- final path is instance of desc
local desc = {} -- descending path
desc[0] = 0 -- override Lua default "1" index

-- @brief create C compatible array for Lua
local function Amake( list )
array = {}
for i=0, #list do
array[i] = list[i+1] -- simulate "C" array in Lua
end
return array
end

G_cols= Amake({0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, } )
G_rows= Amake({0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, } )
C_cols= Amake({0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, } )
C_rows= Amake({0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, } )
Tiles = Amake({ 15,14,1,6, 9,11,4,12, 0,10,7,3, 13,8,5,2,} )
Goal = Amake({1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,0,} )

local m1 = {recursions=0, found=0, threshold=0, times=0, steps=0,}
-- ---------------------------------------------------------------
-- return 1D array index given 2D row,column
local function rcidx( row, col )
return (row * NR + col)
end

-- @brief recursive search
-- @return f_score
local function search( depth, x_row, x_col, h_score)
local move, go_back_move, last_move_by_current
local f_score, ix, min, temp, hscore2, idx1
local N_minus_one = NR - 1;
local rc1 = {row=0,col=0}
local rc2 = {row=0,col=0}
local gtmp = {row=0,col=0}

f_score = depth + h_score;
if f_score > m1.threshold then return f_score end
if h_score == 0 then do
m1.found = 1
Solution = table.concat(desc)
return f_score end end
m1.recursions = m1.recursions+1
m1.times = m1.times + 1
if m1.times > 200000 then do
print("Recursions ",m1.recursions)
m1.times = 0
end end
min = 999999
last_move_by_current = desc[depth];
rc1.row = x_row;
rc1.col = x_col;
for ix = 0,3 do
if ix==0 then do
move = Up;
go_back_move = Down;
rc2.row = x_row - 1;
rc2.col = x_col;
end
elseif ix==1 then do
move = Down;
go_back_move = Up;
rc2.row = x_row + 1;
rc2.col = x_col;
end
elseif ix==2 then do
move = Left;
go_back_move = Right;
rc2.row = x_row;
rc2.col = x_col - 1;
end
elseif ix==3 then do
move = Right;
go_back_move = Left;
rc2.row = x_row;
rc2.col = x_col + 1;
end end
if move==Up and x_row==0 then goto next end
if move==Down and x_row==N_minus_one then goto next end
if move==Left and x_col==0 then goto next end
if move==Right and x_col==N_minus_one then goto next end
if last_move_by_current==go_back_move then goto next end
hscore2 = h_score
idx1 = Tiles[rcidx(rc2.row,rc2.col)]
gtmp.row = G_rows[idx1]
gtmp.col = G_cols[idx1]
local h_adj=0
if go_back_move==Up then do
if gtmp.row < C_rows[idx1] then
h_adj = -1 else h_adj = 1 end end
end
if go_back_move==Down then do
if gtmp.row > C_rows[idx1] then
h_adj = -1 else h_adj = 1 end end
end
if go_back_move==Left then do
if gtmp.col < C_cols[idx1] then
h_adj = -1 else h_adj = 1 end end
end
if go_back_move==Right then do
if gtmp.col > C_cols[idx1] then
h_adj = -1 else h_adj = 1 end end
end
hscore2 = hscore2 + h_adj
C_rows[0] = rc2.row;
C_cols[0] = rc2.col;
C_rows[idx1] = rc1.row;
C_cols[idx1] = rc1.col;
Tiles[rcidx(rc1.row,rc1.col)] = idx1;
Tiles[rcidx(rc2.row,rc2.col)] = 0;
desc[depth+1] = move
desc[depth+2] = '\0'

temp = search(depth+1, rc2.row, rc2.col, hscore2); -- descend
-- regress
Tiles[rcidx(rc1.row,rc1.col)] = 0
Tiles[rcidx(rc2.row,rc2.col)] = idx1
desc[depth+1] = '\0'
C_rows[0] = rc1.row;
C_cols[0] = rc1.col;
C_rows[idx1] = rc2.row;
C_cols[idx1] = rc2.col;
if m1.found == 1 then return temp end
if temp < min then min = temp end
::next:: -- Lua does not have "continue;" so uses goto
end -- end for
m1.found = 0;
-- return the minimum f_score greater than m1.threshold
return min;
end

-- @brief Run solver using A-star algorithm
-- @param Tiles .. 3X3 sliding tile puzzle
local function solve(Tiles)
local temp, i,j
local x_row, x_col, h_score = 0,0,0

m1.found = 0;
for i=0,(NR-1) do
for j=0, (NC-1) do
G_rows[ Goal[rcidx(i,j)] ] = i;
G_cols[ Goal[rcidx(i,j)] ] = j;
C_rows[ Tiles[rcidx(i,j)] ] = i;
C_cols[ Tiles[rcidx(i,j)] ] = j;
end
end
for i=0,(NR-1) do
for j=0, (NC-1) do
if Tiles[rcidx(i,j)] == 0 then do
x_row = i;
x_col = j;
break;
end
end
end
end

desc[0] = '$'
desc[1] = '\0'

h_score = 0; -- Manhattan/Taxicab heuristic
for i = 1,(RCSIZE-1) do
h_score = h_score + (math.abs(C_rows[i] - G_rows[i]) +
math.abs(C_cols[i] - G_cols[i]))
end
m1.threshold = h_score
print("solve -> search")
while true do
temp = search( 0, x_row, x_col, h_score);
if m1.found == 1 then do
print("Gound solution of length",#Solution-1)
print(Solution)
break;
end end
if temp > MAX_F_VALUE then do
print("Maximum f value reached! terminating! \n");
break; end
end
m1.threshold = temp;
end -- while
return 0
end

-- show sliding tile puzzle rows and columns
local function print_tiles( pt)
local i,j,num
for i=0,(NR-1) do
for j=0, (NC-1) do
num = pt[rcidx(i,j)]
io.write(string.format("%02d ", num))
end
print("")
end
print("")
end

-- main(void) {
print("Solve sliding 15 tile puzzle");
m1.recursions = 0
m1.times=0
print_tiles(Tiles);
print_tiles(Goal)
solve(Tiles);
</lang>
{{output}} <pre>
FOUND SOLUTION of length 52 rrrulddluuuldrurdddrullulurrrddldluurddlulurruldrdrd
</pre>
</pre>