我将如何为 TicTacToe 游戏创建 HashMap

How would I create a HashMap for a TicTacToe game

我正在创建一个有 2 个棋盘的 TicTacToe 游戏,用户只能玩一个。如果用户单击网格 1 上的单元格 [2][3],将在网格 1 和网格 2 上的单元格 [2][3] 上绘制一个标记。我正在考虑使用 HashMap 为每个单元格分配索引。像 cell[2][3] 和 cells[2][3] 一样,每个都会分配给索引 9。我将如何实现这是我的代码?我什至会为我想做的事情使用哈希图吗?我不熟悉这个概念,所以我可能只是想得太多了。 注意:Cell[][] 是网格 1 的单元格,Cells[][] 是网格 2 的单元格。Cells[][] 中有随机索引,因此可以随机分配给面板。

编辑:如果我想 link cell(2)(3) 和 cells(2)(3) 我会在初始化 hashmap 时将整数更改为 Cell。然后我会做HMap。 put(cell[2][3], cells[2][3]) 对吧?

代码:

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.border.LineBorder;
import java.util.Random;
import java.util.HashMap;
public class Bull extends JFrame{
   private char currentPlayer = ' ';
   // Creates array of cells called Cell[][] cell
   private Cell[][] cell = new Cell[3][3];
   // Creates array of cells called Sale[][] cells
   private Cells[][] cells = new Cells[3][3];
   // Creates a boolean array
   private boolean t[][] = new boolean[3][3];
   // Creates index array
   private int z[] = new int[8];
   //Initializes Random
   Random rand = new Random();
   // Initializes variables which will be used to create random ints
   int f;
   int g;
   // Initializes JlblStatus
   private JLabel jlblStatus = new JLabel(" ");
   private JLabel jlblIndex = new JLabel(" ");
   // Method that builds the JFrame and JPanels
   public Bull(){
      // Do I change Integer to array?
      HashMap<Integer, Integer> HMap = new HashMap<Integer, Integer>();
      // Title of the JFrame
      JFrame frame = new JFrame("Shadow Tic Tac Toe Game");
      // Makes the JFrame full screen
      frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
      // If x button is clicked than the JFrame closes
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      // Initializes JPanel1
      JPanel panel1 = new JPanel();
      // Initializes JPanel2
      JPanel panel2 = new JPanel();

      // Adds panel1 which will hold the first TicTacToe game.
      panel1.setLayout(new GridLayout(3,3,0,0));
      for(int d = 0; d < 3; d++){
         for(int c = 0; c < 3; c++){
            panel1.add(cell[d][c] = new Cell());
            // Sets size of the cells in JPanel1
            cell[d][c].setPreferredSize(new Dimension(250,250));
         }
      }




      panel2.setLayout(new GridLayout(3,3,0,0));
      int n = 0;
      while(n < 9){
      f=rand.nextInt(3);
      g=rand.nextInt(3);
      while(t[f][g] == false){
         t[f][g] = true;
         panel2.add(cells[f][g] = new Cells());
         cells[f][g].setPreferredSize(new Dimension(250,250));
         System.out.println(f);
         System.out.println("\t" + g);
         n++;

        }
       }








      // Adds Panel1 to the JFrame
      frame.add(panel1, BorderLayout.WEST);
      // Adds Panel2 to the JFrame
      frame.add(panel2, BorderLayout.EAST);
      // Updates the status of the game here (win/lose/draw/whose turn it is
      frame.add(jlblStatus, BorderLayout.SOUTH);
      // Sets size of the message area at the bottom of the frame
      jlblStatus.setPreferredSize(new Dimension(100,100));
      // Shows the Instructions of the game
      Instructions();
      // Calls method Chose() which allows the player to chose which token they will play as
      Chose();
      frame.pack();
      // Sets it so the JFrame is visible to the user
      frame.setVisible(true);
   }


