(简直不忍直视。。。。所有的方法都在同一个类里面,承认我自己确实还是个java小白/(ㄒoㄒ)/~~,代码真的又臭又长。。。。)
实现人机对弈主要是依靠计算棋盘各点的落子得分:
(1)借助上次的双人对弈,我们将k用于记录棋盘上每个点 ↓、→、↙、↘构成连续棋子的个数,m1[a][a]存储每点的k值,m2[a][a]存储每点k值最大的那个方向,scanner()返回一个int类型的数组 { k值最大的坐标 I、J、方向、是否连成5子以及相应坐标的k值 } ;
(2)每次轮到计算机落子时,需要先scanner()一下,查看玩家哪个点,哪个方向连成的棋子最多,然后加以堵截,过程中发现会在同一个地方重复落子,比如:
图1中A右下或向右,均为2,但是都已经落子“#”,此时,需要寻找计算机自己的k最大值。
(3)寻找过程中会出现数组越界情况(图2),这里需要注意补充到达边界了怎么办,另外,界限是 [0,a)。
又臭又长的代码。。。。
package com.vaniot;
import java.util.Scanner;
public class WuZiQi {
public static char[][] Qipan;
public static int a;
public int[][] Qipan1=new int[a][a];
public int[][] Qipan2=new int[a][a];
public int[][] Qipan3=new int[a][a];
public int[][] Qipan4=new int[a][a];
public int max(int x,int y,int z,int w){
if(x>y){
if(x>z) return x>w?x:w;
else return z>w?z:w;
}
else{
if(y>z) return y>w?y:w;
else return z>w?z:w;
}
}
//先画一个棋盘:a*a
public void kongQiPan(){
System.out.println("请输入你的棋盘大小:");
Scanner console=new Scanner(System.in);
a=console.nextInt();
Qipan=new char[a][a];
for(int i=0;ifor(int j=0;j'+';
System.out.print(Qipan[i][j]);
}
System.out.println();
}
}
public void computerPlayer(int ij,int jj){
////A的k值最大处都已经落子“#”,此时,寻找计算机自己的k最大值
int[] flag={0,0,0,0};
WuZiQi wzq=new WuZiQi();
flag=wzq.scanner(ij,jj);//计算机上一步落子处
int I=flag[0];
int J=flag[1];
if(flag[2]==1){
if(J+flag[4]//向右没有到边边上
Qipan[I][J+flag[4]]='#';
ij=I;jj=J+flag[4];
}
else if(J-1>=0){//向左没有到边边上
if(Qipan[I][J-1]=='+'){
Qipan[I][J-1]='#';
ij=I;jj=J-1;
}
else{//向左被占用了,就近随机落子
for(int i=0;ifor(int j=0;jif(Qipan[I+i][J+j]=='+'){
Qipan[I+i][J+j]='#';
j=a-J;i=a-I;//跳出循环
}
}
}
}
}
}
else if(flag[2]==2){
if(I+flag[4]//向下没有到边边上
Qipan[I+flag[4]][J]='#';
ij=I+flag[4];jj=J;
}
else if(I-1>=0){//向上没有到边边上
if(Qipan[I-1][J]=='+'){
Qipan[I-1][J]='#';
ij=I-1;jj=J;
}
else{//向上被占用了,就近随机落子
for(int i=0;ifor(int j=0;jif(Qipan[I+i][J+j]=='+'){
Qipan[I+i][J+j]='#';
j=a-J;i=a-I;//跳出循环
}
}
}
}
}
}
else if(flag[2]==3){
if((I+flag[4]4]>=0)){//向左下没有到边边上
Qipan[I+flag[4]][J-flag[4]]='#';
ij=I+flag[4];jj=J-flag[4];
}
else if((I-1>=0)&&(J+1//向右上没有到边边上
if(Qipan[I-1][J+1]=='+'){
Qipan[I-1][J+1]='#';
ij=I-1;jj=J+1;
}
else{//向右上被占用了,就近随机落子
for(int i=0;ifor(int j=0;jif(Qipan[I+i][J+j]=='+'){
Qipan[I+i][J+j]='#';
j=a-J;i=a-I;//跳出循环
}
}
}
}
}
}
else if(flag[2]==4){
if((I+flag[4]4]//向右下没有到边边上
Qipan[I+flag[4]][J+flag[4]]='#';
ij=I+flag[4];jj=J+flag[4];
}
else if((I-1>=0)&&(J-1>=0)){//向左上没有到边边上
if(Qipan[I-1][J-1]=='+'){
Qipan[I-1][J-1]='#';
ij=I-1;jj=J-1;
}
else{//向左上被占用了,就近随机落子
for(int i=0;ifor(int j=0;jif(Qipan[I+i][J+j]=='+'){
Qipan[I+i][J+j]='#';
j=a-J;i=a-I;//跳出循环
}
}
}
}
}
}
}
public void playGame(){
System.out.println("欢迎两位玩家!请依次落子(您需要输入您落子的坐标,如 2 3):");
int flagA=0,flagB=0;
int Aii=0,Ajj=0;
int ij=0,jj=0;
int[] flag={0,0,0,0};
WuZiQi wzq=new WuZiQi();
while(flag[3]==0){
//还没人胜出时,依次落子
while(flagA==0){
System.out.print("A:");
Scanner console1=new Scanner(System.in);
int Ai=console1.nextInt();
int Aj=console1.nextInt();
Aii=Ai;Ajj=Aj;
if((Ai>=a)||(Aj>=a)){
System.out.println("超出界限,请重新输入!");
}
else if(Qipan[Ai][Aj]=='+'){
Qipan[Ai][Aj]='★';
flagA=1;
for(int i=0;ifor(int j=0;jout.print(Qipan[i][j]);
}
System.out.println();
}
flag=wzq.scanner(Ai,Aj);
if(flag[3]==1){
System.out.println("A胜出!");
break;
}
else{
flagB=0;//由B落子
}
}
else{
System.out.println("该位置上已有棋子,请重新输入!");
}
}
while(flagB==0){
System.out.println("机:");
flag=wzq.scanner(Aii,Ajj);
int I=flag[0];
int J=flag[1];
if(flag[2]==1){// →
if(J+flag[4]//没有到边边上
if(Qipan[I][J+flag[4]]=='+'){
Qipan[I][J+flag[4]]='#';
ij=I;jj=J+flag[4];//记录计算机这一步落在哪里
}
else{//该位置已被占用
wzq.computerPlayer(ij, jj);
}
}
else if(J-1>=0){//向右到边界了,再向左看是否有位置
if(Qipan[I][J-1]=='+'){//向左没有被占用
Qipan[I][J-1]='#';
ij=I;jj=J-1;
}
else{//A向左被占用,再搜寻自己的‘#’
wzq.computerPlayer(ij, jj);
}
}
else{//向左也到边界或者向左被占用,搜寻自己的‘#’或就近任意落子
wzq.computerPlayer(ij, jj);
}
}
else if(flag[2]==2){// ↓
if(I+flag[4]//向下没有到边边上
if(Qipan[I+flag[4]][J]=='+'){
Qipan[I+flag[4]][J]='#';
ij=I+flag[4];jj=J;//记录计算机这一步落在哪里
}
else{//该位置已被占用
wzq.computerPlayer(ij, jj);
}
}
else if(I-1>=0){//向下到边界了,再向上看是否有位置
if(Qipan[I-1][J]=='+'){//向左没有被占用
Qipan[I-1][J]='#';
ij=I-1;jj=J;
}
else{//A向上被占用,再搜寻自己的‘#’
wzq.computerPlayer(ij, jj);
}
}
else{//向上也到边界或者向上被占用,搜寻自己的‘#’或就近任意落子
wzq.computerPlayer(ij, jj);
}
}
else if(flag[2]==3){// ↙
if((I+flag[4]4]>=0)){//向左下没有到边边上
if(Qipan[I+flag[4]][J-flag[4]]=='+'){
Qipan[I+flag[4]][J-flag[4]]='#';
ij=I+flag[4];jj=J-flag[4];//记录计算机这一步落在哪里
}
else{//该位置已被占用
wzq.computerPlayer(ij, jj);
}
}
else if((I-1>=0)&&(J+1//向左下到边界了,再向右上看是否有位置
if(Qipan[I-1][J+1]=='+'){//向左没有被占用
Qipan[I-1][J+1]='#';
ij=I-1;jj=J+1;
}
else{//A向右上被占用,再搜寻自己的‘#’
wzq.computerPlayer(ij, jj);
}
}
else{//向右上也到边界或者向右上被占用,搜寻自己的‘#’或就近任意落子
wzq.computerPlayer(ij, jj);
}
}
else if(flag[2]==4){// ↘
if((I+flag[4]4]>=0)){//向右下没有到边边上
if(Qipan[I+flag[4]][J+flag[4]]=='+'){
Qipan[I+flag[4]][J+flag[4]]='#';
ij=I+flag[4];jj=J+flag[4];//记录计算机这一步落在哪里
}
else{//该位置已被占用
wzq.computerPlayer(ij, jj);
}
}
else if((I-1>=0)&&(J-1>=0)){//向右下到边界了,再向左上看是否有位置
if(Qipan[I-1][J-1]=='+'){//向左上没有被占用
Qipan[I-1][J-1]='#';
ij=I-1;jj=J-1;
}
else{//A向右上被占用,再搜寻自己的‘#’
wzq.computerPlayer(ij, jj);
}
}
else{//向右上也到边界或者向右上被占用,搜寻自己的‘#’或就近任意落子
wzq.computerPlayer(ij, jj);
}
}
flagB=1;
for(int i=0;ifor(int j=0;jout.print(Qipan[i][j]);
}
System.out.println();
}
flag=wzq.scanner(ij,jj);//重新计算棋盘布局
if(flag[3]==1){
System.out.println("计算机胜出!");
break;
}
else{
flagA=0;//由A落子
}
}
}
}
public int[] scanner(int x,int y){
//每落一子,扫描全盘,看是否有连成功的
int[] m=new int[5];//返回k值最大的坐标、方向以及是否连成5子、相应坐标的k值
//从(0,0)开始,先向右扫描
int flag0=0;
for(int i=0;ifor(int j=0;j//不越界的情况下作比较
int k=1;
int k0=0;
while(k0==0){//k=4时,成功
if(j+kif((Qipan[i][j]==Qipan[i][j+k])&&(Qipan[i][j]!='+')){
k++;
}
else k0=1;
}
else break;
}
if(k==5){
flag0=1;//成功左右连成5子
}
Qipan1[i][j]=k;
}
}
//向下扫描
for(int j=0;jfor(int i=0;iint k=1;
int k0=0;
while(k0==0){//k=4时,成功
if(i+kif((Qipan[i][j]==Qipan[i+k][j])&&(Qipan[i][j]!='+')){
k++;
}
else k0=1;
}
else break;
}
if(k==5){
flag0=1;//成功上下连成5子
}
Qipan2[i][j]=k;
}
}
//右上&左下方向
for(int i=0;ifor(int j=0;j//j可以直接从4开始,4之前的这个方向连不成5子
int k=1;
int k0=0;
while(k0==0){//k=4时,成功
if((i+k=0)){
if((Qipan[i][j]==Qipan[i+k][j-k])&&(Qipan[i][j]!='+')){
k++;
}
else k0=1;
}
else break;
}
if(k==5){
flag0=1;//成功右上&左下连成5子
}
Qipan3[i][j]=k;
}
}
//左上&右下方向
for(int i=0;ifor(int j=0;j//j到a-4,a-4之后的这个方向连不成5子
int k=1;
int k0=0;
while(k0==0){//k=4时,成功
if((i+kif((Qipan[i][j]==Qipan[i+k][j+k])&&(Qipan[i][j]!='+')){
k++;
}
else k0=1;
}
else break;
}
if(k==5){
flag0=1;//成功右上&左下连成5子
}
Qipan4[i][j]=k;
}
}
int[][] m1=new int[a][a];//存储每点的k值
int[][] m2=new int[a][a];//存储每点k值最大的那个方向
for(int i=0;ifor(int j=0;j//同一个点,四个方向k值最大的那个方向
//m2记录方向
m1[i][j]=max(Qipan1[i][j],Qipan2[i][j],Qipan3[i][j],Qipan4[i][j]);
if(m1[i][j]==Qipan1[i][j]){
m2[i][j]=1;// →
}
else if(m1[i][j]==Qipan2[i][j]){
m2[i][j]=2;// ↓
}
else if(m1[i][j]==Qipan3[i][j]){
m2[i][j]=3;// ↙
}
else{
m2[i][j]=4;// ↘
}
}
}
//整个棋盘上哪个点的k值最大
int m3=0;
int I=0,J=0;
for(int i=0;ifor(int j=0;jif(m1[i][j]>m3){
m3=m1[i][j];
I=i;J=j;
}
else if(m1[i][j]==m3){//如果两个k相等,取离落子近的那个点
int dd1=(I-x)*(I-x)+(J-y)*(J-y);
int dd2=(i-x)*(i-x)+(j-y)*(j-y);
if(dd1>dd2){
m3=m1[i][j];
I=i;J=j;
}
}
}
}
m[0]=I;m[1]=J;
m[2]=m2[I][J];
m[3]=flag0;
m[4]=m3;
return m;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
WuZiQi qp=new WuZiQi();
qp.kongQiPan();
qp.playGame();
}
}
结果: