package com.raylew.algorithm.book1;
import java.util.Arrays;
import java.util.LinkedList;
/*
在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,
任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,
任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局。
输入描述 Input Description
从文件中读入一个4*4的初始棋局,黑棋子用B表示,白棋子用W表示,空格地带用O表示。
输出描述 Output Description
用最少的步数移动到目标棋局的步数。
样例输入 Sample Input
BWBO
WBWB
BWBW
WBWO
样例输出 Sample Output
5
*/
public class 四子连棋 {
//标记已经访问的状态,判重
public static boolean[] stateArr = new boolean[43036875];
//从初始状态到某一状态的距离
public static int[] distArr = new int[43036875];
public static void main(String[] args) {
// 测试数据:初始棋局,1表示黑棋,2表示白棋,0表示空位
int[][] beginState = {{1, 2, 1, 0}, {2, 1, 2, 1}, {1, 2, 1, 2},
{2, 1, 2, 0}};
LinkedList<int[][]> state_list = new LinkedList<int[][]>();
LinkedList<int[][]> state_list2 = new LinkedList<int[][]>();
state_list.addLast(beginState);
stateArr[getStateHash(beginState)] = true;
int pre = 1;
//bfs算法开始
while (true) {
int[][] state = state_list.removeFirst();
if (success(state)) {
System.out.println(distArr[getStateHash(state)]);
for (int i = 0; i < state.length; i++) {
for (int j = 0; j < state.length; j++) {
System.out.print(state[i][j]);
}
System.out.println();
}
break;
}
//存放两个空位位置
int[][] index_0_arr = new int[2][2];
getIndex_0(state, index_0_arr);
// 第一个空位
int row_fir_0 = index_0_arr[0][0];
int col_fir_0 = index_0_arr[0][1];
//第一个空位上下左右移动最多可产生4种不同的状态
// up
if (row_fir_0 > 0 && (state[row_fir_0 - 1][col_fir_0] != 0)) {
int new_row_fir_0 = row_fir_0 - 1;
if (state[new_row_fir_0][col_fir_0] == pre) {
int[][] newState = new int[4][4];
for (int i = 0; i < 4; i++) {
newState[i] = Arrays.copyOf(state[i], 4);
}
newState[row_fir_0][col_fir_0] = pre;
newState[new_row_fir_0][col_fir_0] = 0;
int hash = getStateHash(newState);
if (stateArr[hash] == false) {
stateArr[hash] = true;
distArr[hash] = distArr[getStateHash(state)] + 1;
state_list2.addLast(newState);
}
}
}
// down
if (row_fir_0 < 3 && (state[row_fir_0 + 1][col_fir_0] != 0)) {
int new_row_fir_0 = row_fir_0 + 1;
if (state[new_row_fir_0][col_fir_0] == pre) {
int[][] newState = new int[4][4];
for (int i = 0; i < 4; i++) {
newState[i] = Arrays.copyOf(state[i], 4);
}
newState[row_fir_0][col_fir_0] = pre;
newState[new_row_fir_0][col_fir_0] = 0;
int hash = getStateHash(newState);
if (stateArr[hash] == false) {
stateArr[hash] = true;
distArr[hash] = distArr[getStateHash(state)] + 1;
state_list2.addLast(newState);
}
}
}
// left
if (col_fir_0 > 0 && (state[row_fir_0][col_fir_0 - 1] != 0)) {
int new_col_fir_0 = col_fir_0 - 1;
if (state[row_fir_0][new_col_fir_0] == pre) {
int[][] newState = new int[4][4];
for (int i = 0; i < 4; i++) {
newState[i] = Arrays.copyOf(state[i], 4);
}
newState[row_fir_0][col_fir_0] = pre;
newState[row_fir_0][new_col_fir_0] = 0;
int hash = getStateHash(newState);
if (stateArr[hash] == false) {
stateArr[hash] = true;
distArr[hash] = distArr[getStateHash(state)] + 1;
state_list2.addLast(newState);
}
}
}
// right
if (col_fir_0 < 3 && (state[row_fir_0][col_fir_0 + 1] != 0)) {
int new_col_fir_0 = col_fir_0 + 1;
if (state[row_fir_0][new_col_fir_0] == pre) {
int[][] newState = new int[4][4];
for (int i = 0; i < 4; i++) {
newState[i] = Arrays.copyOf(state[i], 4);
}
newState[row_fir_0][col_fir_0] = pre;
newState[row_fir_0][new_col_fir_0] = 0;
int hash = getStateHash(newState);
if (stateArr[hash] == false) {
stateArr[hash] = true;
distArr[hash] = distArr[getStateHash(state)] + 1;
state_list2.addLast(newState);
}
}
}
// 第二个空位
int row_sec_0 = index_0_arr[1][0];
int col_sec_0 = index_0_arr[1][1];
//第二个空位上下左右移动最多可产生4种不同的状态
// up
if (row_sec_0 > 0 && (state[row_sec_0 - 1][col_sec_0] != 0)) {
int new_row_sec_0 = row_sec_0 - 1;
if (state[new_row_sec_0][col_fir_0] == pre) {
int[][] newState = new int[4][4];
for (int i = 0; i < 4; i++) {
newState[i] = Arrays.copyOf(state[i], 4);
}
newState[row_sec_0][col_sec_0] = pre;
newState[new_row_sec_0][col_fir_0] = 0;
int hash = getStateHash(newState);
if (stateArr[hash] == false) {
stateArr[hash] = true;
distArr[hash] = distArr[getStateHash(state)] + 1;
state_list2.addLast(newState);
}
}
}
// down
if (row_sec_0 < 3 && (state[row_sec_0 + 1][col_sec_0] != 0)) {
int new_row_sec_0 = row_sec_0 + 1;
if (state[new_row_sec_0][col_sec_0] == pre) {
int[][] newState = new int[4][4];
for (int i = 0; i < 4; i++) {
newState[i] = Arrays.copyOf(state[i], 4);
}
newState[row_sec_0][col_sec_0] = pre;
newState[new_row_sec_0][col_sec_0] = 0;
int hash = getStateHash(newState);
if (stateArr[hash] == false) {
stateArr[hash] = true;
distArr[hash] = distArr[getStateHash(state)] + 1;
state_list2.addLast(newState);
}
}
}
// left
if (col_sec_0 > 0 && (state[row_sec_0][col_sec_0 - 1] != 0)) {
int new_col_sec_0 = col_sec_0 - 1;
if (state[row_sec_0][new_col_sec_0] == pre) {
int[][] newState = new int[4][4];
for (int i = 0; i < 4; i++) {
newState[i] = Arrays.copyOf(state[i], 4);
}
newState[row_sec_0][col_sec_0] = pre;
newState[row_sec_0][new_col_sec_0] = 0;
int hash = getStateHash(newState);
if (stateArr[hash] == false) {
stateArr[hash] = true;
distArr[hash] = distArr[getStateHash(state)] + 1;
state_list2.addLast(newState);
}
}
}
// right
if (col_sec_0 < 3 && (state[row_sec_0][col_sec_0 + 1] != 0)) {
int new_col_sec_0 = col_sec_0 + 1;
if (state[row_sec_0][new_col_sec_0] == pre) {
int[][] newState = new int[4][4];
for (int i = 0; i < 4; i++) {
newState[i] = Arrays.copyOf(state[i], 4);
}
newState[row_sec_0][col_sec_0] = pre;
newState[row_sec_0][new_col_sec_0] = 0;
int hash = getStateHash(newState);
if (stateArr[hash] == false) {
stateArr[hash] = true;
distArr[hash] = distArr[getStateHash(state)] + 1;
state_list2.addLast(newState);
}
}
}
// bfs的两个队列:当queue1为空时,将queue2赋值给queue1
if (state_list.size() == 0) {
state_list = state_list2;
state_list2 = new LinkedList<int[][]>();
pre = (pre == 1) ? 2 : 1;// pre=1表示下一步由黑方走
}
}
}
/**
* 得到空位位置
*
* @param state 当前状态
* @param index_0_arr 用数组存储2个空位的位置
*/
public static void getIndex_0(int[][] state, int[][] index_0_arr) {
boolean first = false;
LOOP:
for (int i = 0; i < state.length; i++) {
for (int j = 0; j < state.length; j++) {
if (state[i][j] == 0) {
if (first == false) {
first = true;
index_0_arr[0][0] = i;
index_0_arr[0][1] = j;
} else {
index_0_arr[1][0] = i;
index_0_arr[1][1] = j;
break LOOP;
}
}
}
}
}
/**
* 判断当前状态是否满足条件,即四子连棋
*
* @param state 当前状态
* @return
*/
public static boolean success(int[][] state) {
boolean ok = false;
for (int i = 0; i < 4; i++) {
if ((state[i][0] == state[i][1] && state[i][1] == state[i][2] && state[i][2] == state[i][3])
|| (state[0][i] == state[1][i]
&& state[1][i] == state[2][i] && state[2][i] == state[3][i])) {
ok = true;
break;
}
}
if (ok == false) {
if (state[0][0] == state[1][1] && state[1][1] == state[2][2]
&& state[2][2] == state[3][3]) {
ok = true;
}
}
return ok;
}
/**
* hash算法,将状态映射到数集上
*
* @param state 当前状态
* @return
*/
public static int getStateHash(int[][] state) {
int sum = 0;
int p = 15;
for (int i = 0; i < state.length; i++) {
for (int j = 0; j < state.length; j++) {
sum += (int) (state[i][j] * Math.pow(3, p));
p--;
}
}
return sum;
}
}