主题:[讨论]一个马跳棋盘的java实现,是否可以更加面向对象一些?
/**
*
*/
package algorithm;
/**
*
*/
public class ChessHorse {
/**
* use buffer printer instead of System.out can enhance IO performance
*
*/
private class BufferPrinter {
private static final int BUFFER_SIZE = 10240;
private StringBuffer sb;
public BufferPrinter() {
sb = new StringBuffer();
}
public void close() {
System.out.print(sb.toString());
sb = null;
}
public void print(String s) {
sb.append(s);
if (sb.length() > BUFFER_SIZE) {
System.out.print(sb.toString());
sb = new StringBuffer();
}
}
public void println() {
print("\n");
}
public void println(String s) {
print(s + "\n");
}
}
/**
* a simple stack class to store track information of the horse
* it can print itself using bufferprinter
*
*/
private class Track {
private int p = -1;
private BufferPrinter printer;
private int[][] track = new int[boardLength*boardHeight][2];
public Track() {
init();
}
public void init() {
// init track
for (int i = 0; i < boardLength*boardHeight; i ++) {
for (int j = 0; j < 2; j ++) {
track[i][j] = -1;
}
}
// init pointer
p = -1;
}
public boolean isFull() {
return p == boardLength*boardHeight - 1;
}
public void pop() {
track[p][0] = -1;
track[p][1] = -1;
p --;
}
public void print() {
if (printer == null) {
printer = new BufferPrinter();
}
int[][] sequence = new int[boardLength][boardHeight];
for (int i = 0; i < boardLength*boardHeight; i ++) {
sequence[track[i][0]][track[i][1]] = i;
}
printer.println("------------------------------------------------------------------");
for (int i = 0; i < boardLength; i ++) {
for (int j = 0; j < boardHeight; j ++) {
printer.print(sequence[i][j] + "\t");
}
printer.println();
}
}
public void push(int x, int y) {
p ++;
track[p][0] = x;
track[p][1] = y;
}
public void setBufferPrinter(BufferPrinter printer) {
this.printer = printer;
}
public int size() {
return p + 1;
}
}
/**
* the array to store adjacent situation
* when no track is on the 8*8 chess board, the situation like this
* 2 3 4 4 4 4 3 2
* 3 4 6 6 6 6 4 3
* 4 6 8 8 8 8 6 4
* 4 6 8 8 8 8 6 4
* 4 6 8 8 8 8 6 4
* 4 6 8 8 8 8 6 4
* 3 4 6 6 6 6 4 3
* 2 3 4 4 4 4 3 2
*
* for example
* there are two point{(1, 2), (2, 1)} [not visited] that can jump to (0, 0)
*/
private int[][] adjacency = null;
/**
* the height of the chessboard, default value is 8
*/
private int boardHeight = 8;
/**
* the length of the chessboard, default value is 8
*/
private int boardLength = 8;
/**
* constant offset array of x-axis
*/
private final int[] offsetx = {-2, -1, 1, 2, 2, 1, -1, -2};
/**
* constant offset array of y-axis
*/
private final int[] offsety = {-1, -2, -2, -1, 1, 2, 2, 1};
/**
* the buffer printer can enhance print performance
*/
private BufferPrinter printer = null;
/**
* the track is a stack object which keeps track information of the horse.
*/
private Track track = null;
/**
* the bool 2D array to store visit situation
*/
private boolean[][] visited = null;
/**
* current position in x-axis
*/
private int x = 0;
/**
* current position in y-axis
*/
private int y = 0;
public ChessHorse() {
printer = new BufferPrinter();
track = new Track();
track.setBufferPrinter(printer);
}
/**
* generate a best visit path on greedy perspective
* @return int[] an array of int ,is index of offsetx and offsety.
*/
private int[] getGreedyPath() {
int[] index = {0, 1, 2, 3, 4, 5, 6, 7};
int[] indexAdj = new int[8];
for (int i = 0; i < 8; i ++) {
if (isLegalJump(x, y, offsetx[i], offsety[i])) {
indexAdj[i] = adjacency[x + offsetx[i]][y + offsety[i]];
} else {
indexAdj[i] = -1;
}
}
// sort indexAdj couple index with bubble
for (int i = 0; i < 8; i ++) {
for (int j = i + 1; j < 8; j ++) {
if (indexAdj[i] > indexAdj[j]) {
int temp = indexAdj[j];
indexAdj[j] = indexAdj[i];
indexAdj[i] = temp;
temp = index[j];
index[j] = index[i];
index[i] = temp;
}
}
}
// generate result array
int si;
for (si = 0; si < 8 && indexAdj[si] == -1; si ++);
int[] result = new int[8 - si];
for (int i = 0; i < 8 - si; i ++) {
result[i] = index[si + i];
}
return result;
}
/**
* init the game
* @param startx start position of x
* @param starty start position of y
*/
private void init(int startx, int starty) {
visited = new boolean[boardLength][boardHeight];
adjacency = new int[boardLength][boardHeight];
track.init();
// init visited and adjacency
for (int i = 0; i < boardLength; i ++) {
for (int j = 0; j < boardHeight; j ++) {
visited[i][j] = false;
adjacency[i][j] = 0;
for (int k = 0; k < 8; k ++) {
if (isLegalJump(i, j, offsetx[k], offsety[k])) {
adjacency[i][j] ++;
}
}
}
}
// start point (startx,starty)
x = startx;
y = starty;
// start point is initially visited
visited[x][y] = true;
// decrease adjacency by 1
updateAdjacency(-1);
track.push(x, y);
}
/**
* test is it able to jump from (x, y) to (x + offsetx, y + offsety)
* @param x
* @param y
* @param offsetx
* @param offsety
* @return
*/
private boolean isLegalJump(int x, int y, int offsetx, int offsety) {
int newx = x + offsetx;
int newy = y + offsety;
return (newx >= 0 && newx < boardLength)
&& (newy >= 0 && newy < boardHeight)
&& !visited[newx][newy];
}
/**
* recursive jump
* @param offx
* @param offy
*/
private void jump(int offx, int offy) {
x = x + offx;
y = y + offy;
// visited
visited[x][y] = true;
// decrease adjacency by 1
updateAdjacency(-1);
// register track
track.push(x, y);
// all is visited
if (track.isFull()) {
track.print();
return;
}
// best path
int[] path = getGreedyPath();
for (int i = 0; i < path.length; i ++) {
jump(offsetx[path[i]], offsety[path[i]]);
reverseJump(offsetx[path[i]], offsety[path[i]]);
}
}
/**
* reverse the jump
* @param offsetx
* @param offsety
*/
private void reverseJump(int offsetx, int offsety) {
// restore board status
visited[x][y] = false;
// increase adjcency by 1
updateAdjacency(1);
track.pop();
// restore position
x = x - offsetx;
y = y - offsety;
}
/**
* set the height of chess board
* @param boardHeight
*/
public void setBoardHeight(int boardHeight) {
this.boardHeight = boardHeight;
}
/**
* set the length of chess board
* @param boardLength
*/
public void setBoardLength(int boardLength) {
this.boardLength = boardLength;
}
/**
* start game
*
*/
public void start() {
printer.println("program start...");
// try all possible start point
for (int i = 0; i < boardLength; i ++) {
for (int j = 0; j < boardHeight; j ++) {
printer.println("start point (" + i + ", " + j + ")");
init(i, j);
int[] path = getGreedyPath();
for (int k = 0; k < 8; k ++) {
jump(offsetx[path[k]], offsety[path[k]]);
reverseJump(offsetx[path[k]], offsety[path[k]]);
}
printer.println();
}
}
printer.println("program stop...");
printer.close();
}
/**
* update the adjacency information stores in the array
* @param delta the value to change
*/
private void updateAdjacency(int delta) {
for (int i = 0; i < 8; i ++) {
int newx = x + offsetx[i];
int newy = y + offsety[i];
if (newx >= 0 && newx < boardLength
&& newy >= 0 && newy < boardHeight) {
adjacency[newx][newy] += delta;
}
}
}
public static void main(String[] args) {
ChessHorse ch = new ChessHorse();
ch.setBoardLength(8);
ch.setBoardHeight(8);
ch.start();
}
}
*
*/
package algorithm;
/**
*
*/
public class ChessHorse {
/**
* use buffer printer instead of System.out can enhance IO performance
*
*/
private class BufferPrinter {
private static final int BUFFER_SIZE = 10240;
private StringBuffer sb;
public BufferPrinter() {
sb = new StringBuffer();
}
public void close() {
System.out.print(sb.toString());
sb = null;
}
public void print(String s) {
sb.append(s);
if (sb.length() > BUFFER_SIZE) {
System.out.print(sb.toString());
sb = new StringBuffer();
}
}
public void println() {
print("\n");
}
public void println(String s) {
print(s + "\n");
}
}
/**
* a simple stack class to store track information of the horse
* it can print itself using bufferprinter
*
*/
private class Track {
private int p = -1;
private BufferPrinter printer;
private int[][] track = new int[boardLength*boardHeight][2];
public Track() {
init();
}
public void init() {
// init track
for (int i = 0; i < boardLength*boardHeight; i ++) {
for (int j = 0; j < 2; j ++) {
track[i][j] = -1;
}
}
// init pointer
p = -1;
}
public boolean isFull() {
return p == boardLength*boardHeight - 1;
}
public void pop() {
track[p][0] = -1;
track[p][1] = -1;
p --;
}
public void print() {
if (printer == null) {
printer = new BufferPrinter();
}
int[][] sequence = new int[boardLength][boardHeight];
for (int i = 0; i < boardLength*boardHeight; i ++) {
sequence[track[i][0]][track[i][1]] = i;
}
printer.println("------------------------------------------------------------------");
for (int i = 0; i < boardLength; i ++) {
for (int j = 0; j < boardHeight; j ++) {
printer.print(sequence[i][j] + "\t");
}
printer.println();
}
}
public void push(int x, int y) {
p ++;
track[p][0] = x;
track[p][1] = y;
}
public void setBufferPrinter(BufferPrinter printer) {
this.printer = printer;
}
public int size() {
return p + 1;
}
}
/**
* the array to store adjacent situation
* when no track is on the 8*8 chess board, the situation like this
* 2 3 4 4 4 4 3 2
* 3 4 6 6 6 6 4 3
* 4 6 8 8 8 8 6 4
* 4 6 8 8 8 8 6 4
* 4 6 8 8 8 8 6 4
* 4 6 8 8 8 8 6 4
* 3 4 6 6 6 6 4 3
* 2 3 4 4 4 4 3 2
*
* for example
* there are two point{(1, 2), (2, 1)} [not visited] that can jump to (0, 0)
*/
private int[][] adjacency = null;
/**
* the height of the chessboard, default value is 8
*/
private int boardHeight = 8;
/**
* the length of the chessboard, default value is 8
*/
private int boardLength = 8;
/**
* constant offset array of x-axis
*/
private final int[] offsetx = {-2, -1, 1, 2, 2, 1, -1, -2};
/**
* constant offset array of y-axis
*/
private final int[] offsety = {-1, -2, -2, -1, 1, 2, 2, 1};
/**
* the buffer printer can enhance print performance
*/
private BufferPrinter printer = null;
/**
* the track is a stack object which keeps track information of the horse.
*/
private Track track = null;
/**
* the bool 2D array to store visit situation
*/
private boolean[][] visited = null;
/**
* current position in x-axis
*/
private int x = 0;
/**
* current position in y-axis
*/
private int y = 0;
public ChessHorse() {
printer = new BufferPrinter();
track = new Track();
track.setBufferPrinter(printer);
}
/**
* generate a best visit path on greedy perspective
* @return int[] an array of int ,is index of offsetx and offsety.
*/
private int[] getGreedyPath() {
int[] index = {0, 1, 2, 3, 4, 5, 6, 7};
int[] indexAdj = new int[8];
for (int i = 0; i < 8; i ++) {
if (isLegalJump(x, y, offsetx[i], offsety[i])) {
indexAdj[i] = adjacency[x + offsetx[i]][y + offsety[i]];
} else {
indexAdj[i] = -1;
}
}
// sort indexAdj couple index with bubble
for (int i = 0; i < 8; i ++) {
for (int j = i + 1; j < 8; j ++) {
if (indexAdj[i] > indexAdj[j]) {
int temp = indexAdj[j];
indexAdj[j] = indexAdj[i];
indexAdj[i] = temp;
temp = index[j];
index[j] = index[i];
index[i] = temp;
}
}
}
// generate result array
int si;
for (si = 0; si < 8 && indexAdj[si] == -1; si ++);
int[] result = new int[8 - si];
for (int i = 0; i < 8 - si; i ++) {
result[i] = index[si + i];
}
return result;
}
/**
* init the game
* @param startx start position of x
* @param starty start position of y
*/
private void init(int startx, int starty) {
visited = new boolean[boardLength][boardHeight];
adjacency = new int[boardLength][boardHeight];
track.init();
// init visited and adjacency
for (int i = 0; i < boardLength; i ++) {
for (int j = 0; j < boardHeight; j ++) {
visited[i][j] = false;
adjacency[i][j] = 0;
for (int k = 0; k < 8; k ++) {
if (isLegalJump(i, j, offsetx[k], offsety[k])) {
adjacency[i][j] ++;
}
}
}
}
// start point (startx,starty)
x = startx;
y = starty;
// start point is initially visited
visited[x][y] = true;
// decrease adjacency by 1
updateAdjacency(-1);
track.push(x, y);
}
/**
* test is it able to jump from (x, y) to (x + offsetx, y + offsety)
* @param x
* @param y
* @param offsetx
* @param offsety
* @return
*/
private boolean isLegalJump(int x, int y, int offsetx, int offsety) {
int newx = x + offsetx;
int newy = y + offsety;
return (newx >= 0 && newx < boardLength)
&& (newy >= 0 && newy < boardHeight)
&& !visited[newx][newy];
}
/**
* recursive jump
* @param offx
* @param offy
*/
private void jump(int offx, int offy) {
x = x + offx;
y = y + offy;
// visited
visited[x][y] = true;
// decrease adjacency by 1
updateAdjacency(-1);
// register track
track.push(x, y);
// all is visited
if (track.isFull()) {
track.print();
return;
}
// best path
int[] path = getGreedyPath();
for (int i = 0; i < path.length; i ++) {
jump(offsetx[path[i]], offsety[path[i]]);
reverseJump(offsetx[path[i]], offsety[path[i]]);
}
}
/**
* reverse the jump
* @param offsetx
* @param offsety
*/
private void reverseJump(int offsetx, int offsety) {
// restore board status
visited[x][y] = false;
// increase adjcency by 1
updateAdjacency(1);
track.pop();
// restore position
x = x - offsetx;
y = y - offsety;
}
/**
* set the height of chess board
* @param boardHeight
*/
public void setBoardHeight(int boardHeight) {
this.boardHeight = boardHeight;
}
/**
* set the length of chess board
* @param boardLength
*/
public void setBoardLength(int boardLength) {
this.boardLength = boardLength;
}
/**
* start game
*
*/
public void start() {
printer.println("program start...");
// try all possible start point
for (int i = 0; i < boardLength; i ++) {
for (int j = 0; j < boardHeight; j ++) {
printer.println("start point (" + i + ", " + j + ")");
init(i, j);
int[] path = getGreedyPath();
for (int k = 0; k < 8; k ++) {
jump(offsetx[path[k]], offsety[path[k]]);
reverseJump(offsetx[path[k]], offsety[path[k]]);
}
printer.println();
}
}
printer.println("program stop...");
printer.close();
}
/**
* update the adjacency information stores in the array
* @param delta the value to change
*/
private void updateAdjacency(int delta) {
for (int i = 0; i < 8; i ++) {
int newx = x + offsetx[i];
int newy = y + offsety[i];
if (newx >= 0 && newx < boardLength
&& newy >= 0 && newy < boardHeight) {
adjacency[newx][newy] += delta;
}
}
}
public static void main(String[] args) {
ChessHorse ch = new ChessHorse();
ch.setBoardLength(8);
ch.setBoardHeight(8);
ch.start();
}
}