此处的所有源文件:
我是编程新手,无法弄清楚为什么我会收到此错误。我已经阅读了我能找到的所有线程,似乎没有任何工作。我知道可以通过查看对象并确保创建它来调试Null PointerException,我认为我已经创建了它。请告诉我你的看法。
该错误说明了它在这一行。 在leftToRight方法内... winsColAvailable和winnerSlotAvailable
代码:
import java.util.Random;
public class MyAgent extends Agent
{
Random r;
/**
* Constructs a new agent, giving it the game and telling it whether it is Red or Yellow.
*
* @param game The game the agent will be playing.
* @param iAmRed True if the agent is Red, False if the agent is Yellow.
*/
public MyAgent(Connect4Game game, boolean iAmRed)
{
super(game, iAmRed);
r = new Random();
}
/**
* The move method is run every time it is this agent's turn in the game. You may assume that
* when move() is called, the game has at least one open slot for a token, and the game has not
* already been won.
*
* By the end of the move method, the agent should have placed one token into the game at some
* point.
*
* After the move() method is called, the game engine will check to make sure the move was
* valid. A move might be invalid if:
* - No token was place into the game.
* - More than one token was placed into the game.
* - A previous token was removed from the game.
* - The color of a previous token was changed.
* - There are empty spaces below where the token was placed.
*
* If an invalid move is made, the game engine will announce it and the game will be ended.
*
*/
public void move()
{
// check if middle column is occupied
// Check and see if I have a winning move
int ifICanWin = iCanWin(iAmRed, myGame);
int ifTheyCanWin = theyCanWin(iAmRed, myGame);
if (ifICanWin >= 0)
{
moveOnColumn(ifICanWin);
}// Check and see if opponent has a winning move
else if (ifTheyCanWin >=0)
{
moveOnColumn(ifTheyCanWin);
} else
{
// Add a disk to all columns -->Shows board potentially after this move
// Duplicate the current game board
Connect4Game duplicateOfGame = new Connect4Game(myGame);
for (int col = 0; col < duplicateOfGame.getColumnCount(); ++col)
{
int lowestEmptySlotIndex = getLowestEmptyIndex(duplicateOfGame.getColumn(col)); // Find the top empty slot in the column
// If the column is full, lowestEmptySlot will be -1
if (lowestEmptySlotIndex > -1) // if the column is not full
{
Connect4Slot lowestEmptySlot = duplicateOfGame.getColumn(col).getSlot(lowestEmptySlotIndex); // get the slot in this column at this index
if (iAmRed) // If the current agent is the Red player...
{
lowestEmptySlot.addRed(); // Place a red token into the empty slot
}
else // If the current agent is the Yellow player (not the Red player)...
{
lowestEmptySlot.addYellow(); // Place a yellow token into the empty slot
}
}
}
ifICanWin = iCanWin(iAmRed, duplicateOfGame); // Checks if I can win on the board showing all my possible moves
if (ifICanWin >= 0)
{
moveOnColumn(ifICanWin);
}
// other players disk to all columns --> Shows board two moves from current state
for (int col = 0; col < duplicateOfGame.getColumnCount(); ++col)
{
int lowestEmptySlotIndex = getLowestEmptyIndex(duplicateOfGame.getColumn(col)); // Find the top empty slot in the column
// If the column is full, lowestEmptySlot will be -1
if (lowestEmptySlotIndex > -1) // if the column is not full
{
Connect4Slot lowestEmptySlot = duplicateOfGame.getColumn(col).getSlot(lowestEmptySlotIndex); // get the slot in this column at this index
if (iAmRed) // If the current agent is the Red player...add other token
{
lowestEmptySlot.addYellow(); // Place a red token into the empty slot
}
else // If the current agent is the Yellow player (not the Red player)...
{
lowestEmptySlot.addRed(); // Place a yellow token into the empty slot
}
}
}
ifTheyCanWin = theyCanWin(iAmRed, duplicateOfGame); // Checks if they can win on the board showing all their possible moves
if (ifTheyCanWin >= 0)
{
moveOnColumn(ifTheyCanWin);
}
if (ifTheyCanWin == -1 && ifICanWin == -1)
{
moveOnColumn(randomMove());
}
}
}
/**
* Drops a token into a particular column so that it will fall to the bottom of the column.
* If the column is already full, nothing will change.
*
* @param columnNumber The column into which to drop the token.
*/
public void moveOnColumn(int columnNumber)
{
int lowestEmptySlotIndex = getLowestEmptyIndex(myGame.getColumn(columnNumber)); // Find the top empty slot in the column
// If the column is full, lowestEmptySlot will be -1
if (lowestEmptySlotIndex > -1) // if the column is not full
{
Connect4Slot lowestEmptySlot = myGame.getColumn(columnNumber).getSlot(lowestEmptySlotIndex); // get the slot in this column at this index
if (iAmRed) // If the current agent is the Red player...
{
lowestEmptySlot.addRed(); // Place a red token into the empty slot
}
else // If the current agent is the Yellow player (not the Red player)...
{
lowestEmptySlot.addYellow(); // Place a yellow token into the empty slot
}
}
}
/**
* Returns the index of the top empty slot in a particular column.
*
* @param column The column to check.
* @return the index of the top empty slot in a particular column; -1 if the column is already full.
*/
public int getLowestEmptyIndex(Connect4Column column) {
int lowestEmptySlot = -1;
for (int i = 0; i < column.getRowCount(); i++)
{
if (!column.getSlot(i).getIsFilled())
{
lowestEmptySlot = i;
}
}
return lowestEmptySlot;
}
/**
* Returns a random valid move. If your agent doesn't know what to do, making a random move
* can allow the game to go on anyway.
*
* @return a random valid move.
*/
public int randomMove()
{
int i = r.nextInt(myGame.getColumnCount());
while (getLowestEmptyIndex(myGame.getColumn(i)) == -1)
{
i = r.nextInt(myGame.getColumnCount());
}
return i;
}
/**
* Returns the column that would allow the agent to win.
*
* You might want your agent to check to see if it has a winning move available to it so that
* it can go ahead and make that move. Implement this method to return what column would
* allow the agent to win.
*
* @return the column that would allow the agent to win.
*/
public int iCanWin(boolean isRed, Connect4Game aGame)
{
// Horizontal R --> L
int leftToRight = canWinLeftToRight(isRed, aGame);
// Horizontal L --> R
int rightToLeft = canWinRightToLeft(isRed, aGame);
// Vertical
int verticaWin = canWinVertically(isRed, aGame);
// Diagonal Up-->R
int upToRight = canWinDiagonalRight(isRed, aGame);
// Diagonal Up-->L
int upToLeft = canWinDiagonalLeft(isRed, aGame);
if (leftToRight > 0) {return leftToRight;}
else if (rightToLeft > 0) {return rightToLeft;}
else if(verticaWin > 0) {return verticaWin;}
else if (upToRight > 0) {return upToRight;}
else if (upToLeft > 0) {return upToLeft;}
else return -1;
}
/**
* Returns the column that would allow the opponent to win.
*
* Implement this method to return what column should
* be blocked to prevent the opponent from winning.
*
* @return the column that would allow the opponent to win.
*/
public int theyCanWin(boolean isRed, Connect4Game aGame)
{
boolean oppColor = !isRed;
// Horizontal R --> L
int leftToRight = canWinLeftToRight(oppColor, aGame);
// Horizontal L --> R
int rightToLeft = canWinRightToLeft(oppColor, aGame);
// Vertical
int verticaWin = canWinVertically(oppColor, aGame);
// Diagonal Up-->R
int upToRight = canWinDiagonalRight(oppColor, aGame);
// Diagonal Up-->L
int upToLeft = canWinDiagonalLeft(oppColor, aGame);
if (leftToRight > 0) {return leftToRight;}
else if (rightToLeft > 0) {return rightToLeft;}
else if(verticaWin > 0) {return verticaWin;}
else if (upToRight > 0) {return upToRight;}
else if (upToLeft > 0) {return upToLeft;}
else return -1;
}
/**
* Returns the name of this agent.
*
* @return the agent's name
*/
public String getName()
{
String name = "The Cyber King";
return name;
}
/**
* Returns a column number if player can play a winning move on a row Left to Right, or a -1 if no winning move available for that player.
*
* @param currentGame is the game board used to determing if a player has a winning move.
* @param checkedColor is the color to be assessed.
* @return the winning column number or a -1
*/
private int canWinLeftToRight(boolean checkedColor, Connect4Game currentGame)
{
for(int row=0; row < 6; ++row )
{
int counter = 0;
for (int col=0; col < 7; ++col) {
Connect4Column currCol = new Connect4Column(myGame.getColumn(col));
Connect4Slot currSlot = new Connect4Slot(currCol.getSlot(row));
boolean currSlotIsFilled = currSlot.getIsFilled();
if (currSlotIsFilled) { // if not null
if (currSlot.getIsRed() == checkedColor) {
++counter;
}
else {
counter = 0;
}
}
else{
counter = 0;
}
Connect4Column winningColAvailable = currentGame.getColumn(col+1);
Connect4Slot winningSlotAvailable = winningColAvailable.getSlot(row);
if (counter == 3 && (col+1)<7 && !winningSlotAvailable.getIsFilled()) {
return col+1;
}
}
}
return -1;
}
/**
* Returns a column number if player can play a winning move on a row right to Left, or a -1 if no winning move available for that player.
*
* @param currentGame is the game board used to determing if a player has a winning move.
* @param checkedColor is the color to be assessed.
* @return the winning column number or a -1
*/
private int canWinRightToLeft(boolean checkedColor, Connect4Game currentGame)
{
for(int row=0; row < currentGame.getRowCount(); ++row )
{
int counter = 0;
for (int col=currentGame.getColumnCount()-1; col >=0 ; --col) {
Connect4Column currCol = currentGame.getColumn(col);
Connect4Slot currSlot = currCol.getSlot(row);
boolean currSlotIsFilled = currSlot.getIsFilled();
if (currSlotIsFilled) { // if not null
if (currSlot.getIsRed() == checkedColor) {
++counter;
}
else {
counter = 0;
}
}
else{
counter = 0;
}
Connect4Column winningColAvailable = currentGame.getColumn(col-1);
Connect4Slot winningSlotAvailable = winningColAvailable.getSlot(row);
if (counter == 3 && (col-1) >= 0 && !winningSlotAvailable.getIsFilled()) {
return col-1;
}
}
}
return -1;
}
/**
* Returns a column number if player can play a winning move it, or a -1 if no winning move available for that player.
*
* @param currentGame is the game board used to determing if a player has a winning move.
* @param checkedColor is the color to be assessed.
* @return the winning column number or a -1
*/
private int canWinVertically(boolean checkedColor, Connect4Game currentGame)
{
for (int col = 0; col < currentGame.getColumnCount(); ++col) {
int counter = 0;
for (int slot = 0; slot < currentGame.getRowCount(); slot++) {
Connect4Column currCol = currentGame.getColumn(col);
Connect4Slot currSlot = currCol.getSlot(slot);
boolean currSlotIsFilled = currSlot.getIsFilled();
if (currSlotIsFilled) { // if not null
if (currSlot.getIsRed() == checkedColor) {
++counter;
System.out.println("Col: " + col + " Slot: "+ slot +" being checked, and is player, so ++counter. Counter is now " + counter);
} else {
counter = 0;
System.out.println("Col: " + col + " Slot: "+ slot +" being checked, and is not player, so counter = 0. Counter is now " + counter);
}
} else {
counter = 0;
System.out.println("Col: " + col + " Slot: "+ slot +" being checked, and is null so counter = 0. Counter is now " + counter);
}
Connect4Slot winningSlot = currCol.getSlot(slot+1);
if (counter == 3 && (slot+1) < 6 && !winningSlot.getIsFilled()) {
return col;
}
}
}
return -1;
}
/**
* Returns a column number if player can play a winning move three columns over and three slots up to the Right.
*
* @param currentGame is the game board used to determing if a player has a winning move.
* @param checkedColor is the color to be assessed.
* @return the winning column number or a -1
*/
private int canWinDiagonalRight(boolean checkedColor, Connect4Game currentGame)
{
for (int col = 0; col < 4; ++col)
{
for (int slot = 0; slot < 3; slot++)
{
System.out.println("Col: " + col + " Slot: "+ slot +" being checked for a diagonal win for player.");
// Slot 1
Connect4Column col1 = currentGame.getColumn(col);
Connect4Slot slot1 = col1.getSlot(slot);
boolean slot1IsFilled = slot1.getIsFilled();
// Slot 2
Connect4Column col2 = currentGame.getColumn(col+1);
Connect4Slot slot2 = col2.getSlot(slot+1);
boolean slot2IsFilled = slot2.getIsFilled();
// slot 3
Connect4Column col3 = currentGame.getColumn(col+2);
Connect4Slot slot3 = col3.getSlot(slot+2);
boolean slot3IsFilled = slot3.getIsFilled();
// Slot 4
Connect4Column winningCol = currentGame.getColumn(col+3);
Connect4Slot winningSlot = winningCol.getSlot(slot+3);
boolean winningSlotIsFilled = winningSlot.getIsFilled();
if (slot1IsFilled &&
slot1.getIsRed() == checkedColor &&
slot2IsFilled &&
slot2.getIsRed() == checkedColor &&
slot3IsFilled &&
slot3.getIsRed() == checkedColor &&
!winningSlotIsFilled)
{
return col+3;
}
}
}
return -1;
}
/**
* Returns a column number if player can play a winning move three columns over and three slots up to the Left.
*
* @param currentGame is the game board used to determing if a player has a winning move.
* @param checkedColor is the color to be assessed.
* @return the winning column number or a -1
*/
private int canWinDiagonalLeft(boolean checkedColor, Connect4Game currentGame)
{
for (int col = 6; col > 2; --col)
{
for (int slot = 0; slot < 3; slot++)
{
System.out.println("Col: " + col + " Slot: "+ slot +" being checked for a diagonal win for player.");
// Slot 1
Connect4Column col1 = currentGame.getColumn(col);
Connect4Slot slot1 = col1.getSlot(slot);
boolean slot1IsFilled = slot1.getIsFilled();
// Slot 2
Connect4Column col2 = currentGame.getColumn(col-1);
Connect4Slot slot2 = col2.getSlot(slot+1);
boolean slot2IsFilled = slot2.getIsFilled();
// slot 3
Connect4Column col3 = currentGame.getColumn(col-2);
Connect4Slot slot3 = col3.getSlot(slot+2);
boolean slot3IsFilled = slot3.getIsFilled();
// Slot 4
Connect4Column winningCol = currentGame.getColumn(col-3);
Connect4Slot winningSlot = winningCol.getSlot(slot+3);
boolean winningSlotIsFilled = winningSlot.getIsFilled();
if (slot1IsFilled &&
slot1.getIsRed() == checkedColor &&
slot2IsFilled &&
slot2.getIsRed() == checkedColor &&
slot3IsFilled &&
slot3.getIsRed() == checkedColor &&
!winningSlotIsFilled)
{
return col+3;
}
}
}
return -1;
}
}
记录:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at MyAgent.canWinLeftToRight(MyAgent.java:273)
at MyAgent.iCanWin(MyAgent.java:179)
at MyAgent.move(MyAgent.java:42)
at Connect4Frame.nextMove(Connect4Frame.java:119)
at Connect4Frame.nextMoveButtonPressed(Connect4Frame.java:234)
at Connect4Frame$2.actionPerformed(Connect4Frame.java:58)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2346)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6525)