《算法的乐趣》——华容道游戏

这一章来简单的介绍一下华容道游戏及如何利用算法来计算出其最优步数。

首先对于华容道游戏,我们来介绍一下它的规则。

有点类似于拼图,本质上这是一个5x4的矩阵,我们的目标就是让曹操(2x2)的矩阵从5x4的矩阵中的第5行的3、4列走出来。

游戏规则很简单,但是想要用最小的步数来完成就不那么容易了,这便是我们下面要着力解决的问题。

其实对于学过dfs和bfs的读者,可能已经想到解决的思路了,其实可以搜索所有的状态,然后形成状态树(这和笔者前面介绍的双人对局的博弈树是一个东西),在建树的过程中,我们设置参数step来记录某个节点(即一种棋局状态)的步数,遍历到了所有棋局状态后自然可以轻松找到最少步骤。

下面我们尝试来完善这个过程的数据结构。首先也是最重要的是,在状态树每个节点记录的不同的棋局状态。容易看到,需要有棋局的状态(我们可以利用二维数组储存)、需要参数step来记录步数。是否还需要一些别的数据呢?

我们能够看到,状态树的建立过程中,一个关键所在是建立父子节点的联系,因此对于某个节点,我们还要储存它的父节点状态,这建立起该节点与上一层树结构的联系;同时,我们还要有参数记录基于改节点的布局,下一步的移动步骤,即生成状态树下一层的一条引线。

由此初步的我们可以写出这样的结构体,来记录某个状态。

struct HRD_GAME_STATE
{
   char board[HIGH][WIDE];  //棋局状态
   MOVE_ACTION move;       //下一步的移动策略
   int step;                          //移动步数
   HRD_GAME_STATE * parent; //父节点
}

容易看到在上文的分析中,我们对“下一步的移动步骤”的描述太过模糊,在编程中我们需要将每个动作量化成一条一条可视化的信息。而对于“移动步骤”来说,第一我们需要知道移动谁,这是一个参量,而第二我们需要知道向哪移动,这又是一个参量。因此在上文数据结构中的move其实还是一个结构体变量。即如下的形式。

typedef struct tagMOVE_ACTION
{
   int heroInx;
   int dirIdx;
}MOVE_ACTION;

类似的,我们进行自上而下的程序设计,对于“每个步骤”中的方向,我们有四个方向的选择,因此我们需要继续构造一个结构体数组,来实现变量dirIdx对四个方向一一对应的描述。

typedef struct tagDIRECTION
{
  int hd;
  int vd;
}DIRECTION;

  DIRECTION directions[4] = {{0,1}、{0,-1},{1,0},{-1,0}};
//这里是矩阵坐标,上下移动行变列不变,左右移动列边行不变。

初步了解到了解决解决华容道算法的数据结构,其实与博弈树非常类似,下面便是更加重要的剪枝与优化了。

<未完>

时间: 2024-10-24 21:13:37

《算法的乐趣》——华容道游戏的相关文章

《算法的乐趣》——博弈树与棋类游戏

从这一篇文章开始,笔者开始了对<算法的乐趣>一书的学习.与以往笔者看的面向竞赛的算法数和经典教材不同,这本书接介绍的算法多为在现实生活中或者已经应用在生产实践当中的算法,比如说这篇文章所介绍的博弈树,就是前段时间非常火的人与AI的围棋大战的基础. 需要提前说明的一件事情是,由于本书当中的算法有非常好的应用与实践性,但是受笔者能力和经历所限,可能无法非常给出并分析算法的源代码,因此笔者在文章中介绍这些算法的时候,也主要以算法思想和伪代码为主,如果读者对某个算法的源代码感兴趣,可以留言笔者会将原作

【算法题目】2048游戏的最少时间 最大数

1.搜狐技术中心笔试遇到的题目 描述:假设滑动一次需要1秒,新出现是4的概率很小可以忽略,加到2048的需要的时间最少是多少? 分析:全部由2相加,得到4需要1次相加,得到8需要3次相加--得到2048需要1024-1次相加 (1024-1)/60约为17分钟 实际上,在进行加法前可能需要等待 新元素2的出现,那么估算的最少时间必然大于17分钟 具体枚举: 目标 需要时间 ? 1 2 3 4 5 6 2      0 4      3 8      5 16    10 32    20   

《算法的乐趣》前言中面试算法。

