📄 mazegame.java
字号:
// 全部水平墙状态初始化为"存在"
for (int i = 0; i < this.height + 1; i++)
for (int j = 0; j < this.width; j++)
horizontal[i][j] = Wall.exist;
// 全部竖直墙状态初始化为"存在"
for (int i = 0; i < this.height; i++)
for (int j = 0; j < this.width + 1; j++)
vertical[i][j] = Wall.exist;
// 迷宫左上角方格为入口,因此它的左墙为不存在
vertical[0][0] = Wall.notExist;
// 迷宫右下角为出口,因此它的右墙不存在
vertical[this.height - 1][this.width] = Wall.notExist;
// 随机生成迷宫.其实质是:拆除若干个水平墙和竖直墙以便能形成迷宫
generate(0, 0);
// 生成迷宫后立刻遍历,得到答案:checks[i][j]为Check.main的都是在主路径上
//分析Java程序设计教程书上的算法,是从首格开始的valid,但是本算法不是从首格开始.因此要从0,1开始,若不行则从1,0开始
if(!traverse(0, 0, 0, 1))traverse(0, 0, 1, 0);
// 遍历完后可能有些不在主路径上的方格未设置成Check.notMain,最好执行以下语句
for (int i = 0; i < this.height; i++)
for (int j = 0; j < this.width; j++)
if(checks[i][j]!=Check.main)
checks[i][j] = Check.notMain;
}
/**
* 生成一个随机迷宫,本方法提供给构造方法及newMaze方法调用. 实质是:拆除若干个水平墙和竖直墙.算法来源:java2游戏设计,清华大学出版社
*
* @param i
* 可以是0至height-1中任一数值,建议输入0
* @param j
* 可以是0至width-1中任一数值,建议输入0
*/
private void generate(int i, int j) {
notMarked[i][j] = false;// 标记这个方格,以便不再访问
Random gen = new Random();// 用于随机一个方向
if (i == 0 && j == 0)// 左上角方格
while (notMarked[i + 1][j] || notMarked[i][j + 1])// 只要下面的方格和右边方格有一个未标记就进入循环
{
switch (gen.nextInt(2)) {
case 0:
if (notMarked[i + 1][j])// 下面方格未标记
{
horizontal[i + 1][j] = Wall.notExist;// 拆除它们之间的墙,使它们连通
generate(i + 1, j);
}// 继续从此方格开始生成
break;
case 1:
if (notMarked[i][j + 1])// 右边方格未标记
{
vertical[i][j + 1] = Wall.notExist;// 拆除它们之间的墙,使它们连通
generate(i, j + 1);
}// 继续从此方格开始生成
break;
}
}
if (i == this.height - 1 && j == 0)// 左下角方格
while (notMarked[i - 1][j] || notMarked[i][j + 1])// 只要上面的方格和右边方格有一个未标记就进入循环
{
switch (gen.nextInt(2)) {
case 0:
if (notMarked[i - 1][j])// 上面方格未标记
{
horizontal[i][j] = Wall.notExist;// 拆除它们之间的墙,使它们连通
generate(i - 1, j);
}// 继续从此方格开始生成
break;
case 1:
if (notMarked[i][j + 1])// 右边方格未标记
{
vertical[i][j + 1] = Wall.notExist;// 拆除它们之间的墙,使它们连通
generate(i, j + 1);
}// 继续从此方格开始生成
break;
}
}
// 以下算法同上,不详述.总之是分类:四个角,四条边,其余.
if (i == 0 && j == this.width - 1)// 右上角方格
while (notMarked[i + 1][j] || notMarked[i][j - 1]) {
switch (gen.nextInt(2)) {
case 0:
if (notMarked[i + 1][j]) {
horizontal[i + 1][j] = Wall.notExist;// 拆除它们之间的墙,使它们连通
generate(i + 1, j);
}// 继续从此方格开始生成
break;
case 1:
if (notMarked[i][j - 1]) {
vertical[i][j] = Wall.notExist;// 拆除它们之间的墙,使它们连通
generate(i, j - 1);
}// 继续从此方格开始生成
break;
}
}
if (i == this.height - 1 && j == this.width - 1)// 右下角方格
while (notMarked[i - 1][j] || notMarked[i][j - 1]) {
switch (gen.nextInt(2)) {
case 0:
if (notMarked[i - 1][j]) {
horizontal[i][j] = Wall.notExist;// 拆除它们之间的墙,使它们连通
generate(i - 1, j);
}// 继续从此方格开始生成
break;
case 1:
if (notMarked[i][j - 1]) {
vertical[i][j] = Wall.notExist;// 拆除它们之间的墙,使它们连通
generate(i, j - 1);
}// 继续从此方格开始生成
break;
}
}
if (i == 0 && j != 0 && j != this.width - 1)// 第一行方格除了左上角和右上角
while (notMarked[i][j + 1] || notMarked[i][j - 1]
|| notMarked[i + 1][j]) {
switch (gen.nextInt(3)) {
case 0:
if (notMarked[i][j + 1]) {
vertical[i][j + 1] = Wall.notExist;
generate(i, j + 1);
}
break;
case 1:
if (notMarked[i][j - 1]) {
vertical[i][j] = Wall.notExist;
generate(i, j - 1);
}
break;
case 2:
if (notMarked[i + 1][j]) {
horizontal[i + 1][j] = Wall.notExist;
generate(i + 1, j);
}
break;
}
}
if (i == this.height - 1 && j != 0 && j != this.width - 1)// 最后一行方格除了左下角和右下角
while (notMarked[i][j - 1] || notMarked[i][j + 1]
|| notMarked[i - 1][j]) {
switch (gen.nextInt(3)) {
case 0:
if (notMarked[i][j - 1]) {
vertical[i][j] = Wall.notExist;
generate(i, j - 1);
}
break;
case 1:
if (notMarked[i][j + 1]) {
vertical[i][j + 1] = Wall.notExist;
generate(i, j + 1);
}
break;
case 2:
if (notMarked[i - 1][j]) {
horizontal[i][j] = Wall.notExist;
generate(i - 1, j);
}
break;
}
}
if (j == 0 && i != 0 && i != this.height - 1)// 第一列方格除了左上角和左下角
while (notMarked[i - 1][j] || notMarked[i + 1][j]
|| notMarked[i][j + 1]) {
switch (gen.nextInt(3)) {
case 0:
if (notMarked[i - 1][j]) {
horizontal[i][j] = Wall.notExist;
generate(i - 1, j);
}
break;
case 1:
if (notMarked[i + 1][j]) {
horizontal[i + 1][j] = Wall.notExist;
generate(i + 1, j);
}
break;
case 2:
if (notMarked[i][j + 1]) {
vertical[i][j + 1] = Wall.notExist;
generate(i, j + 1);
}
break;
}
}
if (j == this.width - 1 && i != 0 && i != this.height - 1)// 最后一列方格除了右上角和右下角
while (notMarked[i - 1][j] || notMarked[i + 1][j]
|| notMarked[i][j - 1]) {
switch (gen.nextInt(3)) {
case 0:
if (notMarked[i - 1][j]) {
horizontal[i][j] = Wall.notExist;
generate(i - 1, j);
}
break;
case 1:
if (notMarked[i + 1][j]) {
horizontal[i + 1][j] = Wall.notExist;
generate(i + 1, j);
}
break;
case 2:
if (notMarked[i][j - 1]) {
vertical[i][j] = Wall.notExist;
generate(i, j - 1);
}
break;
}
}
if (i > 0 && i < this.height - 1 && j > 0 && j < this.width - 1)// 除了最外面一层方格外的其余方格(即有(height-2)*(width-2)个)
while (notMarked[i - 1][j] || notMarked[i + 1][j]
|| notMarked[i][j - 1] || notMarked[i][j + 1]) {
switch (gen.nextInt(4)) {
case 0:
if (notMarked[i - 1][j]) {
horizontal[i][j] = Wall.notExist;
generate(i - 1, j);
}
break;
case 1:
if (notMarked[i + 1][j]) {
horizontal[i + 1][j] = Wall.notExist;
generate(i + 1, j);
}
break;
case 2:
if (notMarked[i][j - 1]) {
vertical[i][j] = Wall.notExist;
generate(i, j - 1);
}
break;
case 3:
if (notMarked[i][j + 1]) {
vertical[i][j + 1] = Wall.notExist;
generate(i, j + 1);
}
break;
}
}
}
/**
* 新建一个迷宫,玩家移动,显示(取消)主路径,追赶者移动的时候就自动重画迷宫.
*
* @param page
* 图形上下文
*/
public void paintComponent(Graphics page) {
super.paintComponent(page);
// 画水平的单位墙
page.setColor(Color.black);
for (int i = 0; i < this.height + 1; i++)
for (int j = 0; j < this.width; j++)
if (horizontal[i][j] == Wall.exist)// 这个水平单位墙存在才画
page.drawLine(j * checkSize, i * checkSize, j * checkSize
+ checkSize, i * checkSize);
// 画竖直的单位墙
page.setColor(Color.black);
for (int i = 0; i < this.height; i++)
for (int j = 0; j < this.width + 1; j++)
if (vertical[i][j] == Wall.exist)// 这个竖直单位墙存在才画
page.drawLine(j * checkSize, i * checkSize, j * checkSize,
i * checkSize + checkSize);
// 画终点
page.setColor(Color.darkGray);
page.drawString("终点", this.width * checkSize, this.height * checkSize);
if (!solve) {// 如果解答为关,画玩家位置
page.setColor(Color.blue);
page.fillOval(playerColumn * checkSize, playerRow * checkSize,
checkSize, checkSize);
}
if (chase && !solve) {// 如果解答为关且追赶者为开则画追赶者
page.setColor(Color.red);
for (Chaser chaser : chasers)
page.fillOval(chaser.column * checkSize,
chaser.row * checkSize, checkSize, checkSize);
}
if (solve) {// 如果解答为"开",就画出主路径
page.setColor(Color.green);
for (int i = 0; i < this.height; i++)
for (int j = 0; j < this.width; j++)
if (checks[i][j] == Check.main)// 方格在主路径上
page.fillOval(j * checkSize, i * checkSize, checkSize,
checkSize);
}
}
/**
* 在本迷宫面板上重新随机生成一个迷宫.设置同初始化的一样
* 这是新生成迷宫的提示:这是一个迷宫游戏.玩家是蓝点,走到右下角就赢.若途中碰到两个红点追赶者就输.请按键盘的方向键移动
* (建议新生成迷宫时给予玩家提示)
*
* @param checkSize
* (迷宫由单位方格构成)单位方格的边长,以像素输入
* @param width
* 迷宫的宽度.例如:宽度若为3即宽度为3个单位方格
* @param height
* 迷宫的高度.例如:高度若为3即高度为3个单位方格
* @param numberOfChasers
* 追赶者的数量(不要追赶者则为0)
* @param tearDownAllowed
* 玩家可拆墙次数限制(不可拆墙则为0,可拆无数次则为-1)
*/
public void newMaze(int checkSize, int width, int height,
int numberOfChasers, int tearDownAllowed) {
this.checkSize = checkSize;
this.width = width;
this.height = height;
this.tearDownAllowed = tearDownAllowed;
this.playerRow = 0;
this.playerColumn = 0;// 玩家初始在左上角的方格:起点
this.solve = false;// 不打印结果
this.timer = new Timer(DELAY, new TimerListener());// 追赶者移动定时器
if (numberOfChasers < 1){
this.chase = false;// 玩家设定追赶者为"关"
chasers=new Chaser[0];}
else {
this.chase=true;
chasers = new Chaser[numberOfChasers];// 初始化追赶者
for (int i = 0; i < numberOfChasers; i++) {
Random gen = new Random();
int ranRow, ranColumn;
ranRow = gen.nextInt(this.height);
ranColumn = gen.nextInt(this.width);
chasers[i] = new Chaser(ranRow, ranColumn);
}
chaseOn();// 开启追赶者,使其移动
}
this.currentResult = 0;// 游戏进行中
this.checks = new Check[this.height][this.width];// 迷宫为height*width个方格
this.horizontal = new Wall[this.height + 1][this.width];
// 单位水平墙.horizontalWalls有height*width-1个
this.vertical = new Wall[this.height][this.width + 1];
// 单位竖直墙.horizontalWalls有(height-1)*width个
this.notMarked = new boolean[this.height][this.width];
// 单位方格是否有标记过(在随机生成迷宫时需要)
// 以下为迷宫具体初始化:
// 全部方格状态初始化为"未踏足过"
for (int i = 0; i < this.height; i++)
for (int j = 0; j < this.width; j++)
checks[i][j] = Check.notFoot;
// 全部方格初始化为"未标记"
for (int i = 0; i < this.height; i++)
for (int j = 0; j < this.width; j++)
notMarked[i][j] = true;
// 全部水平墙状态初始化为"存在"
for (int i = 0; i < this.height + 1; i++)
for (int j = 0; j < this.width; j++)
horizontal[i][j] = Wall.exist;
// 全部竖直墙状态初始化为"存在"
for (int i = 0; i < this.height; i++)
for (int j = 0; j < this.width + 1; j++)
vertical[i][j] = Wall.exist;
// 迷宫左上角方格为入口,因此它的左墙为不存在
vertical[0][0] = Wall.notExist;
// 迷宫右下角为出口,因此它的右墙不存在
vertical[this.height - 1][this.width] = Wall.notExist;
// 随机生成迷宫.其实质是:拆除若干个水平墙和竖直墙以便能形成迷宫
generate(0, 0);
// 生成迷宫后立刻遍历,得到答案:checks[i][j]为Check.main的都是在主路径上
//分析Java程序设计教程书上的算法,是从首格开始的valid,但是本算法不是从首格开始.因此要从0,1开始,若不行则从1,0开始
if(!traverse(0, 0, 0, 1))traverse(0, 0, 1, 0);
// 遍历完后可能有些不在主路径上的方格未设置成Check.notMain,最好执行以下语句
for (int i = 0; i < this.height; i++)
for (int j = 0; j < this.width; j++)
if(checks[i][j]!=Check.main)
checks[i][j] = Check.notMain;
// 新迷宫:重画
repaint();
}
/**
* 本方法供traverse方法调用,用于判断从i1行j1列的方格走到i2行j2列的方格是否可行
*
* @param i1
* 原方格所在行数
* @param j1
* 原方格所在列数
* @param i2
* 目标方格所在行数
* @param j2
* 目标方格所在列数
* @return 从原格走到目标格可行则返回true;否则返回false
*/
private boolean valid(int i1, int j1, int i2, int j2) {
boolean result = false;
if (i2 >= 0 && i2 < this.height && j2 >= 0 && j2 < this.width)
if (checks[i2][j2] == Check.notFoot) {// 保证没有越界而且目标方格未踏足过
if (i1 == i2 - 1 && horizontal[i2][j2] == Wall.notExist)// 从上往下
result = true;
else if (i1 == i2 + 1 && horizontal[i1][j1] == Wall.notExist)// 从下往上
result = true;
else if (j1 == j2 - 1 && vertical[i2][j2] == Wall.notExist)// 从左往右
result = true;
else if (j1 == j2 + 1 && vertical[i1][j1] == Wall.notExist)// 从右往左
result = true;
}
return result;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -