借鉴python 实现思想转成php
最短路径:
u表示向上,d表示向下,l表示向左,r表示向右。
大写表示人推着箱子一起动,小写表示人自己走。
以下为实现代码 都写在注释里面
<?php
/*
*推箱子游戏求解算法
*/
class Sokoban {
public $line = null;
public $sta=''; //开始状态
public $en =''; //结束的状态
public $col = null; //最好列宽相等
public $px = -1;
public $py = -1;
public $paths = []; //记录推箱子的最短路径
public $len = -1; //记录最短路径的长度
public function __construct($line,$col){
$this->line = $line;
$this->col = $col;
}
public function start()
{
/*
*1. 获取sta开始状态和en结束的状态
*2. 获得人的起始位置 px , py
*3.
*/
$mp = [];
for ($i =0; $i < 100; $i+=10){
array_push($mp,substr($this->line,$i,10));
}
$len1 = strlen($this->line);
$line = $this->line;
for($i = 0; $i < $len1; $i++ ){
$cx = floor($i / 10);
$cy = $i % 10;
if(substr($line,$i,1) == 4){
$this->px = $cx;
$this->py = $cy;
}
}
# 现在只需要把sta开始的状态中的2位置移动到en的3的位置即满足条件
$staDic = [0,0,2,0,4];
$enDic = [0,1,0,3,0];
//var_dump($len1);
$static = 0;
$entic = 0;
for($i = 0; $i < $len1; $i++){
$j = substr($line, $i,1);
$this->sta .= $staDic[$j];
$this->en .= $enDic[$j];
}
// var_dump($this->sta);
// var_dump($this->en);
}
public function Isok($sta){
$len = strlen($sta);
$len0 = strlen($this->en);
$endlen = $len > $len0 ? $len0 : $len;
// var_dump('sta:',$sta);
// var_dump('en:',$this->en);
for($i = 0; $i < $endlen; $i++){
$s = substr($sta, $i,1);
$e = substr($this->en, $i,1);
if($e == '3' && $s != '2'){
return false;
}
}
return true;
}
//获取最短的路径保存到paths中
public function run(){
// 4个方向,小写代表只是人移动,大写表示人推着箱子一起移动
$dirs = [[-1,0,'u','U'],[1,0,'d','D'],[0,1,'r','R'],[0,-1,'l','L']];
//状态包括字符串表示的当前状态、当前的路径、当前人的位置
$states = [[$this->sta,'',$this->px,$this->py]];
// 定义数组 剔除重复的数据
$visi = [];
$visi[$this->sta] = 1;
$s_len = 1000;
//var_dump($visi);
//$this->dd(count($states));
while (count($states) > 0){
$sta = $states[0][0];
$path = $states[0][1];
$px = $states[0][2];
$py = $states[0][3];
// 4的装填位置 也就是人在哪
$ppos = $px * $this->col + $py;
$states = array_slice($states, 1);
if(strlen($path) > $s_len ){
break;
}
//保存路径到path中
if ($this->Isok($sta)){
if($this->len == -1 || strlen($path) <= $this->len){
array_push($this->paths, $path);
$this->len = strlen($path);
}
continue;
}
foreach($dirs as $k => $v){
$cx = $px + $v[0];
$cy = $py + $v[1];
$pos = $cx * $this->col + $cy;
//var_dump($pos);
//4 挨着的位置
$nx = $px + 2 * $v[0];
$ny = $py + 2 * $v[1];
//人挨着的装填位置
$npos = $nx * $this->col + $ny;
// var_dump($npos);
// continue;
if(!($nx >= 0 && $nx < $this->col && $ny >= 0 && $ny < $this->col )){
var_dump("难道是这个里面吗");
continue;
}
//
//var_dump(substr($sta, $pos,1),substr($this->en, $pos,1));
if($sta["$pos"] == '2' && $sta["$npos"] == '0' && substr($this->en, $npos,1) != '1'){
$sta["$ppos"] = 0;
$sta["$pos"] = 4;
$sta["$npos"] = 2;
//var_dump($digits);exit;
$new_sta= $sta;
// var_dump($new_sta);
// var_dump($visi);
// var_dump(!array_key_exists("$new_sta", $visi));exit;
if(!array_key_exists("$new_sta", $visi)){
$visi["$new_sta"] = 1;
// var_dump($cx);
// var_dump(["$new_sta",$path.$v[3],$cx,$cy]);exit;
array_push($states,["$new_sta",$path.$v[3],$cx,$cy]);
//var_dump("176",$states);
}
}elseif(substr($sta, $pos,1) == '0' && substr($this->en, $pos,1) != '1'){
$sta["$ppos"] = 0;
$sta["$pos"] = 4;
$new_sta = $sta;
if(!array_key_exists("$new_sta", $visi)){
$visi["$new_sta"] = 1;
array_push($states,["$new_sta",$path.$v[2],$cx,$cy]);
}
}
}
}
}
}
$map = '1111111111111111111111100011111110221111111420111111111001111111300111111330011111111111111111111111';
$col = 10;
$obj = new Sokoban($map,$col);
$obj->start();
$obj->run();
var_dump($obj->paths);