【java】五子棋人机对弈

(简直不忍直视。。。。所有的方法都在同一个类里面,承认我自己确实还是个java小白/(ㄒoㄒ)/~~,代码真的又臭又长。。。。)

实现人机对弈主要是依靠计算棋盘各点的落子得分:

(1)借助上次的双人对弈,我们将k用于记录棋盘上每个点 ↓、→、↙、↘构成连续棋子的个数,m1[a][a]存储每点的k值,m2[a][a]存储每点k值最大的那个方向,scanner()返回一个int类型的数组 { k值最大的坐标 I、J、方向、是否连成5子以及相应坐标的k值 } ;

(2)每次轮到计算机落子时,需要先scanner()一下,查看玩家哪个点,哪个方向连成的棋子最多,然后加以堵截,过程中发现会在同一个地方重复落子,比如:

                                              【java】五子棋人机对弈_第1张图片  

图1中A右下或向右,均为2,但是都已经落子“#”,此时,需要寻找计算机自己的k最大值。

【java】五子棋人机对弈_第2张图片   
(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();
    }
}

结果:

【java】五子棋人机对弈_第3张图片
【java】五子棋人机对弈_第4张图片

你可能感兴趣的:(java)