   // Method that creates the Instructions for the game. Will be shown to the user prior to the user picking his token
   public void Instructions(){
      JOptionPane.showMessageDialog(null,"INSTRUCTIONS" + "\nThis game is called a 'Shadow Tic Tac Toe Game'. In this game there will be two Tic Tac Toe game boards, though only one is playable. \nBut you can win on either board. Lets say you place your token on the center tile at cell(2,3). \nAn X will be drawn on that spot on board 1 and on a randomized spot on the second game board at cell(2,3). \nYou will be able to see the cell indexes before you click on a cell so you can form a strategy");
   }
   // Method that lets the user chose his/her token
   public void Chose(){
      int f = 2;
      // While f == 2 the loop will run
      while(f == 2){
         String input = JOptionPane.showInputDialog("CHOSE" + "\nPlease select your token. \nPress 1 for X and 2 for O.");
         // Reads in the user input. Input put into a variable called pawn
         int pawn = Integer.parseInt(input);
         // If user input 1 his/her token will be X. F will equal 3 so the loop does not run again
         if(input.equals("1")){
            currentPlayer = 'X';
            f = 3;
         // If user input 2 his/her token will be O. F will equal 3 so the loop does not run again
         }else if(input.equals("2")){
            currentPlayer = 'O';
            f = 3;
         // If user does not enter in either a 1 or 2 an error message will appear. f wil equal 2 so the loop runs again and asks the user to chose his/her token again
         }else{
            JOptionPane.showMessageDialog(null,"ERROR INVALID RESPONSE");
            f = 2;
      }
     }
   }
   public class Cells extends JPanel{
      private char tok = ' ';
      public Cells(){
         // Sets the border for the cells to the color black
         setBorder(new LineBorder(Color.black,1));
      }
      public void setTok(char d){
         tok = d;
         repaint();
      }
      public char getTok(){
         return tok;
      }
      protected void Paint(Graphics g){
         super.paint(g);

         if(tok == 'X'){
            g.drawLine(10,10,getWidth() - 10, getHeight()-10);
            g.drawLine(getWidth()-10,10,10,getHeight()-10);
         }else if (tok == 'O'){
            g.drawOval(10,10,getWidth()-20, getHeight()-20);
         }
      }
   }
    public class Cell extends JPanel{
      private char token = ' ';
      public void setToken(char c){
         token = c;
         repaint();
      }
      public char getToken(){
         return token;
      }
      public Cell(){ 
         // Sets the border for the cells to the color black
         setBorder(new LineBorder(Color.black, 1));
         addMouseListener(new MyMouseListener());
      }
       protected void paintComponent(Graphics g) {
         super.paintComponent(g);

         if (token == 'X') {
           g.drawLine(10,10, getWidth() - 10, getHeight() - 10);
           g.drawLine(getWidth() - 10,10,10, getHeight() - 10);
         }
         else if (token == 'O') {
           g.drawOval(10, 10, getWidth() - 20, getHeight() - 20);
         }
      } 
      private class MyMouseListener extends MouseAdapter{
         public void mouseClicked(MouseEvent e){
        // If cell is empty and game is not over
        if (token == ' ' && currentPlayer != ' ') {
          setToken(currentPlayer); // Set token in the cell
          for(int d = 0; d < 3; d++){
            for(int c = 0; c < 3; c++){
               if(cell[d][c].getToken() == 'X'){
                  cells[d][c].setTok('X');
               }else if(cell[d][c].getToken() == 'O'){
                  cells[d][c].setTok('O');
               }else if(cell[d][c].getToken() == ' '){
                  cells[d][c].setTok(' ');
               }
            }
          }
          //setTok(currentPlayer); 
               if(Won(currentPlayer)){
                  jlblStatus.setText("The game is over! " + currentPlayer + " won the game! Congragulations " + currentPlayer + " !");
                  currentPlayer = ' ';
               }else if(Full()){
                  jlblStatus.setText("The game is over, it ends in a draw!");
                  currentPlayer = ' ';
               }else{
                   if(currentPlayer == 'X'){
                     currentPlayer = 'O';
                   }else{
                     currentPlayer = 'X';
                   }

                  jlblStatus.setText("It is " + currentPlayer + " 's turn");  
               }

             }
         }
      }  
   }

   public boolean Full(){
      for(int d = 0; d < 3; d++)
         for(int c = 0; c < 3; c++)
            if(cell[d][c].getToken() == ' ')
               return false;
            return true;

    }

