1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
当时写的我自认为就很不错了。因为是用递归算法做的,那个年代递归被我们视为神技.........
今天又写了一个版本,不过是基于OO思想的。想法是一只蚂蚁从(0,0)点开始爬,每次遇到墙壁或者已经爬过的地方就向右转,每到一个没有爬过的地方就就踩一个脚印,这样踩完以后区域也就填充完成了。个人认为这个版本虽然代码多,但是可读性好,想法自然,也便于维护,相比算法版本还要好玩很多。要是讨论设计模式,能扯上工厂方法和策略模式....不过现在我对模式这种东西极为反感,写的时候也没有去想这些。
最后贴代码:
首先是填充区域类:
package zone;
import algo.*;
/**
* 填充区域
*
* @author Jeky
*
*/
public class Zone {
/**
* 构造一个新的填充区域
*
* @param size 填充区域大小
*/
public Zone(int size) {
this.size = size;
board = new int[size][size];
}
/**
* 以特定值填充某个位置
*
* @param p 位置
* @param value 值
*/
public void fill(Point p, int value) {
board[p.getX()][p.getY()] = value;
}
/**
* 以特定值填充某个位置
*
* @param x 横坐标
* @param y 纵坐标
* @param value 值
*/
public void fill(int x, int y, int value) {
board[x][y] = value;
}
/**
* 获取某个特定位置的值
*
* @param p 位置
* @return 值
*/
public int get(Point p) {
return board[p.getX()][p.getY()];
}
/**
* 获取某个特定位置的值
*
* @param x 横坐标
* @param y 纵坐标
* @return 值
*/
public int get(int x, int y) {
return board[x][y];
}
/**
* 获取区域大小
*
* @return 区域大小
*/
public int getSize() {
return size;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
sb.append(board[j][i] + "\t");
}
sb.append("\n");
}
return sb.toString();
}
private final int size;
private int[][] board;
}
坐标点:
package zone;
/**
* 二维位置
*
* @author Jeky
*
*/
public class Point {
/**
* 以横纵坐标构造一个新的位置
*
* @param x 横坐标
* @param y 纵坐标
*/
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
/**
* 获得横坐标
*
* @return 横坐标
*/
public int getX() {
return x;
}
/**
* 获得纵坐标
*
* @return 纵坐标
*/
public int getY() {
return y;
}
@Override
public String toString() {
return "(" + x + "," + y + ")";
}
private final int x;
private final int y;
}
填充接口:
package algo;
import zone.Zone;
/**
* 旋转填数接口
*
* @author Jeky
*
*/
public interface ZoneFiller {
/**
* 向区域填充数据
*
* @param zone 填充区域
*/
void fill(Zone zone);
}
递归填充算法:
package algo;
import zone.Zone;
/**
* 以递归模式进行填充的填充类
*
* @author Jeky
*
*/
public class RecursionFiller implements ZoneFiller {
@Override
public void fill(Zone zone) {
int size = zone.getSize();
this.zone = zone;
fill(1, size, 0, 0);
}
/**
* 进行递归填充
*
* @param startNumber 开始数字
* @param size 填充长度
* @param startX 填充开始横坐标
* @param startY 填充开始纵坐标
*/
private void fill(int startNumber, int size, int startX, int startY) {
if (size == 0) {
return;
} else if (size == 1) {
zone.fill(startX, startY, startNumber);
} else {
for (int i = startX; i < size + startX - 1; i++) {
zone.fill(i, startY, startNumber);
startNumber++;
}
for (int i = startY; i < size + startY - 1; i++) {
zone.fill(startX + size - 1, i, startNumber);
startNumber++;
}
for (int i = startX + size - 1; i >= 1 + startX; i--) {
zone.fill(i, startY + size - 1, startNumber);
startNumber++;
}
for (int i = startY + size - 1; i >= 1 + startY; i--) {
zone.fill(startX, i, startNumber);
startNumber++;
}
fill(startNumber, size - 2, startX + 1, startY + 1);
}
}
private Zone zone;
}
蚂蚁填充算法:
package algo;
import zone.Point;
import zone.Zone;
/**
* 蚂蚁类,负责在填充区域上爬行并踩出记号
*
* @author Jeky
*
*/
public class Ant implements ZoneFiller{
public Ant() {
movements = new Movement[4];
movements[0] = new RightMovement();
movements[1] = new DownMovement();
movements[2] = new LeftMovement();
movements[3] = new UpMovement();
nowMovementIndex = 0;
}
/**
* 爬行并踩出记号
*
* @param zone 填充区域
*/
public void fill(Zone zone) {
footPrint = 1;
location = new Point(0, 0);
tread(zone);
int maxPrint = zone.getSize() * zone.getSize();
while (footPrint <= maxPrint) {
Point nextLocation = getNextLocation();
if (canWalkTo(zone, nextLocation)) {
location = nextLocation;
tread(zone);
} else {
changeDirection();
}
}
}
/**
* 踩出记号
*
* @param zone 填充区域
*/
private void tread(Zone zone) {
zone.fill(location, footPrint);
footPrint++;
}
/**
* 获取下一个要爬行到的位置
*
* @return 下一个爬行到的位置
*/
private Point getNextLocation() {
Movement m = movements[nowMovementIndex];
return m.getNextPoint(location);
}
/**
* 是否可以向前爬行
*
* @param zone 填充区域
* @param p 前面的位置
* @return 如果可以向前,返回true,否则返回false
*/
private boolean canWalkTo(Zone zone, Point p) {
return p.getX() >= 0
&& p.getY() >= 0
&& p.getX() < zone.getSize()
&& p.getY() < zone.getSize()
&& zone.get(p) == 0;
}
/**
* 换方向
*/
private void changeDirection() {
nowMovementIndex = (nowMovementIndex + 1) % 4;
}
/**
* 爬行动作
*/
private interface Movement {
Point getNextPoint(Point p);
}
/**
* 向上爬
*/
private class UpMovement implements Movement {
@Override
public Point getNextPoint(Point p) {
return new Point(p.getX(), p.getY() - 1);
}
}
/**
* 向下爬
*/
private class DownMovement implements Movement {
@Override
public Point getNextPoint(Point p) {
return new Point(p.getX(), p.getY() + 1);
}
}
/**
* 向左爬
*/
private class LeftMovement implements Movement {
@Override
public Point getNextPoint(Point p) {
return new Point(p.getX() - 1, p.getY());
}
}
/**
* 向右爬
*/
private class RightMovement implements Movement {
@Override
public Point getNextPoint(Point p) {
return new Point(p.getX() + 1, p.getY());
}
}
private Movement[] movements;
private int nowMovementIndex;
private int footPrint;
private Point location;
}