Sokoban: Difference between revisions
m
→{{header|Wren}}: Minor tidy
(Sokoban en Befunge) |
m (→{{header|Wren}}: Minor tidy) |
||
(5 intermediate revisions by 3 users not shown) | |||
Line 10:
* + is the player on a goal
* * is a box on a goal
<syntaxhighlight lang="text">#######
# #
# #
#. # #
#. $$ #
#.$$ #
#.# @#
#######</syntaxhighlight>
Sokoban solutions are usually stored in the LURD format, where lowercase l, u, r and d represent a move in that ('''l'''eft, '''u'''p, '''r'''ight, '''d'''own) direction and capital LURD represents a push.
Line 17 ⟶ 25:
For more information, see [http://www.sokobano.de/wiki/index.php?title=Main_Page the Sokoban wiki].
=={{header|11l}}==
{{trans|Python}}
<syntaxhighlight lang="11l">[String] data
V nrows = 0
V px = 0
V py = 0
V sdata = ‘’
V ddata = ‘’
F init(board)
:data = board.split("\n")
:nrows = max(:data.map(r -> r.len))
V maps = [‘ ’ = ‘ ’, ‘.’ = ‘.’, ‘@’ = ‘ ’, ‘#’ = ‘#’, ‘$’ = ‘ ’]
V mapd = [‘ ’ = ‘ ’, ‘.’ = ‘ ’, ‘@’ = ‘@’, ‘#’ = ‘ ’, ‘$’ = ‘*’]
L(row) :data
V r = L.index
L(ch) row
V c = L.index
:sdata ‘’= maps[ch]
:ddata ‘’= mapd[ch]
I ch == ‘@’
:px = c
:py = r
F push(x, y, dx, dy, &data)
I :sdata[(y + 2 * dy) * :nrows + x + 2 * dx] == ‘#’
| data[(y + 2 * dy) * :nrows + x + 2 * dx] != ‘ ’
data = ‘’
R
data[y * :nrows + x] = ‘ ’
data[(y + dy) * :nrows + x + dx] = ‘@’
data[(y + 2 * dy) * :nrows + x + 2 * dx] = ‘*’
F is_solved(data)
L(i) 0 .< data.len
I (:sdata[i] == ‘.’) != (data[i] == ‘*’)
R 0B
R 1B
F solve()
V open = Deque([(:ddata, ‘’, :px, :py)])
V visited = Set([:ddata])
V dirs = ((0, -1, ‘u’, ‘U’), ( 1, 0, ‘r’, ‘R’),
(0, 1, ‘d’, ‘D’), (-1, 0, ‘l’, ‘L’))
L !open.empty
V (cur, csol, x, y) = open.pop_left()
L(di) dirs
V temp = copy(cur)
V (dx, dy) = (di[0], di[1])
I temp[(y + dy) * :nrows + x + dx] == ‘*’
push(x, y, dx, dy, &temp)
I temp != ‘’ & temp !C visited
I is_solved(temp)
R csol‘’di[3]
open.append((temp, csol‘’di[3], x + dx, y + dy))
visited.add(temp)
E
I :sdata[(y + dy) * :nrows + x + dx] == ‘#’ | temp[(y + dy) * :nrows + x + dx] != ‘ ’
L.continue
temp[y * :nrows + x] = ‘ ’
temp[(y + dy) * :nrows + x + dx] = ‘@’
I temp !C visited
I is_solved(temp)
R csol‘’di[2]
open.append((temp, csol‘’di[2], x + dx, y + dy))
visited.add(temp)
R ‘No solution’
V level =
|‘#######
# #
# #
#. # #
#. $$ #
#.$$ #
#.# @#
#######’
init(level)
print(level"\n\n"solve())</syntaxhighlight>
{{out}}
<pre>
#######
# #
# #
#. # #
#. $$ #
#.$$ #
#.# @#
#######
ulULLulDDurrrddlULrruLLrrUruLLLulD
</pre>
=={{header|Befunge}}==
El código no es mío, sólo lo reproduzco.
<
589*+0g"0"-25**689*+0g"0"-+50p v # Sokoban - (c) Matthew Westcott 2000 # 03
83*>10p99*2->:00p10gg"x"-#v_v p01g<> ## # # # # # # # # # # # # # # # # # # #
Line 46 ⟶ 159:
#0 x 0#
########
</syntaxhighlight>
=={{header|C}}==
Long, long, long C99 code (plus GNU C nested functions). Doesn't output the movement keys, instead it animates the sequence for you. Solution is move optimized. For an even longer solution, see [[Sokoban/C]].
<
#include <stdlib.h>
#include <string.h>
Line 452 ⟶ 564:
return 0;
}</
=={{header|C sharp|C#}}==
<
using System.Linq;
using System.Text;
Line 628 ⟶ 740:
}
}
}</
Output:
<pre>
Line 653 ⟶ 765:
This performs a breadth-first search by moves, so the results should be a move-optimal solution.
<
#include <string>
#include <vector>
Line 806 ⟶ 918:
cout << level << endl << endl << b.solve() << endl;
return 0;
}</
Output:
Line 826 ⟶ 938:
{{works with|GCC 4.6}}
Alternative version, about twice faster (about 2.1 seconds runtime), same output.
<
#include <string>
#include <vector>
Line 965 ⟶ 1,077:
cout << board.solve() << endl;
return 0;
}</
=={{header|D}}==
Line 971 ⟶ 1,083:
{{trans|C++}}
This version uses the queue defined in the Queue/Usage task.
<
import queue_usage2; // No queue in Phobos 2.064.
Line 1,115 ⟶ 1,227:
immutable b = immutable(Board)(level.splitLines);
writeln(level, "\n\n", b.solve);
}</
{{out}}
<pre>#######
Line 1,132 ⟶ 1,244:
{{trans|C}}
This code is not idiomatic D, it retains most of the style of the C version.
<
import core.stdc.stdlib: malloc, calloc, realloc, free, alloca, exit;
Line 1,545 ⟶ 1,657:
return 0;
}</
=={{header|Elixir}}==
{{works with|Elixir|1.3}}
{{trans|Ruby}}
<
defp setup(level) do
{leng, board} = normalize(level)
Line 1,730 ⟶ 1,842:
"""
IO.puts level
Sokoban.solve(level)</
{{out}}
Line 1,749 ⟶ 1,861:
{{trans|C++}}
Well, it started as a C++ translation, but turned out different. It's still the breadth-first set-based algorithm, but I dropped the sdata/ddata optimization and just maintained a single string as the board representation. Also dropped the code to handle non-rectangular boards, and probably some other stuff too.
<
import (
Line 1,865 ⟶ 1,977:
}
return string(buffer)
}</
{{out}}
<pre>
Line 1,882 ⟶ 1,994:
=={{header|Haskell}}==
<
import Data.Array
import Data.List (transpose)
Line 2,013 ⟶ 2,125:
mapM_ putStrLn exampleA
putStrLn ""
putStrLn $ concatMap show solution</
{{out}}
<pre>#######
Line 2,029 ⟶ 2,141:
Translation of [[Sokoban#C++|C++]] via [[Sokoban#D|D]]
{{works with|Java|7}}
<
public class Sokoban {
Line 2,166 ⟶ 2,278:
System.out.println(new Sokoban(level.split(",")).solve());
}
}</
<pre>ulULLulDDurrrddlULrruLLrrUruLLLulD</pre>
Line 2,172 ⟶ 2,284:
=={{header|Julia}}==
{{trans|Go}}
<
board::String
csol::String
Line 2,265 ⟶ 2,377:
#######""")
println("For sokoban level:\n$testlevel\n...solution is :\n$(solve(testlevel))")
</
For sokoban level:
#######
Line 2,281 ⟶ 2,393:
=={{header|Kotlin}}==
{{trans|Java}}
<
import java.util.LinkedList
Line 2,396 ⟶ 2,508:
println()
println(Sokoban(level).solve())
}</
{{out}}
Line 2,416 ⟶ 2,528:
We have chosen to use a double queue (deque) instead of a linked list.
<
type
Line 2,514 ⟶ 2,626:
echo Level.join("\n")
echo()
echo initSokoban(Level).solve()</
{{out}}
Line 2,531 ⟶ 2,643:
{{trans|Python}}
This uses a breadth-first move search, so will find a move-optimal solution.
<
type move_t = Move of dir | Push of dir
Line 2,624 ⟶ 2,736:
"#.# @#";
"#######"] in
solve level</
Output:
<pre>luULLulDDurrrddlULrruLLrrUruLLLulD</pre>
Line 2,644 ⟶ 2,756:
would still be a valid solution. I could fix it, but at the cost of speed and memory.
<
use strict;
use warnings qw(FATAL all);
Line 2,848 ⟶ 2,960:
}
__END__
</syntaxhighlight>
{{out}}
<pre>Solution found!
Line 2,871 ⟶ 2,983:
Push-optimised, prunes (breadth-first) search space to reachable pushable-to-live boxes.<br>
Fairly fast, but often produces same-push-tally but longer results than move-optimised.
<
integer w, h -- (set from parsing the input grid)
sequence moves -- "", as +/-w and +/-1 (udlr)
Line 3,041 ⟶ 3,153:
printf(1,"solution of %d pushes (%s)\n",{pop,elapsed(time()-t0)})
plays(level,pushset)
end if</
{{out}}
Note that a full solution in LURD format would show as 48 moves, as opposed to
Line 3,067 ⟶ 3,179:
Other tests:
<
#############
# # #
Line 3,073 ⟶ 3,185:
#....... #
#############
"""</
{{out}}
<pre>
Line 3,102 ⟶ 3,214:
</pre>
Test #3
<
####
##. ##
Line 3,111 ⟶ 3,223:
###### ##
####
"""</
{{out}}
<pre>
Line 3,134 ⟶ 3,246:
</pre>
Test #4
<
#############
#... # #
Line 3,140 ⟶ 3,252:
#... #
#############
"""</
{{out}}
<pre>
Line 3,158 ⟶ 3,270:
</pre>
Test #5
<
#####
# #
Line 3,170 ⟶ 3,282:
# #########
#######
"""</
{{out}}
<pre>
Line 3,203 ⟶ 3,315:
=={{header|PicoLisp}}==
This searches for a solution, without trying for the push-optimal one. The player moves between the pushes, however, are minimized.
<
# Display board
Line 3,284 ⟶ 3,396:
(pushes) )
(display) # Display solution
(pack (flip Res)) ) ) )</
Test:
<
(quote
"#######"
Line 3,297 ⟶ 3,409:
"#######" ) )
(prinl)
(go)</
Output:
<pre> 8 # # # # # # #
Line 3,324 ⟶ 3,436:
{{works with|Psyco}}
{{works with|Python 2.6}}
<
from collections import deque
import psyco
Line 3,419 ⟶ 3,531:
psyco.full()
init(level)
print level, "\n\n", solve()</
Output:
<pre>#######
Line 3,436 ⟶ 3,548:
This was originally inspired by PicoLisp's solution. Modified to use a priority queue as mentioned on the Sokoban wiki for the main breadth first search on pushes but just a plain queue for the move bfs. This uses personal libraries. Vector2 isn't strictly needed but the math/array library is not currently optimized for untyped Racket. push! is comparable to lisp's, awhen is anaphoric when, ret uses the bound value as the result of its expression, and tstruct is short for struct with the #:transparent option.
<syntaxhighlight lang="racket">
#lang racket
(require data/heap
Line 3,544 ⟶ 3,656:
(pushes s clear))
(bfs)])))
</syntaxhighlight>
{{out}}
Line 3,557 ⟶ 3,669:
(formerly Perl 6)
{{trans|Go}}
<syntaxhighlight lang="raku"
my $level = q:to//;
#######
Line 3,657 ⟶ 3,769:
}
return "No solution";
}</
{{out}}
<pre>Level:
Line 3,672 ⟶ 3,784:
=={{header|Ring}}==
<
#--------------------------------------------------#
# Sokoban Game #
Line 4,055 ⟶ 4,167:
UpdateGameMap(oGame)
lPlayerWin = False
</syntaxhighlight>
Output image:
Line 4,066 ⟶ 4,178:
===Simple Version===
{{trans|Python}}
<
class Sokoban
Line 4,124 ⟶ 4,236:
"No solution"
end
end</
'''Test:'''
<
#######
# #
Line 4,136 ⟶ 4,248:
#######
EOS
puts level, "", Sokoban.new(level).solve</
{{out}}
Line 4,157 ⟶ 4,269:
When a box is pushed there, it doesn't process after that.
<
def initialize(level)
board = level.lines.map(&:rstrip)
Line 4,251 ⟶ 4,363:
"No solution"
end
end</
Runtime: about 0.20 seconds.
Line 4,257 ⟶ 4,369:
This code does a breadth-first search so it finds a solution with a minimum number of moves.
{{trans|OCaml}}<!-- the big difference is that this is all in one procedure for speed as it reduces the amount of packing/unpacking of tuples/lists, and the queue isn't shortened as that's significantly slower for these sorts of board sizes -->
<
proc solveSokoban b {
Line 4,326 ⟶ 4,438:
}
error "no solution"
}</
Demonstration code:
<
"#######"
"# #"
Line 4,338 ⟶ 4,450:
"#######"
}
puts [solveSokoban $level]</
Output: <pre>ulULLulDDurrrddlULrruLLrrUruLLLulD</pre>
Runtime with stock Tcl 8.5 installation: ≅2.2 seconds<!-- on what is now a fairly old machine -->
Line 4,348 ⟶ 4,460:
{{libheader|Wren-set}}
This works but at a rather sedate pace - 26.7 seconds.
<
import "./llist" for DLinkedList
import "./set" for Set
var Board = Tuple.create("Board", ["cur", "sol", "x", "y"])
Line 4,454 ⟶ 4,566:
System.print(level.join("\n"))
System.print()
System.print(Sokoban.new(level).solve())</
{{out}}
|