sokoban推箱子攻略_sokoban全关图解
1.求个推箱子的C++代码 要有注解 800到1000行
2.推箱子存档功能怎么实现
下面是全部代码。可复制存为一个lurd2xsb.hs文件,然后用ghc –make lurd2xsb.hs命令编译,会生成一个lurd2xsb可执行文件。之后用 ./lurd2xsb 或 cat [lurd file] | ./lurd2xsb 命令来运行。也可以用 runhaskell lurd2xsb.hs 直接即时编译并运行。
module Main where
import Data.List (transpose, intercalate)
import System.IO
type Sokoban = [[Char]]
type Solution = String
main = do
putStrLn "\nHaskell LURD2XSB\n\n\t usage: paste LURD solution in one line and press enter.\n"
lurd <- getLine
putStrLn $ intercalate "\n" $ reconstruct lurd
b = ["###", "#@#", "###"]
isLeftLeak :: Sokoban -> Bool
isLeftLeak = foldl (\acc xs -> if head xs /= '#' then True else acc) False
isRightLeak :: Sokoban -> Bool
isRightLeak = foldl (\acc xs -> if last xs /= '#' then True else acc) False
prePad :: Sokoban -> Sokoban
prePad s = if (isLeftLeak s) then map (\x -> ('#':x) ) s else s
sufPad :: Sokoban -> Sokoban
sufPad s = if (isRightLeak s) then map (\x -> x ++ "#") s else s
lastIsBox :: String -> Bool
lastIsBox xs = elem (last xs) "$*"
lastToMan :: String -> String
lastToMan xs = init xs ++ m
where m = (if last xs == '.' then "+" else "@")
headToFloor :: String -> String
headToFloor [] = []
headToFloor (x:xs) = (f:xs)
where f = (if x == '+' || x == '*' || x== '#' then '.' else ' ')
isMan :: Char -> Bool
isMan '@' = True
isMan '+' = True
isMan _ = False
undoRowL :: String -> String
undoRowL xs = if (elem '@' xs || elem '+' xs)
then lastToMan xs1 ++ headToFloor xs2
else xs
where (xs1,xs2) = span (not . isMan ) xs
undoRowPushL :: String -> String
undoRowPushL xs = if (elem '@' xs || elem '+' xs)
then lastToMan xs1 ++ b ++ headToFloor xs3
else xs
where (xs1,xs2@(h:xs3)) = span (not . isMan ) xs
b = (if h == '@' then "$" else "*" )
undoL :: Sokoban -> Sokoban
undoL s = prePad $ map undoRowL s
undoPushL :: Sokoban -> Sokoban
undoPushL s = prePad $ sufPad $ map undoRowPushL s
undo :: Sokoban -> Char -> Sokoban
undo s 'r' = undoL s
undo s 'R' = undoPushL s
undo s 'l' = map reverse $ undoL $ map reverse s
undo s 'L' = map reverse $ undoPushL $ map reverse s
undo s 'd' = transpose . undoL .transpose $ s
undo s 'D' = transpose . undoPushL . transpose $ s
undo s 'u' = transpose . (map reverse) . undoL . (map reverse) . transpose $ s
undo s 'U' = transpose . (map reverse) . undoPushL . (map reverse) . transpose $ s
reconstruct :: Solution -> Sokoban
reconstruct s = foldl (\acc x -> undo acc x) b $ reverse s
2012年4月24日更新:
今天换了一种实现方法,使得看上去更“数学”一些。主要是用 foldl 方法重新实现了 undoRowL 和 undoRowPushL 函数。另外输入输出改用 interact 函数,输入lurd串之后需要用 ctrl – D 执行。
module Main where
import Data.List (transpose, intercalate)
import System.IO (interact)
type Sokoban = [[Char]]
type Solution = String
main = interact $ (++"\n") . (intercalate "\n") . reconstruct
b = ["###", "#@#", "###"]
isLeftLeak :: Sokoban -> Bool
isLeftLeak = foldl (\acc xs -> if head xs /= '#' then True else acc) False
isRightLeak :: Sokoban -> Bool
isRightLeak = foldl (\acc xs -> if last xs /= '#' then True else acc) False
prePad :: Sokoban -> Sokoban
prePad s = if (isLeftLeak s) then map (\x -> ('#':x) ) s else s
sufPad :: Sokoban -> Sokoban
sufPad s = if (isRightLeak s) then map (\x -> x ++ "#") s else s
undoRowLStep :: String -> Char -> String
undoRowLStep (' ':xs) '@' = ' ':'@':xs
undoRowLStep ('.':xs) '@' = ' ':'+':xs
undoRowLStep ('#':xs) '@' = ' ':'@':xs
undoRowLStep (' ':xs) '+' = '.':'@':xs
undoRowLStep ('.':xs) '+' = '.':'+':xs
undoRowLStep ('#':xs) '+' = '.':'@':xs
undoRowLStep xs c = c:xs
undoRowPushLStep :: String -> Char -> String
undoRowPushLStep (' ':xs) '@' = '$':'@':xs
undoRowPushLStep ('.':xs) '@' = '$':'+':xs
undoRowPushLStep ('#':xs) '@' = '$':'@':xs
undoRowPushLStep (' ':xs) '+' = '*':'@':xs
undoRowPushLStep ('.':xs) '+' = '*':'+':xs
undoRowPushLStep ('#':xs) '+' = '*':'@':xs
undoRowPushLStep xs@('$':'@':ys) '$' = ' ':xs
undoRowPushLStep xs@('*':'@':ys) '$' = ' ':xs
undoRowPushLStep xs@('$':'+':ys) '$' = ' ':xs
undoRowPushLStep xs@('*':'+':ys) '$' = ' ':xs
undoRowPushLStep xs@('$':'@':ys) '*' = '.':xs
undoRowPushLStep xs@('*':'@':ys) '*' = '.':xs
undoRowPushLStep xs@('$':'+':ys) '*' = '.':xs
undoRowPushLStep xs@('*':'+':ys) '*' = '.':xs
undoRowPushLStep xs@('$':'@':ys) '#' = '.':xs
undoRowPushLStep xs@('*':'@':ys) '#' = '.':xs
undoRowPushLStep xs@('$':'+':ys) '#' = '.':xs
undoRowPushLStep xs@('*':'+':ys) '#' = '.':xs
undoRowPushLStep xs c = c:xs
undoRowL :: String -> String
undoRowL xs = reverse $ foldl undoRowLStep [] xs
undoRowPushL :: String -> String
undoRowPushL xs = reverse $ foldl undoRowPushLStep [] xs
undoL :: Sokoban -> Sokoban
undoL s = prePad $ map undoRowL s
undoPushL :: Sokoban -> Sokoban
undoPushL s = prePad $ sufPad $ map undoRowPushL s
undo :: Sokoban -> Char -> Sokoban
undo s 'r' = undoL s
undo s 'R' = undoPushL s
undo s 'l' = map reverse $ undoL $ map reverse s
undo s 'L' = map reverse $ undoPushL $ map reverse s
undo s 'd' = transpose . undoL .transpose $ s
undo s 'D' = transpose . undoPushL . transpose $ s
undo s 'u' = transpose . (map reverse) . undoL . (map reverse) . transpose $ s
undo s 'U' = transpose . (map reverse) . undoPushL . (map reverse) . transpose $ s
undo s _ = s
reconstruct :: Solution -> Sokoban
reconstruct s = foldl (\acc x -> undo acc x) b $ reverse s
2012年4月28日更新:
前面的实现都不考虑异常情况。事实上,并不是每一个lurd答案都能合法地还原成一个关卡。在利用答案逆推关卡过程中,有三种异常:一是撤销移动时,退回来的位置被箱子占领(如drrulL);二是撤销推动时,退回来的位置被箱子占领(如LURD,这和第一种本质一样);三是撤销推动时,要回退的箱子并不存在(如Rrr)。于是,重新修改了一下程序,使用了 Haskell 的 Maybe Monad 这一特性和 Monad 的 >>= 运算。当lurd答案合法有效时,返回 Just Sokoban,否则返回 Nothing 。
module Main where
import Data.List (transpose)
type Sokoban = [[Char]]
type Solution = String
main = do
putStrLn "\nHaskell LURD2XSB\n\n\t usage: paste LURD solution in one line and press enter.\n"
lurd <- getLine
putStrLn $ map reformat $ show $ reconstruct lurd
reformat :: Char -> Char
reformat '[' = '\n'
reformat ']' = '\n'
reformat ',' = '\n'
reformat '"' = ' '
reformat x = x
b = ["###", "#@#", "###"]
isLeftLeak :: Sokoban -> Bool
isLeftLeak = foldl (\acc xs -> if head xs /= '#' then True else acc) False
isRightLeak :: Sokoban -> Bool
isRightLeak = foldl (\acc xs -> if last xs /= '#' then True else acc) False
prePad :: Sokoban -> Sokoban
prePad s = if (isLeftLeak s) then map (\x -> ('#':x) ) s else s
sufPad :: Sokoban -> Sokoban
sufPad s = if (isRightLeak s) then map (\x -> x ++ "#") s else s
undoRowLStep :: String -> Char -> String
undoRowLStep (' ':xs) '@' = ' ':'@':xs
undoRowLStep ('.':xs) '@' = ' ':'+':xs
undoRowLStep ('#':xs) '@' = ' ':'@':xs
undoRowLStep ('$':xs) '@' = ' ':'e':xs
undoRowLStep ('*':xs) '@' = ' ':'e':xs
undoRowLStep (' ':xs) '+' = '.':'@':xs
undoRowLStep ('.':xs) '+' = '.':'+':xs
undoRowLStep ('#':xs) '+' = '.':'@':xs
undoRowLStep ('$':xs) '+' = ' ':'e':xs
undoRowLStep ('*':xs) '+' = ' ':'e':xs
undoRowLStep xs c = c:xs
undoRowPushLStep :: String -> Char -> String
undoRowPushLStep (' ':xs) '@' = '$':'@':xs
undoRowPushLStep ('.':xs) '@' = '$':'+':xs
undoRowPushLStep ('#':xs) '@' = '$':'@':xs
undoRowPushLStep ('$':xs) '@' = '$':'e':xs
undoRowPushLStep ('*':xs) '@' = '$':'e':xs
undoRowPushLStep (' ':xs) '+' = '*':'@':xs
undoRowPushLStep ('.':xs) '+' = '*':'+':xs
undoRowPushLStep ('#':xs) '+' = '*':'@':xs
undoRowPushLStep ('$':xs) '+' = '*':'e':xs
undoRowPushLStep ('*':xs) '+' = '*':'e':xs
undoRowPushLStep xs@('$':'@':ys) '$' = ' ':xs
undoRowPushLStep xs@('*':'@':ys) '$' = ' ':xs
undoRowPushLStep xs@('$':'+':ys) '$' = ' ':xs
undoRowPushLStep xs@('*':'+':ys) '$' = ' ':xs
undoRowPushLStep xs@('$':'@':ys) '*' = '.':xs
undoRowPushLStep xs@('*':'@':ys) '*' = '.':xs
undoRowPushLStep xs@('$':'+':ys) '*' = '.':xs
undoRowPushLStep xs@('*':'+':ys) '*' = '.':xs
undoRowPushLStep xs@('$':'@':ys) '#' = '.':xs
undoRowPushLStep xs@('*':'@':ys) '#' = '.':xs
undoRowPushLStep xs@('$':'+':ys) '#' = '.':xs
undoRowPushLStep xs@('*':'+':ys) '#' = '.':xs
undoRowPushLStep xs@('$':'@':ys) ' ' = 'e':xs
undoRowPushLStep xs@('*':'@':ys) ' ' = 'e':xs
undoRowPushLStep xs@('$':'+':ys) ' ' = 'e':xs
undoRowPushLStep xs@('*':'+':ys) ' ' = 'e':xs
undoRowPushLStep xs@('$':'@':ys) '.' = 'e':xs
undoRowPushLStep xs@('*':'@':ys) '.' = 'e':xs
undoRowPushLStep xs@('$':'+':ys) '.' = 'e':xs
undoRowPushLStep xs@('*':'+':ys) '.' = 'e':xs
undoRowPushLStep xs c = c:xs
undoRowL :: String -> String
undoRowL xs = reverse $ foldl undoRowLStep [] xs
undoRowPushL :: String -> String
undoRowPushL xs = reverse $ foldl undoRowPushLStep [] xs
undoL :: Sokoban -> Sokoban
undoL s = prePad $ map undoRowL s
undoPushL :: Sokoban -> Sokoban
undoPushL s = prePad $ sufPad $ map undoRowPushL s
undo :: Char -> Sokoban -> Sokoban
undo 'r' s = undoL s
undo 'R' s = undoPushL s
undo 'l' s = map reverse $ undoL $ map reverse s
undo 'L' s = map reverse $ undoPushL $ map reverse s
undo 'd' s = transpose . undoL .transpose $ s
undo 'D' s = transpose . undoPushL . transpose $ s
undo 'u' s = transpose . (map reverse) . undoL . (map reverse) . transpose $ s
undo 'U' s = transpose . (map reverse) . undoPushL . (map reverse) . transpose $ s
undo _ s = s
undo2 :: Char -> Sokoban -> Maybe Sokoban
undo2 x s =
let s' = undo x s
in if elem 'e' (concat s') then Nothing else Just s'
reconstruct :: Solution -> Maybe Sokoban
reconstruct [] = Just b
reconstruct (x:xs) = reconstruct xs >>= undo2 x
求个推箱子的C++代码 要有注解 800到1000行
sudoku52 说的对, 他给的参考资料链接有教程。
魔方吧论坛推箱子专区也有。
魔方吧里面给的其实就是动画制作过程。
动画制作过程三个步骤:
(1) 截图 -- 那个教程是用YSOKOBANBMP做截图。
但你是可以用你喜欢用的软件做截图的。 ALT+PRINT SCREEN热键也可以。
基本上是, 答案的每一步, 做一个截图。
你应该也看到, 如果答案有200步, 你就需要做200个截图。 有点麻烦。
(2) 剪裁 (如果有需要, 可以删除你不需要的部分)
(3) 用动画软件制作动画。不同软件, 用法有点不同。
做出来的动画文件大小也不同。
那个教程是用UNFREEZ。
但你也可以用其它软件,
如: ULEAD GIF ANIMATION, GIF MAKER, GIFSICLE,...等。
教程里面用YSOKOBANBMP做截图, 那是因为它可以自动每一步做一个截图。
但在它可以做截图之前, 它当然需要知道答案。
如果你用YSOKOBANBMP推过关卡, 它就会自动记下答案。
按F2就可以重播答案。
像教程里面说, 让它自动截图,
按: CTRL+F3 (开动自动截图的功能)
然后按 F2 就可以了。
教程其实已经很清楚。
如果还有疑问, 可以在那个教程跟帖发问。
补充回复:
可能你误会了, YSOKOBANBMP本身是一个推箱子软件。
截图功能只是截它自己窗口的图。
它不是一个截图软件, 不可以截其它软件窗口的图。
如果你想做其它软件的窗口截图, 你需要用其它的截图软件。
做好截图后就可以跟着教程做剩下的步骤。
如果你的目的不是GIF动画, 而是录影,
那你需要的工具就不同了, 步骤也不同了。
你需要“SCREEN RECORDER”软件。(画面录影软件)
这个我少用, 没有好的软件推荐。
推箱子存档功能怎么实现
//*******************************************************
Sokoban.h:?类定义Sokoban.c:?类成员函数实现
Use_Sokoban.c:?主函数
请用VC6(别编译器的也行)先运行Use_Sokoban.c文件,要编译该文件一下,
再点Project->?Add?To?Project->?Files?选择Sokoban.c文件,
即将Sokoban.c加载到工程里,最后运行就OK拉。
//*******************************************************
Sokoban.h
//*******************************************************
#ifndef?SOKOBAN_H_?//防止文件重复包含
#define?SOKOBAN_H_
#include?<queue>
using?std::queue;
//每一步的数据类型
struct?node?
{
int?bx,?by;?//箱子的坐标 int?px,?py;?//人的坐标};
//推箱子类
class?Sokoban?
{
private:
enum?{L?=?15,?H?=?7}; char?GameMap[H][L];?//地图 int?Pex,?Pey;?//人的位置 int?Boxx,?Boxy;?//箱子的位置int?Succeed,?Prove;?//是否成功到目的地,?是否可玩性
int?dx[4],?dy[4];?//方向数组
protected:
char?Empty; char?People; char?Box; char?Block; char?Target; int?dir;?//记录按键方向 node?s,?e;public:
Sokoban();?//构建函数 ~Sokoban()?{}?//析构函数,即为inline //地图初始化函数 void?Initial(); //箱子路劲验证函数,参数为箱子坐标(bx,by),人坐标(px,py) void?Box_Bfs(int?bx,?int?by,?int?px,?int?py); //人路劲验证函数,人所到的目的地(ex,ey) bool?People_Bfs(int?ex,?int?ey); //地图刷新函数 void?Show(); //按键判断函数 void?Button(); //箱子人移动函数 void?Move(); //验证越界函数 bool?Check(int?x,?int?y);?};
#endif
//*******************************************************
Sokoban.cpp
//*******************************************************
#include?"Sokoban.h"
#include?<cstring>
#include?<cstdlib>
#include?<ctime>
#include?<iostream>
#include?<conio.h>
using?std::cout;
using?std::endl;
Sokoban::Sokoban()?//构建函数即对变量初始化
{
dir?=?-1; Succeed?=?Prove?=?0; memset(GameMap,?'.',?sizeof(GameMap)); Empty?=?'.'; People?=?'P'; Box?=?'#'; Block?=?'*'; Target?=?'T'; //方向依次为上右下左 dx[0]?=?-1;?dx[1]?=?0;?dx[2]?=?1;?dx[3]?=?0;? dy[0]?=?0;dy[1]?=?1;?dy[2]?=?0;?dy[3]?=?-1;//随机,使程序每次运行时所产生的随机数不同
srand(time(0));}
//地图初始化函数
void?Sokoban::Initial()
{
int?count?=?0,?x,?y; //对地图中随机产生25个阻碍物 while(count?!=?25) { x?=?rand()%H; y?=?rand()%L;if(GameMap[x][y]?==?Empty)
{GameMap[x][y]?=?Block;
count++; } } while(true)?//随机产生人开始的位置 { x?=?rand()%H; y?=?rand()%L; if(GameMap[x][y]?==?Empty) {GameMap[x][y]?=?People;
Pex?=?x;
Pey?=?y;
break;
} } while(true)?//随机产生箱子开始的位置 { x?=?rand()%H; y?=?rand()%L; //不让箱子在地图的边界处 if(GameMap[x][y]?==?Empty?&&?x?!=?0?&&?y?!=?0 &&?x?!=?H-1?&&?y?!=?L-1) {GameMap[x][y]?=?Box;
Boxx?=?x;
Boxy?=?y;
break;
} } while(true)?//随机产生目标的位置 { x?=?rand()%H; y?=?rand()%L; if(GameMap[x][y]?==?Empty) {GameMap[x][y]?=?Target;
break;
} } //对游戏地图检查是否可将箱子推到目的地,即判断游戏可玩性 Sokoban::Box_Bfs(Boxx,?Boxy,?Pex,?Pey);? //如游戏不可玩,即再随机产生地图 if(!Prove) {memset(GameMap,?'.',?sizeof(GameMap));
Sokoban::Initial(); } else Sokoban::Show();}
//箱子路劲验证函数
//用BFS算法对箱子验证是否可到目的地
void?Sokoban::Box_Bfs(int?bx,?int?by,?int?px,?int?py)
{
queue<node>_Box;?//创建箱子队列 //visit对上一步走到下一步的记录,防止箱子走重复路劲 //visit[i][j][z][k]表示箱子从点(i,j)到点(z,k) //visit[][][][]为0时表示为走过,1时表示已走过 int?visit[H][L][H][L]; memset(visit,?0,?sizeof(visit));?//visit数组初始化? s.bx?=?bx;?s.by?=?by;?//将起始的箱子、人位置放入队列 s.px?=?px;?s.py?=?py; _Box.push(s); int?pe_x,?pe_y; while(!_Box.empty())?//队列为空时跳出{
s?=?_Box.front();
_Box.pop();
if(GameMap[s.bx][s.by]?==?Target)?//到达目的地
{
Prove?=?1;
break;
}
for(int?i?=?0;?i?<?4;?i++)
{
e.bx?=?s.bx?+?dx[i];?e.by?=?s.by?+?dy[i];
switch(i)?//人推箱子的位置
{
case?0:?pe_x?=?s.bx?+?dx[2];?pe_y?=?s.by?+?dy[2];?break;
case?1:?pe_x?=?s.bx?+?dx[3];?pe_y?=?s.by?+?dy[3];?break;
case?2:?pe_x?=?s.bx?+?dx[0];?pe_y?=?s.by?+?dy[0];?break;
case?3:?pe_x?=?s.bx?+?dx[1];?pe_y?=?s.by?+?dy[1];?break;
}
//验证箱子和人的位置的合法性
if(!Check(e.bx,?e.by)?||?!Check(pe_x,?pe_y)
||?GameMap[e.bx][e.by]?==?Block?||?GameMap[pe_x][pe_y]?==?Block
||?visit[s.bx][s.by][e.bx][e.by]?)
continue;
//如人可推箱子即进入队列
if(Sokoban::People_Bfs(pe_x,?pe_y))?
{
//保存人推箱子后的位置
e.px?=?pe_x;?e.py?=?pe_y;
_Box.push(e);
visit[s.bx][s.by][e.bx][e.by]?=?1;?//箱子路劲的标记
}
}
}}
//人路劲验证函数
//用BFS算法对人验证是否可推箱子
bool?Sokoban::People_Bfs(int?ex,?int?ey)
{
queue<node>_People;node?t,?end;
//visit数组对人的路劲进行标记,0为未走过,1为走过int?visit[H][L];?
//visit数组初始化为0 memset(visit,?0,?sizeof(visit));t.px?=?s.px;?t.py?=?s.py;?//人初始位置进入队列
_People.push(t);
visit[t.px][t.py]?=?1;
while(!_People.empty())?//对立为空时跳出
{
t?=?_People.front();
_People.pop();
if(t.px?==?ex?&&?t.py?==?ey)?//人可到达(ex,ey)该点
return?1;
for(int?i?=?0;?i?<?4;?i++)
{
end.px?=?t.px?+?dx[i];?end.py?=?t.py?+?dy[i];
//检查人的位置合法性
if(!Check(end.px,?end.py)?||?GameMap[end.px][end.py]?==?Block
||?GameMap[end.px][end.py]?==?Box?||?visit[end.px][end.py])
continue;//进入队列
_People.push(end);
visit[end.px][end.py]?=?1;?//记录
}
}
return?0;
}
//地图刷新函数
void?Sokoban::Show()
{
int?i,?j; while(true) {? //每半秒刷新一次地图clock_t?s?=?clock();
while(clock()?-?s?<?CLOCKS_PER_SEC/2) //先判断按键在移动 Sokoban::Button();? Sokoban::Move(); system("cls"); for(i?=?0;?i?<?H;?i++) {for(j?=?0;?j?<?L;?j++)
cout?<<?GameMap[i][j]; cout?<<?endl; } cout?<<?endl; cout?<<?"\n**********************************"?<<?endl; cout?<<?"*?小小C++语言推箱子游戏?*"?<<?endl; cout?<<?"*?游戏规则:?*"?<<?endl; cout?<<?"*?P:?人#:?箱子*"?<<?endl;cout?<<?"*?*:?障碍物T:?目的地?*"?<<?endl;
cout?<<?"**********************************"?<<?endl; cout?<<?"*每次游戏地图不一样*"?<<?endl; cout?<<?"*人将箱子推到目的地即过关*"?<<?endl; cout?<<?"*所给地图,一定可过关,请慎重移箱子*"?<<?endl; cout?<<?"*箱子无路可走时,机器不会提示?*"?<<?endl; cout?<<?"**********************************"?<<?endl; //箱子成功到达目的地 if(Succeed) {cout?<<?"\n^_^?>_<"?<<?endl;
cout?<<?"恭喜过关成功!?再来一盘吧"?<<?endl;
getchar();
break;
} }}
//按键判断函数
void?Sokoban::Button()
{
int?key; if(kbhit()?!=?0)?//检查当前是否有键盘输入,若有则返回一个非0值,否则返回0 {? while(kbhit()?!=?0)?//可能存在多个按键,要全部取完,以最后一个为主 key?=?getch();?//将按键从控制台中取出并保存到key中 switch(key) {?//上
case?72:?dir?=?0;
break;//右
case?77:?dir?=?1;?
break;//下
case?80:?dir?=?2;?
break;//左
case?75:?dir?=?3;?
break; } }}
//人推箱子移动函数
void?Sokoban::Move()
{
int?x,?y; //有按键时 if(dir?!=?-1)? { //人所推向的位置坐标 x?=?Pex?+?dx[dir];?y?=?Pey?+?dy[dir]; //人所推位置为空,即走向该位置 if(Check(x,?y)?&&?GameMap[x][y]?==?'.') {GameMap[Pex][Pey]?=?'.';?//人的位置改变
GameMap[x][y]?=?'P';
Pex?=?x;?Pey?=?y;
dir?=?-1;?//按键记录为无即-1
} else?//人所推位置为箱子,即将箱子推向该方向的前面这点if(Check(x,?y)?&&?GameMap[x][y]?==?'#'
&&?Check(x+dx[dir],?y+dy[dir])
&&?GameMap[?x+dx[dir]?][?y+dy[dir]?]?==?'.')
{
GameMap[Boxx][Boxy]?=?'.';?//箱子的位置改变
GameMap[x+dx[dir]?][?y+dy[dir]?]?=?'#';
Boxx?=?x?+?dx[dir];?Boxy?=?y?+?dy[dir];
GameMap[Pex][Pey]?=?'.';?//人的位置改变
GameMap[x][y]?=?'P';
Pex?=?x;?Pey?=?y;
dir?=?-1;
}
else?//将箱子推向该方向的前面这点为目的地
if(Check(x,?y)?&&?GameMap[x][y]?==?'#'
&&?Check(x+dx[dir],?y+dy[dir])
&&?GameMap[?x+dx[dir]?][?y+dy[dir]?]?==?'T')
{
GameMap[Boxx][Boxy]?=?'.';?//箱子的位置改变GameMap[x+dx[dir]?][?y+dy[dir]?]?=?'#';
Boxx?=?x?+?dx[dir];?Boxy?=?y?+?dy[dir];
GameMap[Pex][Pey]?=?'.';?//人的位置改变
GameMap[x][y]?=?'P';
Pex?=?x;?Pey?=?y;
dir?=?-1;
Succeed?=?1;?//记录成功到达目的地}
}}
//判断越界情况
bool?Sokoban::Check(int?x,?int?y)
{
if(x?<?0?||?x?>=?H?||?y?<?0?||?y?>=?L)return?0;
else
return?1;
}
//*************************************************
Use_Sokoban.cpp
//*************************************************
#include?<iostream>
#include?"Sokoban.h"
using?namespace?std;
int?main()
{
Sokoban?s; s.Initial(); return?0;}
//*************************************************
推箱子存档功能当然是视呼 你用的推箱子程序。
有些推箱子程序可以存档, 有些不可以。
手机版本推箱子我不用, 不清楚什么推箱子程序有存档功能。
PC版本的推箱子程序我用了不少。
点睛推箱子可以自动保存答案。
老封推箱子可以自动保存答案。
国外版本:
YSokoban (中文翻译是歪推箱子) 可以自动保存答案。
YASC 可以自动保存答案。
SokoSe 可以自动保存答案。
SokoMind 可以自动保存答案。
SokoFan 可以自动保存答案。
JSoko 可以自动保存答案。
Sokoban for Windows v3 可以自动保存答案。