刚刚看了王晓华前辈在<算法的乐趣>一书的前言中提到了一个面试题: 有一个由若干正整数组成的数列,数列中中的每一个数都不超过32.已知数列中存在反复的数字.请给出一个算法找出这个数列中全部反复的数字. 我用java实现了一种方法: package com.wr.FindSameNum; public class FindSameNum { public static void main(String[] args){ int[] myInput = {1,2,3,4,5,32,5,15,14,2

Java初学之华容道游戏

1 package hhuarongdao; 2 3 public class example { 4 public static void main(String args[]) 5 { 6 new Hua_Rong_Road(); 7 } 8 } 1 package hhuarongdao; 2 import java.awt.*; 3 import javax.swing.*; 4 5 import java.awt.event.*; 6 public class Hua_Rong_Roa

模拟算法_掷骰子游戏&amp;&amp;猜数游戏

模拟算法是用随机函数来模拟自然界中发生的不可预测的情况,C语言中是用srand()和rand()函数来生成随机数. 先来介绍一下随机数的生成: 1.产生不定范围的随机数 函数原型:int rand() 产生一个介于0~RAD_MAX间的整数,其具体值与系统有关系.Linux下为2147483647.我们可以在include文件夹中的stdlib.h中可以看到(Linux在usr目录下,Windows在安装目录下) 1 #include<stdio.h> 2 #include<stdlib

Maze_AI: 一款基于 Python + Pygame + AI 算法的迷宫小游戏

大三课程设计周自己一个人写的迷宫小游戏 (一)课题内容 实现走迷宫. 主要功能为界面显示.上下左右键的响应以及当前步数统计. 通过该课题全面熟悉数组.字符串等的使用,掌握程序设计的基本方法及友好界面的设计. (二)课题要求 1. 基本要求 (1)游戏界面显示:迷宫地图.上下左右移动的特效. (2)动作选择:上下左右键对应于上下左右的移动功能,遇到障碍的处理. (3)得分统计功能:步数等. 2. 扩展要求 (1)用户数据管理. (2)设计一个自动走迷宫的程序,使得得到最短路径. (三)组队分工情况

三个水桶等分8升水的问题 -《算法的乐趣》

智力题目 有三个容积分别为3升.5升.8升的水桶,其中容积为8升的水桶中装满了水,容积为3升和容积为5升的水桶都是空的.三个水桶都没有刻度,现在需要将大水桶中的8升水等分成两份,每份都是4升水,附加条件是只能这三个水桶,不能借助其他辅助容器. “恩,是的,这是一个很经典的问题.” “然而,我们并不能想全,不信请继续往下看.”答案 ”废话不多说,直接看方法吧.“第一种(7步) 将8L的水桶中的水,倒满5L的水桶,这时:8L水桶为3L.5L水桶为5L.3L水桶为0L 将5L的水桶中的水,倒满3L的水

K:leetcode 5381.查询带键的排列 这题简单,但我还能优化。精益求精,才是算法的乐趣所在!

前言: 本题来自leetcode第184场周赛的第二小题.以前参加过周赛,觉得很有趣.苦于最近一段时间比较忙就没坚持参加了(实际上是借口来着....),由于昨晚思考一些事情,导致睡不着,所以起得有点早,就参加了本场周赛,然后就碰到了这道题. 这题本身并不难,但是在比赛结束后,参看了别人的题解.基本都是用暴力模拟的方式来解决的(虽然也能accept),但本人觉得有着改进空间.为此,特地整理了思路,并将思路整理成文,以期能够共同获得进步. 为循序渐进的讲解该题,按照以往的习惯,先从最简单的方式入手,

【猜牌算法】魔术师的游戏

Description 魔术师手中有m张牌,牌的编号为1-n,魔术师预先将牌排好后迭在一起,牌面朝下.对观众说:我不看牌,只数数就可以猜到每张牌是什么,我大声数数,你们听.不信?你们就看. 魔术师按顺序从上到下数手中的牌,第一次数1,将第一张牌(最上面的那张牌)翻过来放到桌面,正好是牌1.第二次数1.2,将第一张牌放到这迭牌的下面,将第二张牌翻过来放到桌面,正好是牌2.第三次数1.2.3,将前面两张依次放在这迭牌的下面,再翻第三张牌放到桌面,正好是牌3.这样依次进行,将n张牌全翻过来,准确无误.