2015-04-04 41 views
0

好吧,所以我一直在關注在Java中的Connect4本教程,我試圖修改它,以適應我已經有的東西,適合libgdx。實施後,我有一些奇怪的問題。Connect4在Libgdx

問題1:在我第一步之後,計算機用他的芯片填滿了整個底部行,然後進行第一步。

問題2:計算機沒有顯示任何A.I.並從第一列和第一列開始,並在那裏放置一個芯片。電腦將繼續遵循這種模式。

問題3:如果我贏得了比賽,但是當計算機贏了時,我的獲獎檢查員不再意識到。當我第一次設計遊戲時,我開始讓計算機隨機放置芯片(用於測試),而我的獲獎檢查人員則爲計算機和我自己工作。

我跟着這篇文章是在這裏:Connect4 in Java

這裏是我的代碼。

ConnectFour.java

package com.comp452.tme31; 

import com.badlogic.gdx.ApplicationAdapter; 
import com.badlogic.gdx.Gdx; 
import com.badlogic.gdx.Input; 
import com.badlogic.gdx.InputProcessor; 
import com.badlogic.gdx.graphics.Color; 
import com.badlogic.gdx.graphics.GL20; 
import com.badlogic.gdx.graphics.Texture; 
import com.badlogic.gdx.graphics.g2d.BitmapFont; 
import com.badlogic.gdx.graphics.g2d.SpriteBatch; 

public class ConnectFour extends ApplicationAdapter implements InputProcessor { 

    // Create final ints for number of columns and rows in game. 
    protected final static int COLUMNS = 7; 
    protected final static int ROWS = 6; 
    protected final static int TILESIZE = 64; 

    // Create boolean to determine if player can take a turn. 
    protected boolean playersTurn = true; 

    // Create boolean for gameover. 
    protected boolean gameOver = false; 

    // Create boolean for winners. 
    private boolean winner = false; 

    // Sprite batch for texture drawing. 
    SpriteBatch batch; 
    // Create textures to represent board and player pieces. 
    Texture drawingTile, empty, player, computer; 

    // Create 2D array to hold game board. 
    private final static int[][] gameBoard = new int[COLUMNS][ROWS]; 

    public static int[][] getGameBoard() { 
     return gameBoard; 
    } 

    // Create variables to display status message. 
    BitmapFont mainStatusDisplay; 
    public static String mainStatusString; 
    public static String winningString; 

    // Create and set max depth for tree search 
    private final int MAX_DEPTH = 4; 

    // Create win, loss and nothing for zero sum game. 
    private final float WIN = 1f; 
    private final float LOSE = -1f; 
    private final float TIE = 0f; 

    @Override 
    public void create() { 
     batch = new SpriteBatch(); 
     empty = new Texture("empty.jpg"); 
     player = new Texture("player.jpg"); 
     computer = new Texture("computer.jpg"); 

     Gdx.input.setInputProcessor(this); 

     // Initialize display for status messages. 
     mainStatusDisplay = new BitmapFont(); 
     mainStatusString = "Player's Turn"; 
     winningString = ""; 
    } 

    @Override 
    public void render() { 
     update(); 
     Gdx.gl.glClearColor(0, 0, 0, 1); 
     Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 
     batch.begin(); 
     drawBoard(); 
     mainStatusDisplay.setColor(Color.YELLOW); 
     mainStatusDisplay.draw(batch, mainStatusString, 32, 416); 
     batch.end(); 
    } 

    public void drawBoard() { 

     for (int i = 0; i < COLUMNS; i ++) { 
      for (int j = 0; j < ROWS; j++) { 
       if (gameBoard[i][j] == 0) { 
        drawingTile = empty; 
       } 
       else if (gameBoard[i][j] == 1) { 
        drawingTile = player; 
       } 

       else if (gameBoard[i][j] == 2) { 
        drawingTile = computer; 
       } 
       batch.draw(drawingTile, i * 64, j * 64); 
      } 
     } 
    } 

    // Method update handles updates to game logic. 
    public void update() { 
     // If it's gameover, end the game. 
     if (gameOver) { 
      // Set players turn to true to prevent computer from taking another turn. 
      playersTurn = true; 
      // Set status message to winning message; 
      mainStatusString = winningString; 
      // Disable input processor to prevent player from taking another turn. 
      Gdx.input.setInputProcessor(null); 
     }   

     // If it's not players turn, call computersTurn. 
     else if (!playersTurn) { 
      mainStatusString = "Computer's Turn"; 
      computersTurn(); 
     } 

     if (checkForWin(1) && checkForWin(2)) { 
      gameOver = true; 
     } 
    } 

    public void computersTurn() { 
     double maxScore = 2. * Integer.MIN_VALUE; 
     int xValue = 0; 

     // Search the gameboard and find the best move. 
     for (int x = 0; x < COLUMNS; x++) { 
      // If x column is a value move... 
      if (canMove(x)) { 
       // Set score of move from function. 
       double score = moveScore(x); 

       // If score is greater than max score... 
       if (score > maxScore) { 
        // Set score to max score and xValue to column. 
        maxScore = score; 
        xValue = x; 
        // If the score is a win, break from loop. 
        if (score == WIN) { 
         break; 
        } 
       } 
      } 
     } 
     // Set the piece for player at column as x. 
     setPiece(2, xValue); 

     // Set players turn and string status. 
     playersTurn = true; 
     mainStatusString = "Player's Turn"; 
    } 

    // Method moveScore determines the value of a move and returns it. 
    public double moveScore(int xValue) { 
     // Set the piece in place. 
     setPiece(2, xValue); 
     // Get the score and check it's value with alpha beta pruning. 
     double score = alphaBetaPrune(MAX_DEPTH, Integer.MIN_VALUE, Integer.MAX_VALUE, 1); 
     // Remove the piece. 
     takeAwayPiece(xValue); 

     return score; 
    } 

    public double alphaBetaPrune(int depth, double alpha, double beta, int whoPlayed) { 
     winner = checkForWin(1) || checkForWin(2); 
     // If we've reached the max depth of the tree or there is a winner... 
     if (depth == 0 || winner) { 
      double score; 
      // If there is a winner... 
      if (winner) { 
       // If player is the winner... 
       if (checkForWin(1)) { 
        // Set a losing score (Computer does not want player to win). 
        score = LOSE; 
       } 
       // Else this is a win for the computer... 
       else { 
        // Set score to a win. 
        score = WIN; 
       } 
      } 
      // Otherwise there is no winner... 
      else { 
       // Set score to TIE (0). 
       score = TIE; 
      } 

      // Return score and remove depth level. 
      return score/(MAX_DEPTH - depth +1); 
     } 

     // If computer is making the move... 
     if (whoPlayed == 2) { 
      // Iterate through gameboard. 
      for (int x = 0; x < COLUMNS; x++) { 
       // Check and see if next move can be made. 
       if (canMove(x)) { 
        // Make move for computer to x. 
        setPiece(2, x); 
        // Set alpha equal to return from recursion step minus one depth level. 
        alpha = Math.max(alpha, alphaBetaPrune(depth - 1, alpha, beta, 1)); 
        // Remove piece. 
        takeAwayPiece(x); 
        // Check returned alpha against beta and break from loop if beta is less than alpha. 
        if (beta <= alpha) { 
         break; 
        } 
       } 
      } 
      // We're here if alpha is larger and we didn't break from loop. 
      return alpha; 
     } 
     // Else if player is making move... 
     else { 
      // Iterate through gameboard. 
      for (int x = 0; x < COLUMNS; x++) { 
       // Check and see if next move can be made. 
       if (canMove(x)) { 
        // Make move for player to x. 
        setPiece(1, x); 
        // Set beta equal to return from recursion step minus one depth level for beta. 
        beta = Math.min(beta, alphaBetaPrune(depth - 1, alpha, beta, 2)); 
        // Remove piece. 
        takeAwayPiece(x); 
        // Check returned alpha against beta and break from loop if beta is less than alpha. 
        if (beta <= alpha) { 
         break; 
        } 
       } 
      } 
      // We're here if alpha is larger than beta and we didn't break from loop. 
      return beta; 
     } 
    } 

    // Method setPiece takes two int values as parameters and places a piece on the game board. 
    public void setPiece(int whoPlayed, int xValue) { 
     // For loop to iterate through each row. 
     for (int i = 0; i < ROWS; i++) { 
      // If row is empty... 
      if (gameBoard[xValue][i] == 0) { 
       // Place piece on the board. 
       gameBoard[xValue][i] = whoPlayed; 
       break; 
      } 
     } 
    } 

    // Method takeAwayPiece takes two int values as parameters and removes a piece from the board. 
    public void takeAwayPiece(int xValue) { 
     // For loop to iterate through each row. 
     for (int i = ROWS - 1; i > 0; i--) { 
      // If row contains a piece.. 
      if (gameBoard[xValue][i] != 0) { 
       // Remove piece. 
       gameBoard[xValue][i] = 0; 
       break; 
      } 
     } 
    } 

    // Method to determine if a move is valid 
    public boolean canMove(int xValue) { 
     // If the top spot in the given column is 0, return true. 
     return (gameBoard[xValue][ROWS-1] == 0); 
    } 

    // Method checkForWin takes a flag and checks to see if that player has won the game. 
    public boolean checkForWin(int whoPlayed) { 
     // Create counter to check for 4 in a row. 
     int win = 0; 
     // Iterate through gameboard and count pieces in a row. 
     for (int y = 0; y < ROWS; y++) { 
      for (int x = 0; x < COLUMNS; x++) { 
       // If piece is player who is checking, increment counter. 
       if (gameBoard[x][y] == whoPlayed) { 
        win++; 
       } 
       // Not in a row, set counter to 0. 
       else { 
        win = 0; 
       } 
       if (win == 4) { 
        break; 
       } 
      } 
      // If win counter is 4, winner. 
      if (win == 4) { 
       winningString = "Horizontal Win for Player " + whoPlayed; 
       return true; 
      } 
      // Else, reset win counter and check next column. 
      else { 
       win = 0; 
      } 
     } 

     // Iterate through gameboard and count pieces in a column. 
     for (int x = 0; x < COLUMNS; x++) { 
      for (int y = 0; y < ROWS; y++) { 
       // If piece is player who is checking, increment counter. 
       if (gameBoard[x][y] == whoPlayed) { 
        win++; 
       } 
       // Not in a row, set counter to 0. 
       else { 
        win = 0; 
       } 
       if (win == 4) { 
        break; 
       } 
      } 
      // If win counter is 4, player won. 
      if (win == 4) { 
       winningString = "Vertical Win for Player " + whoPlayed; 
       return true; 
      } 
      // Else, reset win counter and check next column. 
      else { 
       win = 0; 
      } 
     } 

     // Iterate through gameboard and count pieces in a diagonal row, left to right. 
     for (int x = 0; x < 3; x++) { 
      for (int y = 0; y < 2; y++) { 
       // If piece is player who is checking, check next piece diagonally. 
       if (gameBoard[x][y] == whoPlayed) { 
        // Then check next diagonal piece. 
        if (gameBoard[x+1][y+1] == whoPlayed) { 
         // Then check next diagonal piece. 
         if (gameBoard[x+2][y+2] == whoPlayed) { 
          // Then check last diagonal piece. 
          if (gameBoard[x+3][y+3] == whoPlayed) { 
           // Set winning message to player won and set gameover flag. 
           winningString = "Diagonal Win (LR) for Player " + whoPlayed; 
           // Exit function. 
           return true; 
          } 
         } 
        } 
       } 
      } 
     } 

     // Iterate through gameboard and count pieces in a diagonal row, right to left. 
     for (int x = 3; x < COLUMNS; x++) { 
      for (int y = 0; y < 2; y++) { 
       // If piece is player who is checking, check next piece diagonally. 
       if (gameBoard[x][y] == whoPlayed) { 
        // Then check next diagonal piece. 
        if (gameBoard[x-1][y+1] == whoPlayed) { 
         // Then check next diagonal piece. 
         if (gameBoard[x-2][y+2] == whoPlayed) { 
          // Then check last diagonal piece. 
          if (gameBoard[x-3][y+3] == whoPlayed) { 
           // Set winning message to player won and set gameover flag. 
           winningString = "Diagonal Win (RL) for Player " + whoPlayed; 
           // Exit function. 
           return true; 
          } 
         } 
        } 
       } 
      } 
     } 

     // Iterate through gameboard and if no 0 slots remain, game is a tie. 
     for (int x = 0; x < COLUMNS; x++) { 
      for (int y = 0; y < ROWS; y++) { 
       // If a 0 slot remains, return. 
       if (gameBoard[x][y] == 0) { 
        return false; 
       } 
      } 
     } 

     // If we're here, then there was no winners and no slots left. 
     winningString = "Tie Game"; 
     return false; 
    } 

    @Override 
    public boolean touchDown(int x, int y, int pointer, int button) { 
     if (playersTurn) { 
      if (button == Input.Buttons.LEFT) { 
       if (canMove(x/TILESIZE)) { 
        setPiece(1, x/TILESIZE); 
        playersTurn = false; 
        return true; 
       } 
      } 
     } 
     return false; 
    } 

    @Override 
    public boolean touchUp(int i, int i1, int i2, int i3) { 
     return false; 
    } 

    @Override 
    public boolean touchDragged(int i, int i1, int i2) { 
     return false; 
    } 

    @Override 
    public boolean mouseMoved(int i, int i1) { 
     return false; 
    } 

    @Override 
    public boolean scrolled(int i) { 
     return false; 
    } 
    @Override 
    public boolean keyDown(int i) { 
     return false; 
    } 

    @Override 
    public boolean keyUp(int i) { 
     return false; 
    } 

    @Override 
    public boolean keyTyped(char c) { 
     return false; 
    } 
} 

謝謝!

+0

我能夠追蹤win checker error的來源。在我的更新方法中,我用一個&&符號來檢查,這意味着如果布爾值失敗,表達式失敗,並且由於玩家和計算機不能同時獲勝,它總是會返回false。我將它改爲OR(||),然後突然,win checker工作,現在是A.I.也適用。唯一的問題仍然是計算機從一開始就放置整行棋子的第一個問題。 – 2015-04-04 02:13:27

回答

0

因此,在第一次修復之後,縮小問題的其他問題相當容易。在我的takeAwayPiece方法中,它沒有去除底部行上的任何東西,所以當A.I計算出它的下一步時,它放在底部的試件不起作用。

所以在takeAwayPiece的方法,我把它改成下面

// Method takeAwayPiece takes two int values as parameters and removes a piece from the board. 
    public void takeAwayPiece(int xValue) { 
     // For loop to iterate through each row. 
     for (int i = ROWS; i > 0; i--) { 
      System.out.println(i); 
      // If row contains a piece.. 
      if (gameBoard[xValue][i-1] != 0) { 
       // Remove piece. 
       //System.out.println("Piece at column " + xValue + " " + i); 
       gameBoard[xValue][i-1] = 0; 
       break; 
      } 
     } 
    } 

您可能注意到,不同的是,我開始=的行而非行-1,然後我被檢查對X-1而不是x(以前我只是試圖改變從i> 0到i = 0的條件,但有一些瘋狂的奇怪結果)。