понедельник, 22 сентября 2025 г.

Игра Крестики-Нолики на java с графическим интерфейсом

 

 

 

Игра в Крестики-Нолики как известно уже бородатая задача для ИИ. Надо получить некоторую шустрость, но оставить игроку возможность выиграть. Я нашел прототип в инете (без поиска) и потерял ссылку, у кого увел графику:)) Перебор в общем идет на три полухода, оценка случайная в пределах разумного - каждая клетка имеет оценку как функцию от количества линий которые можно замкнуть с данного поля. Ссылка на исходник:

https://disk.yandex.ru/d/rnc8CABdtIXSUQ


/***
*  Простая игра в крестики-нолики
*  с графическим интерфейсом и выбором хода
*  с элементом случайности
*  evgeniy-korniloff@yandex.ru
***/

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

public class TicTacToeGame {
    public static void main(String args[]) {
        Gui gui = new Gui();

    }
}




class TicTacToe {
    public static int count = 0;
    public boolean test = true;
    public Gui gui;
    ////////////////////
    Random random;

    public static String[][] board = new String[3][3];
    public static XYS tbl[]=new XYS[5];

    final   int KREST=0,NIL=1,EMPTY=2,INF=1000;
    public  int xboard[][]=new int[3][3];
    public  int side=KREST;
    public int score_board[][]=new int[3][3];
    public static int score_board_max[][]={
     { 3, 2, 3},
     { 2, 4, 2},
     { 3, 2, 3}
    };
    
    public static int full_line[][]={
        {0,1,2},
        {3,4,5},
        {6,7,8},
        {0,3,6},
        {1,4,7},
        {2,5,8},
        {0,4,8},
        {6,4,2}
    };
    Boolean is_full_line(int side){
        for(int j=0;j<8;j++){
            int i;
            for(i=0;i<3;i++){
                int y=full_line[j][i]/3;
                int x=full_line[j][i]%3;
                if(xboard[y][x]!=side)
                    break;
            }
            if(i==3) return true;
        }
        return false;
    }
    int Evaluate(int c,int depth){
        if(is_full_line(c))return INF+depth;
        if(is_full_line(c^1)) return -INF - depth;
        int s[]={0,0};
        int cnt=0;
        for(int y=0;y<3;y++)
            for(int x=0;x<3;x++)
                if(xboard[y][x]!=EMPTY){
                    s[xboard[y][x]] += score_board[y][x];
                    cnt++;
                }
        return cnt==9? -1+random.nextInt(3):s[c] - s[c^1];
    }
    Boolean Draw(){
        int cnt=0;
        for(int y=0;y<3;y++)
            for(int x=0;x<3;x++)
                if(xboard[y][x]!=EMPTY){
                    cnt++;
                }
        return cnt==9? true:false;
    }
    void init_score(){
       for(int y=0;y<3;y++)
            for(int x=0;x<3;x++)
                score_board[y][x]=
                 random.nextInt(score_board_max[y][x]*3);
    }
    class XYS{
      public int x,y,score;
      void Clear(){x=-1;y=-1;score=-INF-10;}
      XYS(){Clear();}
      Boolean Empty(){return x==-1 || y==-1;}
    };
    public void call_search(){
      random = new Random(System.nanoTime());
      init_score();
      XYS z = new XYS();
      int t = search(side,3,z);
      if(z.Empty()==false){
        xboard[z.y][z.x]=side;
        if(side==KREST)
          gui.gboard[z.y][z.x].setText("X");
        else if(side==NIL)
          gui.gboard[z.y][z.x].setText("o");
        side ^= 1;
      }
    
    }
    public int search(int c,int depth,XYS z){
        z.Clear();
        XYS tmp = tbl[depth];

        int t = Evaluate(c,depth);
        if(depth<=0 || t<=-INF || t>=INF || Draw()) return t;
        for(int y=0;y<3;y++)
         for(int x=0;x<3;x++)
          if(xboard[y][x]==EMPTY)
           {
              xboard[y][x]=c;
              int e = -search(c^1,depth-1,tmp);
              if(e>z.score){
                z.score = e;
                z.x=x;
                z.y=y;
              }
              
              xboard[y][x]=EMPTY;
           }
         return z.score;
    }
    
