一个问题

这堂课,以及接下来的实验,将带你解决一个中等复杂的问题。问题是要在迷宫中找到一条路。

迷宫将从具有以下格式的文本文件加载。

9日13  ############# eoo # #已坏啊# oo啊# # # # # # # # # # #阿阿阿阿呜oo # ooox # # # # # # # # # # # #阿阿ooooooooooo # # # # # # # # # # # # # ooooooooooo阿阿 # #############

文本文件中的第一行给出了迷宫的尺寸——迷宫由多少行和多少列组成。剩下的线条给出了迷宫本身的结构。#代表一堵墙,0代表一个开放空间,e代表入口,x代表出口。

典型的迷宫具有死胡同和循环等特征。任何解决迷宫的算法都必须能够处理这些特征,并仍然找到从入口到出口的路径。

类的集合来解决这个问题

构造面向对象程序来解决复杂问题的第一步是确定将在解决方案中发挥作用的一个或多个类。对于这个问题,有三个类立即浮现出来:

Cell类

下面是一个类的完整源代码,该类可用于表示迷宫赢博体育程序中的单个细胞。

包迷宫;/**一个类来表示迷宫中的细胞。细胞可以被封锁、打开或访问。此外,迷宫的入口和出口*由一种特殊的细胞类型表示。*/公共类Cell{/*类变量*/私有静态final char OPEN = 'o';private static final char VISITED = 'v';private static final char CLOSED = '#';private static final char entry = 'e';private static final char EXIT = 'x';/*成员变量。*/ private int row;Private int column;私有char状态;/*构造函数*/ public Cell(int row,int column,char code) {this。Row = Row;这一点。Column = Column;状态=代码;} /*访问方法*/公共布尔isOpen(){返回状态==打开||状态==入口||状态==退出;}公共布尔is入口(){返回状态==入口;}公共布尔isExit(){返回状态==退出;}公共int getRow(){返回行;}公共int getColumn(){返回列;}公共char toChar(){返回状态;}公共String toString(){返回"(" +行+ "," +列+ ":" + toChar() + ")";} /* Mutator方法*/ public void markVisited() {if(state == OPEN) state = VISITED;}公共无效clearVisited() {if(state == VISITED) state = OPEN;} /*测试程序来测试Cell类。*/ public static void main(String[] args) {Cell firstCell = new Cell(1,1,'o');system . out。println(“访问单元格之前是:” + firstCell.toString());firstCell.markVisited ();system . out。println(“访问单元格后:” + firstCell.toString());System.out.println ();Cell secondCell = new Cell(3,1,'#');system . out。println(“访问单元格之前是:” + secondCell.toString());firstCell.markVisited ();system . out。println(“访问单元格后:” + secondCell.toString());}}

这个类使用了一个特殊的特性,即静态成员变量。与其他成员变量一样,这些变量在类中声明,而不是在任何方法中声明。这些变量的变量声明包含关键字static,它将这些变量标记为静态成员变量。普通成员变量作为变量出现在类的每个对象中,而静态成员变量只在类本身中出现一次。成员变量的一个实例由该类中的赢博体育对象共享。静态成员变量的一个流行赢博体育是定义类常量:类常量是类中用于特殊目的的固定值。要使Java中的变量成为常量,需要在变量声明中添加关键字final。此外,final变量在声明它们的同时被初始化。下面是其中一个静态成员变量:

private static final char OPEN = 'o';

这个声明允许我们在赢博体育代码中使用单词OPEN来代替字母“o”。由于OPEN比‘o’更有意义,这将使我们的代码更不容易出错。

我在这里遵循的另一个策略是将成员变量和方法组织到组中。每当一个类开始包含很多内容时,将内容组织成逻辑分组就会变得很有帮助。我把这些方法分成了几组:

最后,您将在这个类中看到的最后一个东西是main方法。这个main方法的目的是允许我们编写一些简单的测试代码来测试类的操作。

迷宫课堂

下面是我们的赢博体育程序将用来表示迷宫的Maze类的大纲。在这个大纲中,我省略了方法的代码,以便更容易地了解类的结构。

public类Maze{/*成员变量*/ private Cell[][] grid;/*从文件中读取迷宫。*/ public Maze(String fileName){} /* Accessor方法*/ //查找并返回入口单元格public cell findEntrance(){} //查找给定单元格打开的邻居//并返回对该邻居单元格的引用。如果//你找不到这样的邻居,返回null。public Cell findOpenNeighbor(Cell fromCell){} //打印迷宫的内容到系统。out public void print() {} /* Mutator方法*/ /重置赢博体育访问过的cell以打开public void clearVisited(){} //测试程序以测试Maze类public static void main(String args[]){}}

本课程旨在提供足够有用的方法来帮助解决迷宫搜索问题。特别是,该类提供了一个方法,用于查找并返回启动搜索过程所需的入口单元格,还提供了一个方法,用于查找给定单元格的未访问邻居。正如我们将在本周的实验练习中看到的,这两种方法足以让我们解决迷宫搜索问题。

Path类

我们需要解决迷宫搜索问题的最后一个类是一个可以表示迷宫路径的类。在迷宫搜索开始时,路径将只包含一个单元格,即迷宫的入口单元格。随着搜索的进行,我们将系统地向路径中添加cell。有时,这条路会进入死胡同。当这种情况发生时,我们将无法为路径末端的单元格找到任何未访问的邻居,我们将不得不返回到存在未访问邻居的点。为了促进这一点,我们必须能够从路径的末端脱落细胞。

下面是Path类的概要,展示了它的方法和成员变量。

public class Path{/*成员变量*/ private ArrayList<Cell> cells;//保存路径上的单元格/*构造一个初始空路径。*/ public Path() {} /* Accessor methods */ //返回路径上的最后一个单元格,如果路径为空则返回null。public Cell lastCell(){} //打印路径上的每个Cell public void Print () {} /* Mutator方法*/ /将给定的Cell添加到路径的末尾public void addCell(Cell toAdd){} //从路径中移除最后一个Cell public void removeCell(){} //测试程序以测试path类public static void main(String args[]) {}}

Path类将其单元存储在一个内部数组列表中。在这里使用ArrayList是合适的结构,因为我们可以从一个空的ArrayList开始,并根据需要使用add()和remove()方法将单元格添加到路径的末尾或删除它们。

解决迷宫问题

我们现在有了解决迷宫问题所需的赢博体育基本成分。在本周的实验中,我们将完成我在上面概述的三个类的构建,并使用这些类来解决迷宫问题。