package nooga.server; //Only the server should invoke this AIFE, so it is in //the server package import nooga.client.*; import nooga.util.*; import nooga.board.*; import javax.swing.*; import java.util.*; import java.io.*; /** This is the front end for the "computer player" that plays against the client when only 1 client is playing when the DotsGameHandler in intizialized. When it is the AI's turn, it will try to find a move as follows: Step 1. If there is a square that can be taken, take that square. Step 2. If step 1 fails, randomly make a move that will not allow your opponent to be able to make a square on their next move, if such a move exists. Step 3. If no move can be found in steps 1 and 2, make any random legal move (Since step 2 failed, making such a move in step three will enable the AI's opponent to make a aquare on thier next turn.) Since DotsAIFE is only used by the server, DotsAIFE appears in the server package. @see DotsGameHandler **/ public class DotsAIFE extends NOOGAAIFE { public DotsAIFE() { myRandom = new Random(); try { myClient = new NOOGAClientImpl(this,null); } catch (Exception e) { e.printStackTrace();} } public String getGameType() { return Constants.DOTS; } /** This is the main "brains" function of the AI. The AI will try to find a move as follows: 1. If there is a square that can be taken, take that square. 2. Randomly make a move that will not allow your opponent to be able to make a square on thier next mo, IF such a move exists. 3. If no move can be found in steps 1 and 2, make any random legal move (Since step 2 failed, making a move in step three will enable the AI's opponent to make a aquare on thier next turn. */ public void doTurn(Object dotsBoard) { try{ Thread.sleep(250);} catch(Exception e) {e.printStackTrace();} System.out.println("\nComputer taking turn..."); myDotsBoard = (DotsBoard) dotsBoard; if (makeSquare()) { try{ myClient.reportMove(myMove); return; } catch (Exception e){e.printStackTrace();} } else { if ( ! leaveNoOpenSquaresMove() ) { randomMove(); } } try { myClient.reportMove(myMove); return; } catch (Exception e) { e.printStackTrace(); } //System.out.println("AI done doing move"); } /** Make any random move ("Step 3"). */ private void randomMove() { int maxMoveAttempts = 4000; int index=0; int rightOrDown=RIGHT; for(int i =0; i < maxMoveAttempts; i++) { index = myRandom.nextInt(myDotsBoard.getHeight()*myDotsBoard.getWidth()); rightOrDown = myRandom.nextInt(2); if( index >= ((myDotsBoard.getHeight() -1) * myDotsBoard.getWidth())) if(rightOrDown == DOWN) continue; if( (index % (myDotsBoard.getWidth())) == (myDotsBoard.getWidth()-1) ) if( rightOrDown == RIGHT) continue; if( !isConnected(index,rightOrDown) ) { int point1 = index; int point2; if(rightOrDown == 0) { point2 = index + 1; } else { point2 = index + myDotsBoard.getWidth(); } myMove = new DotsMove(point1, point2); return; } } System.out.println("ERROR: UNABLE TO FIND MOVE"); } /** Try to make a move that will not leave a square available for the AI's opponent to take ("Step 2). */ private boolean leaveNoOpenSquaresMove() { int maxMoveAttempts = 1000; int index; int rightOrDown; for(int i= 0; i < maxMoveAttempts; i++) { index = myRandom.nextInt(myDotsBoard.getHeight()*myDotsBoard.getWidth()); rightOrDown = myRandom.nextInt(2); if( index >= ((myDotsBoard.getHeight() -1) * myDotsBoard.getWidth())) if(rightOrDown == DOWN) continue; if( (index % (myDotsBoard.getWidth())) == (myDotsBoard.getWidth()-1) ) if( rightOrDown == RIGHT) continue; if( !isConnected(index,rightOrDown)) { if(rightOrDown ==DOWN) { if( (numSidesTaken(index) != 2) && (numSidesTaken(index-1)!= 2) ) { int point1 = index; int point2 = index + myDotsBoard.getWidth(); myMove = new DotsMove(point1, point2); return true; } } else if (rightOrDown == RIGHT) { if( (numSidesTaken(index) != 2) && (numSidesTaken(index - myDotsBoard.getWidth()) != 2 ) ) { int point1 = index; int point2 = index + 1; myMove = new DotsMove(point1, point2); return true; } } } } return false; } /** Try to take a square ("Step 1.") */ private boolean makeSquare() { for(int i =0; i < myDotsBoard.getHeight()*myDotsBoard.getWidth(); i++) { if(numSidesTaken(i) == 3) { takeSquare(i); return true; } } return false; } private void takeSquare(int index) { if(!isConnected(index,RIGHT)) { int point1 = index; int point2 = index + 1; myMove = new DotsMove(point1, point2); } if( !isConnected(index,DOWN)) { int point1 = index; int point2 = index + myDotsBoard.getWidth(); myMove = new DotsMove(point1, point2); } if( !isConnected(index+1,DOWN) ) { int point1 = index+1; int point2 = index +1 + myDotsBoard.getWidth(); myMove = new DotsMove(point1, point2); } if( !isConnected(index+myDotsBoard.getWidth(),RIGHT) ) { int point1 = index + myDotsBoard.getWidth(); int point2 = index + myDotsBoard.getWidth() + 1; myMove = new DotsMove(point1, point2); } } private boolean isConnected(int index, int rightOrDown) { //if we are checking to the right of the dot if(rightOrDown == RIGHT) { return myDotsBoard.checkConnected(index, index+1); } else if(rightOrDown ==DOWN) { return myDotsBoard.checkConnected(index, index+ myDotsBoard.getWidth()); } else { System.out.println("Error in AI"); return false; } } private int numSidesTaken(int index) { int numSidesTaken = 0; if( isConnected(index,RIGHT) ) { numSidesTaken++; } if( isConnected(index,DOWN) ) { numSidesTaken++; } if( isConnected(index+1,DOWN) ) { numSidesTaken++; } if(isConnected(index+ myDotsBoard.getWidth(), RIGHT) ) { numSidesTaken++; } return numSidesTaken; } private DotsBoard myDotsBoard; private DotsMove myMove; private static final int RIGHT = 0; private static final int DOWN = 1; }