# 华容道游戏（下）

## 游戏定义

``````class HrdGame{
constructor(caoIdx, heroes){
this.caoIdx = caoIdx;                        //曹操在武将列表中的序号
var startState = new HrdGameState();         //新建开局棋局
startState.initState(heroes)                 //开局棋局初始化
this.states = []                             //存储所有棋局状态，广度搜索的状态空间
this.zhash = {}                              //棋局及其镜像哈希，判重空间
this.result = 0;                             //解的总数
}
}``````

## 算法思路及代码

### 解的判定

``````function isEscaped(game, gameState){            //曹操的位置到达（1，3）
return (gameState.heroes[game.caoIdx -1].left == CAO_ESCAPE_LEFT) && (gameState.heroes[game.caoIdx - 1].top == CAO_ESCAPE_TOP)
}``````

### 棋局搜索

``````function resolveGame(game)                                     //广度搜索主函数
{
let index = 0;
while(index < game.states.length){
gameState = game.states[index];                        //依次选定棋局状态
if(isEscaped(game, gameState)){                        //找到解，输出
game.result++;
console.log('result:'+game.result+' step--'+gameState.step+' index:'+index)
}
else{
searchNewGameStates(game, gameState);             //选定棋局搜索所有新棋局
}
index++;
}
return (game.result > 0);
}``````

### 搜索新棋局

``````function searchNewGameStates(game, gameState)                   //搜索新棋局
{
for(let i = 0; i < gameState.heroes.length; i++)            //遍历武将
{
for(let j = 0; j < MAX_MOVE_DIRECTION; j++)             //遍历所有方向
{
trySearchHeroNewState(game, gameState, i, j);       //移动武将产生新棋局
}
}
}``````

### 新棋局生成

``````function trySearchHeroNewState(game, gameState, heroIdx, dirIdx)
{
let newState = moveHeroToNewState(gameState, heroIdx, dirIdx);    //新棋局产生
if(newState) {
{
/*尝试连续移动，根据华容道游戏规则，连续的移动也只算一步*/
tryHeroContinueMove(game, newState, heroIdx, dirIdx);
return;
}
}
}``````

### 移动武将

``````function moveHeroToNewState(gameState, heroIdx, dirIdx)
{
if(canHeroMove(gameState, heroIdx, dirIdx))                //能够移动
{
var newState = new HrdGameState();                     //新建棋局
if(newState)
{
copyGameState(gameState, newState);                //用父棋局初始化新棋局
var hero = newState.heroes[heroIdx];               //取得武将
const dir = DIRECTION[dirIdx];                     //取得方向

clearPosition(newState, hero.type, hero.left, hero.top); //清除父棋局信息
takePosition(newState, heroIdx, hero.type, hero.left + dir[0], hero.top + dir[1]);            //新棋局数据生成
hero.left = hero.left + dir[0];                    //武将新位置设定
hero.top = hero.top + dir[1];

newState.step = gameState.step + 1;                //移动步数加一
newState.parent = gameState;                       //形成因果链
newState.move.heroIdx = heroIdx;                   //记录移动方法
newState.move.dirIdx = dirIdx;
return newState;                                   //返回新棋局
}
}
return null;
}``````

### 处理棋局

``````function addNewStatePattern(game, gameState)
{
var l2rHash = getZobristHash(zobHash, gameState);            //计算棋局哈希值
if(!game.zhash[l2rHash])                                     //棋局不存在
{
game.zhash[l2rHash] = l2rHash;                           //棋局哈希存储
var r2lHash = getMirrorZobristHash(zobHash, gameState);
game.zhash[r2lHash] = r2lHash;                           //棋局镜像哈希存储
game.states.push(gameState);                             //棋局存储

return true;
}

return false;                                                //棋局已经存在，忽略
}``````

## 开局及解

### 横刀立马

``````var hs =[new Warrior(WARRIOR_TYPE.HT_VBAR,0,0),
new Warrior(WARRIOR_TYPE.HT_BOX,1,0),
new Warrior(WARRIOR_TYPE.HT_VBAR,3,0),
new Warrior(WARRIOR_TYPE.HT_VBAR,0,2),
new Warrior(WARRIOR_TYPE.HT_HBAR,1,2),
new Warrior(WARRIOR_TYPE.HT_VBAR,3,2),
new Warrior(WARRIOR_TYPE.HT_BLOCK,0,4),
new Warrior(WARRIOR_TYPE.HT_BLOCK,1,3),
new Warrior(WARRIOR_TYPE.HT_BLOCK,2,3),
new Warrior(WARRIOR_TYPE.HT_BLOCK,3,4)
]``````

``````result:1 step--81 index:11930
result:2 step--85 index:12123
result:3 step--98 index:12337
result:4 step--101 index:12348``````

### 指挥若定

``````var hs = [new Warrior(WARRIOR_TYPE.HT_VBAR,0,0),          //构建武将列表，初始棋局
new Warrior(WARRIOR_TYPE.HT_BOX,1,0),
new Warrior(WARRIOR_TYPE.HT_VBAR,3,0),
new Warrior(WARRIOR_TYPE.HT_BLOCK,0,2),
new Warrior(WARRIOR_TYPE.HT_HBAR,1,2),
new Warrior(WARRIOR_TYPE.HT_BLOCK,3,2),
new Warrior(WARRIOR_TYPE.HT_VBAR,0,3),
new Warrior(WARRIOR_TYPE.HT_BLOCK,1,3),
new Warrior(WARRIOR_TYPE.HT_BLOCK,2,3),
new Warrior(WARRIOR_TYPE.HT_VBAR,3,3)
]``````

``````result:1 step--73 index:11391
result:2 step--84 index:12207
result:3 step--86 index:12263
result:4 step--89 index:12306``````

### 兵分三路

``````var hs = [new Warrior(WARRIOR_TYPE.HT_BLOCK,0,0),          //构建武将列表，初始棋局
new Warrior(WARRIOR_TYPE.HT_BOX,1,0),
new Warrior(WARRIOR_TYPE.HT_BLOCK,3,0),
new Warrior(WARRIOR_TYPE.HT_VBAR,0,1),
new Warrior(WARRIOR_TYPE.HT_HBAR,1,2),
new Warrior(WARRIOR_TYPE.HT_VBAR,3,1),
new Warrior(WARRIOR_TYPE.HT_VBAR,0,3),
new Warrior(WARRIOR_TYPE.HT_BLOCK,1,3),
new Warrior(WARRIOR_TYPE.HT_BLOCK,2,3),
new Warrior(WARRIOR_TYPE.HT_VBAR,3,3)
]``````

``````result:1 step--74 index:7767
result:2 step--80 index:9212
result:3 step--94 index:10921
result:4 step--97 index:11157``````

## 完整代码

``https://gitee.com/zhoutk/test``

## 小结

#### 你可能感兴趣的

2 条评论
Igin · 2018年09月05日

0

zhoutk 作者 · 2018年09月06日