    void new_game(){
        
        for(int y=0;y<3;y++)
            for(int x=0;x<3;x++)
            {
                xboard[y][x]=EMPTY;
            }
        side=KREST;
        init_score();        
    }
/// /////////////////////
    public TicTacToe(Gui i){
        gui=i;
        random = new Random(System.nanoTime());
        new_game();
        for(int j=0;j<5;j++)
          tbl[j]=new XYS();
        //if(random.nextInt(2)==1)
        //  call_search();
    }
    public int get_button_index_on_board(JButton button){
        for(int y=0;y<3;y++)
            for(int x=0;x<3;x++)
                if(gui.gboard[y][x]==button)
                    return y*3+x;
        return -1;
    }
    public void buttonClicked(JButton button) {
        if(side==KREST) {
          int i = get_button_index_on_board(button);
          if(i!=-1) {
             int y = i/3;
             int x = i%3;
             if(xboard[y][x]==EMPTY){
                xboard[y][x]=KREST;
                side=NIL;
                button.setText("X");
             }  
          }
        }else if(side==NIL){
            int i = get_button_index_on_board(button);
            if(i!=-1) {
                int y = i/3;
                int x = i%3;
                if(xboard[y][x]==EMPTY){
                
                    xboard[y][x]=NIL;
                    side=KREST;
                    button.setText("O");
                }
            }
        }
        call_search();

        /**
        if(test) {
            if(button.getText().equals("")) {
                count++;
                if(count % 2 == 1) {
                    button.setText("X");
                }
                if(count % 2 == 0) {
                    button.setText("O");
                }
            }
        }
         **/
    }

    public void gameRules(JButton button) {
       if(is_full_line(KREST) ||
           is_full_line(NIL)){
            
          JOptionPane.showMessageDialog(null, " won.");
          
        }else if(Draw()){
          JOptionPane.showMessageDialog(null, " draw.");            
            
        }
          
        /***
        if(test) {
     //   if(false){

            //"X" or "O"?
            String string = button.getText();

            //Gives coordinates of the button
            int x = Character.getNumericValue(button.getName().charAt(0));
            int y = Character.getNumericValue(button.getName().charAt(1));
            board[x][y] = string;

            if(board[0][0] != null && board[0][0].equals(board[1][1]) && board[1][1].equals(board[2][2])) {
                JOptionPane.showMessageDialog(null,string + " won.");
                test = false;
            }

            else if(board[0][2] != null && board[0][2].equals(board[1][1]) && board[1][1].equals(board[2][0])) {
                JOptionPane.showMessageDialog(null,string + " won.");
                test = false;
            }
            else if(count == 9) {
                JOptionPane.showMessageDialog(null, "draw.");
                test = false;
            }
            else {
                for (int i = 0; i < 3; i++) {
                    if (board[i][0] != null && board[i][0].equals(board[i][1]) && board[i][0].equals(board[i][2])) {
                        JOptionPane.showMessageDialog(null, string + " won.");
                        test = false;
                        break;
                    }
                    if (board[0][i] != null && board[0][i].equals(board[1][i]) && board[0][i].equals(board[2][i])) {
                        JOptionPane.showMessageDialog(null, string + " won.");
                        test = false;
                        break;
                    }
                }
            }
            
        }
        */
    }
}



class Gui {
    public         JButton[][] gboard = new JButton[3][3];

    public Gui() {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        TicTacToe ticTacToe = new TicTacToe(this);
        panel.setLayout(new java.awt.GridLayout(3, 3));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        for (int i = 0; i < 3; i++){
            for(int j = 0; j < 3; j++) {
                final JButton button = new JButton();
                gboard [j][i]=button;
                String string = i +  "" + j;
                button.setText("");
                button.setName(string);
                button.addActionListener(
                        new ActionListener() {
                            public void actionPerformed(ActionEvent e) {
                                ticTacToe.buttonClicked(button);
                                ticTacToe.gameRules(button);
                            }
                        }

                );
                button.setFont(new Font("Arial", Font.PLAIN, 40));
                button.setBorder(BorderFactory.createLineBorder(Color.BLACK));
                panel.add(button);
            }

        }

        frame.add(panel);
        frame.setSize(400,400);
        frame.setVisible(true);




    }
}

Комментариев нет:

Отправить комментарий