旋转填数

前两天想起自己大二曾经写过的旋转填数。就是向一个矩阵中填充数字,形成螺旋状,比如5阶的:

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;
}

转载于:https://my.oschina.net/Jeky/blog/28757

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值