   public boolean Won(char token){
      for(int d = 0; d < 3; d++){
         if(cell[d][0].getToken() == token && cell[d][1].getToken() == token && cell[d][2].getToken() == token){
            return true;
         }
      }
      for(int c = 0; c < 3; c++){
         if(cell[0][c].getToken() == token && cell[1][c].getToken() == token && cell[2][c].getToken() == token){
            return true;
         }
       }
      if(cell[0][0].getToken() == token && cell[1][1].getToken() == token && cell[2][2].getToken() == token){
         return true;
      }
      if(cell[0][2].getToken() == token && cell[1][1].getToken() == token && cell[2][0].getToken() == token){
         return true;
      }
      return false;
   }
     public static void main(String [] args){
      new Bull();
   }
}

所以基本上你想将一个网格(玩家可以玩的)上的一个单元格映射到另一个网格(阴影网格)上的某个单元格?

您可以只使用另一个二维数组来完成此操作,该数组存储单元格在另一个网格中映射到的索引,但您需要 return 一个包含 x 和 y 坐标的点对象。但是这种方法有点烦人,难以跟踪并且有其局限性。

如果你想用一个网格中的一个 PointHashMap<Point, Point> 到另一个网格中的 Point,那么你必须覆盖 hashCode()Pointequals() 并做这样的事情:

HashMap<Point, Point> mapPointToPoint = new HashMap<>();

// (0,0) maps to shadow grid (1,2)
mapPointToPoint.put(new Point(0,0), new Point(1,2));
mapPointToPoint.put(new Point(0,1), new Point(2,1));
// ... more mappings for all the cells

// to get 
Point pointInPlayableGrid = new Point(0,0);
Point pointInShadowGrid = mapPointToPoint.get(pointInPlayableGrid);
// pointInShadowGrid == (1,2) since that's what it was mapped to

但是,如果您想拥有多个阴影网格,则需要为每个阴影网格提供从可播放网格中的点到阴影网格中的点的映射。

因此,既然您已经有了 Cell class,为什么不让每个 Cell 存储它映射到的所有单元格的 List<Cell>。这也非常灵活,因为您甚至可以将单个可播放 Cell 映射到单个阴影网格中的多个单元格,并且在可播放 Cell 悬停时,您可以浏览阴影列表 Cells 它也映射到并突出显示它们。

public class Cell extends JPanel{
    private Cell shadowCell;
    public void setCellThisMapsTo(Cell otherCell){ this.shadowCell = otherCell; }
    public Cell getCellThisMapsTo(){ return shadowCell; }
    // ... all the other stuff
}

// ... wherever you initialize the playable and shadow grid
// get a list of the shadow Cells, randomized order
Cell[][] shadowGrid; // however you init this
Cell[][] playableGrid; // however you init this

LinkedList<Cell> shadowCells = new LinkedList<>();
for(int x = 0; x < 3; x++){
    for(int y = 0; y < 3; y++){
        shadowCells.add(shadowGrid[x][y]);
    }
}
Collections.shuffle(shadowCells);

for(int x = 0; x < 3; x++){
    for(int y = 0; y < 3; y++){
        Cell playableCell = playableGrid[x][y];
        Cell shadowCell = shadowCells.removeFirst();
        playableCell.setCellThisMapsTo(shadowCell );
    }
}

// Now all the playable cells map to a random shadow cell
Cell playableCell = playableGrid[0][0];
Cell shadowCell = playableCell.getCellThisMapsTo();

阴影 Cells 不会映射到任何其他单元格,因此 shadowCell.getCellThisMapsTo() 会 return null。但是这种方法可以轻松地将可玩单元格映射到阴影单元格并跟踪它们,甚至无需使用 HashMap 也不必跟踪 Points 映射到 Points。


这是我对 Point 的定义。如果您想根据其值(而不是其对象引用)将某些内容放入哈希映射中,那么重写 hashCode()equals():

很重要
class Point {
    public final int x;
    public final int y;
    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }

    // !!! OVERRIDE hashCode() and equals() so  you can use this properly in a HashMap !!!
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 71 * hash + this.x;
        hash = 71 * hash + this.y;
        return hash;
    }

     @Override
    public int equals(Object o) {
        if (obj == null)
            return false;
        if (this == obj)
            return true;
        if (getClass() != o.getClass())
            return false;
        Point p = (Point) o;
        return this.x == p.x && this.y == p.y;
    }
}