/* Rocks Source Code */ /* By Dick Christoph May 1998 */ /* dchristo@minn.net */ /* www1.minn.net/~dchristo */ import java.applet.*; import java.awt.*; public class Rocks extends Applet implements Runnable { static final int MAXSCREENX = 300; static final int MAXSCREENY = 400; /* 450 -> 550 */ static final int MSGWIDTH = 220; static final int MSGHEIGHT = 30; static final int MAXROWS = 6; static final int MAXCOLS = 15; /* Last column is a phony one */ public static int numRows, numCols; static final int FALSE = 0; static final int TRUE = 1; // RockCanvas.width = topleftoff + lanewidth * (MAXCOLS - 1) (= 350 // lanewidth = ((2 * rowSize)/3)/2; // rowSize = (Rocks.MAXSCREENY - 100) / (Rocks.MAXROWS+1); /* Extra 1 is for startHeight and BottomHeight */ // laneWidth = 21.42 public static int board[][][]; /* ROW, COL, GATEINFO=3 */ public static int tboard[][][]; /* ROW, COL, GATEINFO=3 */ static final int GATETYPE = 0; static final int GATEPOSITION = 1; static final int GATEHOLDS = 2; static final int GATEBALLNUM = 3; static final int GATEDOESHOLD = 4; /* indcates a ball is in 0 or 4 of a gate (not held) from bounce of BallInGate */ static final int BOARDINFOCOLS = 5; /* Gate Types */ static final int NOGATE = 0; static final int REGULAR = 1; static final int LEFTEDGE = 2; static final int RIGHTEDGE = 3; /* Gate Position */ static final int LEFT = 0; static final int RIGHT = 1; /* Gate Holds */ static final int NOBALL = 0; static final int BALL = 1; static final int MAXBALLS = 100; public static int balls[][]; /* MAXBALLS, BALLINFO */ public static int tballs[][]; /* MAXBALLS, BALLINFO */ public static int firstFreeBall, tfirstFreeBall; /* BallInfo */ static final int LOCATION = 0; static final int BALLCOLOR = 1; static final int INDEXR = 2; /* Row,Col of Gate or Col of Start */ static final int INDEXC = 3; static final int SUBINDEX = 4; static final int WHEREINGATE = 5; /* Position within Gate 1..6, 1-Start 1/2-Bottom */ static final int CHANGING = 6; // indicates BALL is still changing static final int PREVBALL = 7; /* Pointers for FreeBall Heap */ static final int NEXTBALL = 8; /* Pointers for FreeBall Heap */ static final int MAXSUB = 3; static final int GREEN = 1; static final int BLUE = 2; static final int RED = 3; /* Location Index */ static final int INBANK = 0; /* */ static final int INSTART = 1; static final int INGATE = 2; static final int INBOTTOM = 3; static final int MINREPEATSCORE = 2; public static int ballsOnboard, tballsOnboard, whoseTurn, winner, turnCount, playerScored; public static boolean boardChanging, tboardChanging; // Indicates the balls are still falling public static boolean bottomChanging; // Indicates the balls are still falling public static final int HUMAN = 1; public static final int COMPUTER = 2; public static int eventList[]; // MAXEVENTS public static int eventListTop; public static final int MAXEVENTS = (MAXROWS * MAXCOLS)/2; /* maxBallsOnScreen How to calculate */ static final int BALLNUM = 0; // from getFreeBall(); public static int bottom[][][], tbottom[][][]; public static RockCanvas cnv1; public static Label whoseTurnL; public static int humanScore, computerScore, winningScore; public static TextField humanScoreF, computerScoreF, statusMsg; public static Checkbox cbHumanFirst; public static Button newGameButton; public static Choice chSkill, chRows, chCols, chWinningScore; private Thread updateThread = null; Panel p1, p2, p3, p4, p5, p6, p7, p8, p9, p10; /* FindBestMoveHard Stuff */ public static boolean level4MemSetup; public static final int MAXSBOARDS = 1000; /* MAX SBOARDS needed, needn't save one for each ENDNODE Can also deleted sboards after all paths have been investigated */ public static final int MAXENDNODES = 1000; /* MAXIMUM END NODES needed */ public static final int MAXTREENODES = 1000; public static final int MAXSBALLLIST = 5000; public static int sboard[][][][]; /* MAXSBOARDS */ public static treeNode treeNodes[]; public static endNode endNodes[]; /* of treeNode pointers (actually int); */ public static sBallInfo sBallList[]; public static int sBalls[]; /*first sball in sBallList[] */ public static int sBoardRef[][]; public static final int COUNT = 0; public static final int NEXTBOARD = 1; public static int firstFreeSBall, firstFreeSBoard, firstFreeTreeNode; public static int endNodeStart, endNodeEnd, firstFreeEndNode; public static int maxTreeNodes, maxTreeNodesT; /* */ public void init() { int msgStartX, msgStartY; setLayout(null); resize(MAXSCREENX + MSGWIDTH,MAXSCREENY); addNotify(); numRows = MAXROWS; numCols = MAXCOLS; cnv1 = new RockCanvas(); add(cnv1); cnv1.reshape(0,0,MAXSCREENX, MAXSCREENY); humanScore = 0; computerScore = 0; msgStartX = MAXSCREENX; msgStartY = RockCanvas.topLeftOff; p1 = new Panel(); computerScoreF = new TextField(4); p1.add(new Label(" My Score: ")); p1.add(computerScoreF); p1.reshape(msgStartX, msgStartY, MSGWIDTH, MSGHEIGHT); computerScoreF.setText("" + computerScore); add(p1); p2 = new Panel(); humanScoreF = new TextField(4); p2.add(new Label("Your Score: ")); p2.add(humanScoreF); p2.reshape(msgStartX, msgStartY+MSGHEIGHT, MSGWIDTH, MSGHEIGHT); humanScoreF.setText("" + humanScore); add(p2); p3 = new Panel(); whoseTurnL = new Label("Your Turn"); whoseTurnL.setAlignment(Label.CENTER); whoseTurnL.setFont(new Font("SansSerif", Font.BOLD, 14)); p3.add(whoseTurnL); p3.reshape(msgStartX, msgStartY+2*MSGHEIGHT, MSGWIDTH, MSGHEIGHT); add(p3); p4 = new Panel(); statusMsg = new TextField(25); p4.add(statusMsg); p4.reshape(msgStartX,msgStartY+3*MSGHEIGHT,MSGWIDTH,MSGHEIGHT); add(p4); p5 = new Panel(); cbHumanFirst = new Checkbox("You move First"); cbHumanFirst.setState(true); p5.add(cbHumanFirst); p5.reshape(msgStartX, msgStartY+5*MSGHEIGHT, MSGWIDTH, MSGHEIGHT); add(p5); p6 = new Panel(); chSkill = new Choice(); p6.add(new Label("My Search: ")); chSkill.addItem("Level 1"); /* 0: 1-depth1: 2-depth2: 3-depth3: */ chSkill.addItem("Level 2"); chSkill.addItem("Level 3"); chSkill.addItem("Level 4"); p6.add(chSkill); chSkill.select(2); p6.reshape(msgStartX,msgStartY+6*MSGHEIGHT,MSGWIDTH,MSGHEIGHT); add(p6); p7 = new Panel(); chRows = new Choice(); chRows.addItem("2 Rows"); chRows.addItem("4 Rows"); chRows.addItem("6 Rows"); p7.add(chRows); chRows.select(1); p7.reshape(msgStartX,msgStartY+7*MSGHEIGHT,MSGWIDTH,MSGHEIGHT); add(p7); p8 = new Panel(); chCols = new Choice(); chCols.addItem("4 Columns"); chCols.addItem("6 Columns"); chCols.addItem("8 Columns"); chCols.addItem("10 Columns"); chCols.addItem("12 Columns"); chCols.addItem("14 Columns"); p8.add(chCols); chCols.select(1); p8.reshape(msgStartX,msgStartY+8*MSGHEIGHT,MSGWIDTH,MSGHEIGHT); add(p8); p9 = new Panel(); chWinningScore = new Choice(); p9.add(new Label("Winning Score: ")); chWinningScore.addItem("10"); chWinningScore.addItem("25"); chWinningScore.addItem("50"); chWinningScore.addItem("75"); chWinningScore.addItem("100"); p9.add(chWinningScore); chWinningScore.select(1); p9.reshape(msgStartX, msgStartY+9*MSGHEIGHT, MSGWIDTH, MSGHEIGHT); add(p9); p10 = new Panel(); newGameButton = new Button("New Game"); p10.add(newGameButton); p10.reshape(msgStartX,msgStartY+10*MSGHEIGHT,MSGWIDTH,MSGHEIGHT); add(p10); setupMem(); initBoard(); cnv1.repaint(); if (updateThread == null) { updateThread = new Thread(this,"Rockslide Game"); } updateThread.start(); } public void start() { if (updateThread == null) { updateThread = new Thread(this,"Rockslide Game"); } } public void destroy() { } public void stop() { updateThread = null; } public boolean action(Event e, Object arg) { Object source = e.target; boolean rv; rv = false; updateThread.suspend(); if (source == newGameButton) { // System.out.println("New Game"); initBoard(); cnv1.repaint(); // if (!cbHumanFirst.getState()) // findBestMove(); } else { if (source == cbHumanFirst) { if ((humanScore == 0) && (computerScore == 0)) { if (!cbHumanFirst.getState()) { initBoard(); // cnv1.repaint(); } } } else { rv = true; } } updateThread.resume(); return true; } public static int strVal(String vStr) { int rv; try { rv = Integer.parseInt(vStr); } catch (NumberFormatException e) { rv = 0; } return(rv); } public boolean handleEvent(Event e) { if (e.id == Event.WINDOW_DESTROY) System.exit(0); return super.handleEvent(e); } public static void setupMem() { int r, c; board = new int[MAXROWS][MAXCOLS][5]; tboard = new int[MAXROWS][MAXCOLS][5]; balls = new int[MAXBALLS][9]; tballs = new int[MAXBALLS][9]; bottom = new int[MAXROWS][MAXCOLS][2]; tbottom = new int[MAXROWS][MAXCOLS][2]; eventList = new int[MAXEVENTS]; eventListTop = 0; if (SkillLevel() == 4) { setupLevel4Mem(); level4MemSetup = true; } else level4MemSetup = false; for (c = 0; c < MAXCOLS; c++) { bottom[0][c][0] = FALSE; bottom[1][c][0] = FALSE; bottom[0][c][1] = -1; bottom[1][c][1] = -1; tbottom[0][c][0] = FALSE; tbottom[1][c][0] = FALSE; tbottom[0][c][1] = -1; tbottom[1][c][1] = -1; } } public static void setupLevel4Mem() { int c; sboard = new int[MAXSBOARDS][MAXROWS][MAXCOLS][5]; treeNodes = new treeNode[MAXTREENODES]; for (c = 0; c < MAXTREENODES; c++) treeNodes[c] = new treeNode(); endNodes = new endNode[MAXENDNODES]; for (c = 0; c < MAXENDNODES; c++) endNodes[c] = new endNode(); sBallList = new sBallInfo[MAXSBALLLIST]; for (c = 0; c < MAXSBALLLIST; c++) sBallList[c] = new sBallInfo(); sBalls = new int[MAXSBOARDS]; sBoardRef = new int[MAXSBOARDS][2]; } public static void initBoard() { int i, r, c; numRows = getNumRows(); numCols = getNumCols(); cnv1.initCanvas(); maxTreeNodes = 0; maxTreeNodesT = 0; winner = 0; playerScored = 0; if (cbHumanFirst.getState()) whoseTurn = COMPUTER; else whoseTurn = HUMAN; toggleTurnMsg(); for (i = 0; i < MAXBALLS; i++) { balls[i][PREVBALL] = i - 1; balls[i][NEXTBALL] = i + 1; } balls[MAXBALLS-1][NEXTBALL] = -1; firstFreeBall = 0; ballsOnboard = -1; humanScore = 0; computerScore = 0; computerScoreF.setText("" + computerScore); humanScoreF.setText("" + humanScore); /* Setup Board */ for (r = 0; r < numRows; r++) { for (c = 0; c < numCols; c++) { board[r][c][GATETYPE] = NOGATE; board[r][c][GATEBALLNUM] = -1; board[r][c][GATEDOESHOLD] = -1; if ((r % 2) == 0) { if ((c % 2) == 1) board[r][c][GATETYPE] = REGULAR; } else { if ((c % 2) == 0) { if (c == 0) board[r][c][GATETYPE] = LEFTEDGE; else { if (c == numCols - 1) board[r][c][GATETYPE] = RIGHTEDGE; else board[r][c][GATETYPE] = REGULAR; } } } } } /* Randomize Board */ for (r = 0; r < numRows; r++) { for (c = 0; c < numCols; c++) { if (board[r][c][GATETYPE] == REGULAR) { board[r][c][GATEHOLDS] = NOBALL; board[r][c][GATEBALLNUM] = -1; if ( ((int) (Math.random() * 2)) == 0) board[r][c][GATEPOSITION] = LEFT; else board[r][c][GATEPOSITION] = RIGHT; } } } if (false) { for (r = 0; r < numRows; r++) { for (c = 0; c < numCols; c++) { if (board[r][c][GATETYPE] == REGULAR) { if (board[r][c][GATEPOSITION] == LEFT) System.out.println(" board[" + r + "][" + c + "][GATEPOSITION]= LEFT;"); else System.out.println(" board[" + r + "][" + c + "][GATEPOSITION]= RIGHT;"); } } } } // getBoard(); boardChanging = false; bottomChanging = false; humanScore = 0; computerScore = 0; winningScore = getWinningScore(); if ((SkillLevel() == 4) && (!level4MemSetup)) { setupLevel4Mem(); level4MemSetup = true; } } public static void getBoard() { board[0][1][GATEPOSITION]= LEFT; board[0][3][GATEPOSITION]= LEFT; board[0][5][GATEPOSITION]= RIGHT; board[0][7][GATEPOSITION]= RIGHT; board[0][9][GATEPOSITION]= LEFT; board[0][11][GATEPOSITION]= RIGHT; board[0][13][GATEPOSITION]= LEFT; board[1][2][GATEPOSITION]= LEFT; board[1][4][GATEPOSITION]= RIGHT; board[1][6][GATEPOSITION]= RIGHT; board[1][8][GATEPOSITION]= RIGHT; board[1][10][GATEPOSITION]= LEFT; board[1][12][GATEPOSITION]= RIGHT; board[2][1][GATEPOSITION]= LEFT; board[2][3][GATEPOSITION]= RIGHT; board[2][5][GATEPOSITION]= RIGHT; board[2][7][GATEPOSITION]= RIGHT; board[2][9][GATEPOSITION]= RIGHT; board[2][11][GATEPOSITION]= LEFT; board[2][13][GATEPOSITION]= RIGHT; board[3][2][GATEPOSITION]= RIGHT; board[3][4][GATEPOSITION]= LEFT; board[3][6][GATEPOSITION]= RIGHT; board[3][8][GATEPOSITION]= LEFT; board[3][10][GATEPOSITION]= LEFT; board[3][12][GATEPOSITION]= RIGHT; board[4][1][GATEPOSITION]= RIGHT; board[4][3][GATEPOSITION]= RIGHT; board[4][5][GATEPOSITION]= LEFT; board[4][7][GATEPOSITION]= LEFT; board[4][9][GATEPOSITION]= RIGHT; board[4][11][GATEPOSITION]= LEFT; board[4][13][GATEPOSITION]= LEFT; board[5][2][GATEPOSITION]= LEFT; board[5][4][GATEPOSITION]= RIGHT; board[5][6][GATEPOSITION]= RIGHT; board[5][8][GATEPOSITION]= RIGHT; board[5][10][GATEPOSITION]= RIGHT; board[5][12][GATEPOSITION]= RIGHT; } public static void addBall(int laneNumber) { int bn; bn = getFreeBall(); balls[bn][LOCATION] = INSTART; if (whoseTurn == HUMAN) { // System.out.println("HUMAN: " + laneNumber); balls[bn][BALLCOLOR] = RED; } else { // System.out.println("COMPUTER: " + laneNumber); balls[bn][BALLCOLOR] = BLUE; } balls[bn][INDEXR] = 0; balls[bn][INDEXC] = laneNumber; balls[bn][SUBINDEX] = 0; balls[bn][WHEREINGATE] = 0; balls[bn][CHANGING] = TRUE; if (ballsOnboard != -1) balls[ballsOnboard][PREVBALL] = bn; balls[bn][PREVBALL] = -1; balls[bn][NEXTBALL] = ballsOnboard; ballsOnboard = bn; eventList[0] = bn; eventListTop = 1; boardChanging = true; } public static void addtBall(int laneNumber) { int bn; bn = getFreetBall(); tballs[bn][LOCATION] = INSTART; if (whoseTurn == HUMAN) tballs[bn][BALLCOLOR] = RED; else tballs[bn][BALLCOLOR] = BLUE; tballs[bn][INDEXR] = 0; tballs[bn][INDEXC] = laneNumber; tballs[bn][WHEREINGATE] = 0; tballs[bn][CHANGING] = TRUE; if (tballsOnboard != -1) tballs[tballsOnboard][PREVBALL] = bn; tballs[bn][PREVBALL] = -1; tballs[bn][NEXTBALL] = tballsOnboard; tballsOnboard = bn; eventList[0] = bn; eventListTop = 1; tboardChanging = true; } public static int getFreeBall() { int rv; rv = firstFreeBall; firstFreeBall = balls[firstFreeBall][NEXTBALL]; if (rv == -1) statusMsg.setText("Out of Memory for Rocks"); return(rv); } public static void recycleBall(int ballNum) { int pb, nb; pb = balls[ballNum][PREVBALL]; nb = balls[ballNum][NEXTBALL]; if (nb != -1) balls[nb][PREVBALL] = pb; if (pb != -1) balls[pb][NEXTBALL] = nb; balls[ballNum][PREVBALL] = -1; balls[ballNum][NEXTBALL] = firstFreeBall; firstFreeBall = ballNum; } public static void removeBallFromBoard(int ballNum) { int pb, nb; if (ballsOnboard == ballNum) { ballsOnboard = balls[ballNum][NEXTBALL]; if (ballsOnboard != -1) balls[ballsOnboard][PREVBALL] = -1; } else { pb = balls[ballNum][PREVBALL]; nb = balls[ballNum][NEXTBALL]; if (nb != -1) balls[nb][PREVBALL] = pb; if (pb != -1) balls[pb][NEXTBALL] = nb; } balls[firstFreeBall][PREVBALL] = ballNum; balls[ballNum][NEXTBALL] = firstFreeBall; firstFreeBall = ballNum; } public static int getFreetBall() { int rv; rv = tfirstFreeBall; tfirstFreeBall = tballs[tfirstFreeBall][NEXTBALL]; if (rv == -1) { statusMsg.setText("Out of Memory for TBalls"); System.out.println("getFreeTBall: Out of Memory for TBalls"); } return(rv); } public static void recycletBall(int ballNum) { int pb, nb; pb = tballs[ballNum][PREVBALL]; nb = tballs[ballNum][NEXTBALL]; if (nb != -1) tballs[nb][PREVBALL] = pb; if (pb != -1) tballs[pb][NEXTBALL] = nb; tballs[ballNum][PREVBALL] = -1; tballs[ballNum][NEXTBALL] = tfirstFreeBall; tfirstFreeBall = ballNum; } public static void removetBallFromBoard(int ballNum) { int pb, nb; if (tballsOnboard == ballNum) { tballsOnboard = tballs[ballNum][NEXTBALL]; if (tballsOnboard != -1) tballs[ballsOnboard][PREVBALL] = -1; } else { pb = tballs[ballNum][PREVBALL]; nb = tballs[ballNum][NEXTBALL]; if (nb != -1) tballs[nb][PREVBALL] = pb; if (pb != -1) tballs[pb][NEXTBALL] = nb; } tballs[firstFreeBall][PREVBALL] = ballNum; tballs[ballNum][NEXTBALL] = tfirstFreeBall; tfirstFreeBall = ballNum; } public static void toggleTurnMsg() { turnCount = 1; if (whoseTurn == HUMAN) { whoseTurn = COMPUTER; whoseTurnL.setText("It is My Turn: " + turnCount); } else { whoseTurn = HUMAN; whoseTurnL.setText("It is Your Turn: " + turnCount); } } public static void displayTurnMsg() { turnCount++; if (whoseTurn == COMPUTER) whoseTurnL.setText("It is My Turn: " + turnCount); else whoseTurnL.setText("It is Your Turn: " + turnCount); } public void run() { boolean done; Thread myThread = Thread.currentThread(); int moveHistory[], moveHistoryTop, mh, cm; moveHistory = new int[24]; moveHistoryTop = 0; // done = false; while (updateThread == myThread) { if (boardChanging) cnv1.repaint(); if ((!boardChanging) && (whoseTurn == COMPUTER) && (winner == 0)) { cm = findComputerMove(); addBall(cm); moveHistory[moveHistoryTop++] = cm; } if (boardChanging) { moveBalls(); if (!boardChanging) { if (playerScored > MINREPEATSCORE-1) displayTurnMsg(); else { toggleTurnMsg(); // for (mh = 0; mh < moveHistoryTop; mh++) // System.out.println(mh + " Move Lane: " + moveHistory[mh]); moveHistoryTop = 0; } playerScored = 0; } } if ((!boardChanging) && (checkForWinner())) cnv1.repaint(); try { Thread.sleep(75); } catch (InterruptedException e) { } } } public static void moveBalls() { int evt, ln, bn, r, c, saver, savec, r1, c1, gp; boolean found, pauseBall; boardChanging = false; evt = 0; while (evt < eventListTop) { bn = eventList[evt]; /* Ball Number */ if ((balls[bn][CHANGING] == 1) || (balls[bn][SUBINDEX] != 0)) { boardChanging = true; if (balls[bn][SUBINDEX] != 0) balls[bn][SUBINDEX]--; else { balls[bn][SUBINDEX] = MAXSUB - 1; switch (balls[bn][LOCATION]) { case INSTART: if (balls[bn][WHEREINGATE] == 0) { ln = balls[bn][INDEXC]; balls[bn][LOCATION] = INGATE; balls[bn][INDEXR] = 0; balls[bn][INDEXC] = (2 * (ln / 2)) + 1; if (ln == balls[bn][INDEXC]) balls[bn][WHEREINGATE] = 4; else balls[bn][WHEREINGATE] = 0; r = balls[bn][INDEXR]; c = balls[bn][INDEXC]; if (board[r][c][GATETYPE] == REGULAR) { if (board[r][c][GATEPOSITION] == LEFT) { if (balls[bn][WHEREINGATE] == 0) { if (board[r][c][GATEHOLDS] == BALL) { /* Move Back into START */ balls[bn][LOCATION] = INSTART; balls[bn][INDEXR] = 0; balls[bn][INDEXC] = ln; balls[bn][WHEREINGATE] = 1; } else { board[r][c][GATEHOLDS] = BALL; board[r][c][GATEBALLNUM] = bn; balls[bn][CHANGING] = FALSE; } } } else /* GatePosition = RIGHT */ { if (balls[bn][WHEREINGATE] == 4) { if (board[r][c][GATEHOLDS] == BALL) { /* Move Back into START */ balls[bn][LOCATION] = INSTART; balls[bn][INDEXR] = 0; balls[bn][INDEXC] = ln; balls[bn][WHEREINGATE] = 2; } else { board[r][c][GATEHOLDS] = BALL; board[r][c][GATEBALLNUM] = bn; balls[bn][CHANGING] = FALSE; } } } } } else // WHEREINGATE = 1 or 2 { ln = balls[bn][INDEXC]; balls[bn][LOCATION] = INGATE; balls[bn][INDEXR] = 0; balls[bn][INDEXC] = (2 * (ln / 2)) + 1; if (balls[bn][WHEREINGATE] == 1) balls[bn][WHEREINGATE] = 4; else balls[bn][WHEREINGATE] = 0; /* This spot must not have an open gate, i think */ } break; case INGATE: r = balls[bn][INDEXR]; c = balls[bn][INDEXC]; switch (balls[bn][WHEREINGATE]) { case 0: /* Shouldn't be the case that Ball is sitting in gate */ case 4: board[r][c][GATEDOESHOLD] = -1; case 1: case 5: balls[bn][WHEREINGATE] += 1; break; case 2: case 6: /* First Test to see if next row/column has a GATEDOESHOLD if so pauseBall */ pauseBall = false; r1 = r + 1; ln = balls[bn][INDEXC] - 1; if (balls[bn][WHEREINGATE] == 6) ln = ln + 1; if ((r1 % 2) == 0) c1 = (2 * (ln / 2)) + 1; else c1 = (2 * ((ln+1) / 2)); if (r1 < numRows) { if (board[r1][c1][GATEDOESHOLD] != -1) pauseBall = true; } if (!pauseBall) { gp = board[r][c][GATEPOSITION]; if (board[r][c][GATEPOSITION] == LEFT) { if (ln == balls[bn][INDEXC]) { board[r][c][GATEPOSITION] = RIGHT; } } else { if (ln == (balls[bn][INDEXC] -1)) { board[r][c][GATEPOSITION] = LEFT; } } if (gp != board[r][c][GATEPOSITION]) { if (board[r][c][GATEHOLDS] == BALL) { addToEventList(board[r][c][GATEBALLNUM]); board[r][c][GATEHOLDS] = NOBALL; board[r][c][GATEBALLNUM] = -1; } } /* move to next row or bottom */ saver = balls[bn][INDEXR]; savec = balls[bn][INDEXC]; ln = balls[bn][INDEXC] - 1; if (balls[bn][WHEREINGATE] == 6) ln = ln + 1; if (r < numRows - 1) { // balls[bn][LOCATION] = INGATE; balls[bn][INDEXR] = r+1; if ((balls[bn][INDEXR] % 2) == 0) balls[bn][INDEXC] = (2 * (ln / 2)) + 1; else balls[bn][INDEXC] = (2 * ((ln+1) / 2)); if (ln == balls[bn][INDEXC]) balls[bn][WHEREINGATE] = 4; else balls[bn][WHEREINGATE] = 0; r = balls[bn][INDEXR]; c = balls[bn][INDEXC]; if (board[r][c][GATETYPE] == REGULAR) { if (board[r][c][GATEPOSITION] == LEFT) { if (balls[bn][WHEREINGATE] == 0) { if (board[r][c][GATEHOLDS] == BALL) { /* move Back to previous Gate */ balls[bn][INDEXR] = saver; balls[bn][INDEXC] = savec; balls[bn][WHEREINGATE] = 7; } else { board[r][c][GATEHOLDS] = BALL; board[r][c][GATEBALLNUM] = bn; balls[bn][CHANGING] = FALSE; } } else board[r][c][GATEDOESHOLD] = bn; } else /* GatePosition = RIGHT */ { if (balls[bn][WHEREINGATE] == 4) { if (board[r][c][GATEHOLDS] == BALL) { /* move Back to previous Gate */ balls[bn][INDEXR] = saver; balls[bn][INDEXC] = savec; balls[bn][WHEREINGATE] = 3; } else { board[r][c][GATEHOLDS] = BALL; board[r][c][GATEBALLNUM] = bn; balls[bn][CHANGING] = FALSE; } } else board[r][c][GATEDOESHOLD] = bn; } } } else /* move to bottom */ { balls[bn][LOCATION] = INBOTTOM; balls[bn][INDEXR] = 0; balls[bn][INDEXC] = ln; balls[bn][WHEREINGATE] = 0; } } break; case 3: case 7: pauseBall = false; r1 = r + 1; ln = balls[bn][INDEXC] - 1; if (balls[bn][WHEREINGATE] == 3) ln = ln - 1; else ln = ln + 2; if ((r1 % 2) == 0) c1 = (2 * (ln / 2)) + 1; else c1 = (2 * ((ln+1) / 2)); if (board[r1][c1][GATEDOESHOLD] != -1) pauseBall = true; if (!pauseBall) { ln = balls[bn][INDEXC] - 1; if (balls[bn][WHEREINGATE] == 3) ln = ln - 1; else ln = ln + 2; balls[bn][INDEXR] = r+1; if ((balls[bn][INDEXR] % 2) == 0) balls[bn][INDEXC] = (2 * (ln / 2)) + 1; else balls[bn][INDEXC] = (2 * ((ln+1) / 2)); if (ln == balls[bn][INDEXC]) balls[bn][WHEREINGATE] = 4; else balls[bn][WHEREINGATE] = 0; board[r1][c1][GATEDOESHOLD] = bn; /* This spot must not have an open gate, i think */ } break; } break; case INBOTTOM: bottomChanging = true; /* 0 */ ln = balls[bn][INDEXC]; /* 1 */ if (bottom[1][ln][0] == TRUE) { if (bottom[0][ln][0] != TRUE) { balls[bn][INDEXR] = 0; balls[bn][CHANGING] = FALSE; balls[bn][WHEREINGATE] = 0; bottom[0][ln][0] = TRUE; bottom[0][ln][1] = bn; } else { found = false; for (r = 1; (r >= 0) && (!found); r--) { for (c = 0; (c < numCols -2) && (!found); c++) { if (bottom[r][c][0] != TRUE) { balls[bn][INDEXR] = r; balls[bn][INDEXC] = c; balls[bn][WHEREINGATE] = r; balls[bn][CHANGING] = FALSE; bottom[r][c][0] = TRUE; bottom[r][c][1] = bn; found = true; } } } } } else // (bottom[1][ln][0] != TRUE) { balls[bn][INDEXR] = 1; balls[bn][INDEXC] = ln; balls[bn][WHEREINGATE] = 1; balls[bn][CHANGING] = FALSE; bottom[1][ln][0] = TRUE; bottom[1][ln][1] = bn; } break; } } } evt++; } if (!boardChanging) { if (bottomChanging) { boardChanging = true; found = false; for (r = 0; (r < 2) && (!found); r++) { for (c = numCols-2; (c >= 0) && (!found); c--) { if (bottom[r][c][0] == TRUE) { bn = bottom[r][c][1]; if (whoseTurn == HUMAN) { humanScore++; humanScoreF.setText("" + humanScore); } else { computerScore++; computerScoreF.setText("" + computerScore); } removeBallFromBoard(bn); /* Remove from eventList? */ bottom[r][c][0] = FALSE; bottom[r][c][1] = -1; found = true; playerScored++; } } } if (!found) bottomChanging = false; } } } public static void movetBalls() { int evt, ln, bn, r, c, saver, savec, r1, c1, gp; boolean found, pauseBall; tboardChanging = false; evt = 0; while (evt < eventListTop) { bn = eventList[evt]; /* Ball Number */ if (tballs[bn][CHANGING] == 1) { tboardChanging = true; switch (tballs[bn][LOCATION]) { case INSTART: if (tballs[bn][WHEREINGATE] == 0) { ln = tballs[bn][INDEXC]; tballs[bn][LOCATION] = INGATE; tballs[bn][INDEXR] = 0; tballs[bn][INDEXC] = (2 * (ln / 2)) + 1; if (ln == tballs[bn][INDEXC]) tballs[bn][WHEREINGATE] = 4; else tballs[bn][WHEREINGATE] = 0; r = tballs[bn][INDEXR]; c = tballs[bn][INDEXC]; if (tboard[r][c][GATETYPE] == REGULAR) { if (tboard[r][c][GATEPOSITION] == LEFT) { if (tballs[bn][WHEREINGATE] == 0) { if (tboard[r][c][GATEHOLDS] == BALL) { /* Move Back into START */ tballs[bn][LOCATION] = INSTART; tballs[bn][INDEXR] = 0; tballs[bn][INDEXC] = ln; tballs[bn][WHEREINGATE] = 1; } else { tboard[r][c][GATEHOLDS] = BALL; tboard[r][c][GATEBALLNUM] = bn; tballs[bn][CHANGING] = FALSE; } } } else /* GatePosition = RIGHT */ { if (tballs[bn][WHEREINGATE] == 4) { if (tboard[r][c][GATEHOLDS] == BALL) { /* Move Back into START */ tballs[bn][LOCATION] = INSTART; tballs[bn][INDEXR] = 0; tballs[bn][INDEXC] = ln; tballs[bn][WHEREINGATE] = 2; } else { tboard[r][c][GATEHOLDS] = BALL; tboard[r][c][GATEBALLNUM] = bn; tballs[bn][CHANGING] = FALSE; } } } } } else // WHEREINGATE = 1 or 2 { ln = tballs[bn][INDEXC]; tballs[bn][LOCATION] = INGATE; tballs[bn][INDEXR] = 0; tballs[bn][INDEXC] = (2 * (ln / 2)) + 1; if (tballs[bn][WHEREINGATE] == 1) tballs[bn][WHEREINGATE] = 4; else tballs[bn][WHEREINGATE] = 0; /* This spot must not have an open gate, i think */ } break; case INGATE: r = tballs[bn][INDEXR]; c = tballs[bn][INDEXC]; switch (tballs[bn][WHEREINGATE]) { case 0: /* Shouldn't be the case that Ball is sitting in gate */ case 4: tboard[r][c][GATEDOESHOLD] = -1; case 1: case 5: tballs[bn][WHEREINGATE] += 1; break; case 2: case 6: /* First Test to see if next row/column has a GATEDOESHOLD if so pauseBall */ pauseBall = false; r1 = r + 1; ln = tballs[bn][INDEXC] - 1; if (tballs[bn][WHEREINGATE] == 6) ln = ln + 1; if ((r1 % 2) == 0) c1 = (2 * (ln / 2)) + 1; else c1 = (2 * ((ln+1) / 2)); if (r1 < numRows) { if (tboard[r1][c1][GATEDOESHOLD] != -1) pauseBall = true; } if (!pauseBall) { gp = tboard[r][c][GATEPOSITION]; if (tboard[r][c][GATEPOSITION] == LEFT) { if (ln == tballs[bn][INDEXC]) { tboard[r][c][GATEPOSITION] = RIGHT; } } else { if (ln == (tballs[bn][INDEXC] -1)) { tboard[r][c][GATEPOSITION] = LEFT; } } if (gp != tboard[r][c][GATEPOSITION]) { if (tboard[r][c][GATEHOLDS] == BALL) { taddToEventList(tboard[r][c][GATEBALLNUM]); tboard[r][c][GATEHOLDS] = NOBALL; tboard[r][c][GATEBALLNUM] = -1; } } /* move to next row or bottom */ saver = tballs[bn][INDEXR]; savec = tballs[bn][INDEXC]; ln = tballs[bn][INDEXC] - 1; if (tballs[bn][WHEREINGATE] == 6) ln = ln + 1; if (r < numRows - 1) { // tballs[bn][LOCATION] = INGATE; tballs[bn][INDEXR] = r+1; if ((tballs[bn][INDEXR] % 2) == 0) tballs[bn][INDEXC] = (2 * (ln / 2)) + 1; else tballs[bn][INDEXC] = (2 * ((ln+1) / 2)); if (ln == tballs[bn][INDEXC]) tballs[bn][WHEREINGATE] = 4; else tballs[bn][WHEREINGATE] = 0; r = tballs[bn][INDEXR]; c = tballs[bn][INDEXC]; if (tboard[r][c][GATETYPE] == REGULAR) { if (tboard[r][c][GATEPOSITION] == LEFT) { if (tballs[bn][WHEREINGATE] == 0) { if (tboard[r][c][GATEHOLDS] == BALL) { /* move Back to previous Gate */ tballs[bn][INDEXR] = saver; tballs[bn][INDEXC] = savec; tballs[bn][WHEREINGATE] = 7; } else { tboard[r][c][GATEHOLDS] = BALL; tboard[r][c][GATEBALLNUM] = bn; tballs[bn][CHANGING] = FALSE; } } else tboard[r][c][GATEDOESHOLD] = bn; } else /* GatePosition = RIGHT */ { if (tballs[bn][WHEREINGATE] == 4) { if (tboard[r][c][GATEHOLDS] == BALL) { /* move Back to previous Gate */ tballs[bn][INDEXR] = saver; tballs[bn][INDEXC] = savec; tballs[bn][WHEREINGATE] = 3; } else { tboard[r][c][GATEHOLDS] = BALL; tboard[r][c][GATEBALLNUM] = bn; tballs[bn][CHANGING] = FALSE; } } else tboard[r][c][GATEDOESHOLD] = bn; } } } else /* move to bottom */ { tballs[bn][LOCATION] = INBOTTOM; tballs[bn][INDEXR] = 0; tballs[bn][INDEXC] = ln; tballs[bn][WHEREINGATE] = 0; } } break; case 3: case 7: pauseBall = false; r1 = r + 1; ln = tballs[bn][INDEXC] - 1; if (tballs[bn][WHEREINGATE] == 3) ln = ln - 1; else ln = ln + 2; if ((r1 % 2) == 0) c1 = (2 * (ln / 2)) + 1; else c1 = (2 * ((ln+1) / 2)); if (tboard[r1][c1][GATEDOESHOLD] != -1) pauseBall = true; if (!pauseBall) { ln = tballs[bn][INDEXC] - 1; if (tballs[bn][WHEREINGATE] == 3) ln = ln - 1; else ln = ln + 2; tballs[bn][INDEXR] = r+1; if ((tballs[bn][INDEXR] % 2) == 0) tballs[bn][INDEXC] = (2 * (ln / 2)) + 1; else tballs[bn][INDEXC] = (2 * ((ln+1) / 2)); if (ln == tballs[bn][INDEXC]) tballs[bn][WHEREINGATE] = 4; else tballs[bn][WHEREINGATE] = 0; tboard[r1][c1][GATEDOESHOLD] = bn; /* This spot must not have an open gate, i think */ } break; } break; case INBOTTOM: /* 0 */ ln = tballs[bn][INDEXC]; /* 1 */ if (tbottom[1][ln][0] == TRUE) { if (tbottom[0][ln][0] != TRUE) { tballs[bn][INDEXR] = 0; tballs[bn][CHANGING] = FALSE; tballs[bn][WHEREINGATE] = 0; tbottom[0][ln][0] = TRUE; tbottom[0][ln][1] = bn; } else { found = false; for (r = 1; (r >=0) && (!found); r--) { for (c = 0; (c < numCols -2) && (!found); c++) { if (tbottom[r][c][0] != TRUE) { tballs[bn][INDEXR] = r; tballs[bn][INDEXC] = c; tballs[bn][WHEREINGATE] = r; tballs[bn][CHANGING] = FALSE; tbottom[r][c][0] = TRUE; tbottom[r][c][1] = bn; found = true; } } } } } else // (tbottom[1][ln][0] != TRUE) { tballs[bn][INDEXR] = 1; tballs[bn][INDEXC] = ln; tballs[bn][WHEREINGATE] = 1; tballs[bn][CHANGING] = FALSE; tbottom[1][ln][0] = TRUE; tbottom[1][ln][1] = bn; } break; } } evt++; } } public static void addToEventList(int ballNum) { int e; boolean found = false; for (e = 0; (e < eventListTop) && (!found); e++) { if (eventList[e] == ballNum) found = true; } if (!found) eventList[eventListTop++] = ballNum; balls[ballNum][CHANGING] = TRUE; } public static void taddToEventList(int ballNum) { int e; boolean found = false; for (e = 0; (e < eventListTop) && (!found); e++) { if (eventList[e] == ballNum) found = true; } if (!found) eventList[eventListTop++] = ballNum; tballs[ballNum][CHANGING] = TRUE; } public static int getNumRows() /* 0:2 1:4 2:6 */ { return(2 + 2 * chRows.getSelectedIndex()); } public static int getNumCols() /* 0:4 1:6 2:8 3:10 4:12 5:14 (+1) */ { return(4 + (2 * chCols.getSelectedIndex()) + 1); } public static int getWinningScore() // 0 = 10, 1 = 25, 2 = 50 3 = 75 4 = 100) { int rv; rv = 10; switch (chWinningScore.getSelectedIndex()) { case 0: rv = 10; break; case 1: rv = 25; break; case 2: rv = 50; break; case 3: rv = 75; break; case 4: rv = 100; break; } return(rv); } public static int SkillLevel() { int i, rv; return(chSkill.getSelectedIndex() + 1); } public static int findComputerMove() { int rv; rv = 0; switch (SkillLevel()) { case 1: rv = numCols / 2; break; case 2: rv = (int) (Math.random() * (numCols - 1)); break; case 3: rv = findBestMove(); break; case 4: rv = findBestMoveHard(); break; } return(rv); } public static void clrTBottom() { int c; for (c = 0; c < numCols - 1; c++) { tbottom[0][c][0] = FALSE; tbottom[1][c][0] = FALSE; tbottom[0][c][1] = -1; tbottom[1][c][1] = -1; } } public static int findBestMove() { int r, c, i, pmoves[], possibleMove; int mcnt, rv, mtop; pmoves = new int[numCols]; rv = 0; for (c = 0; c < numCols - 1; c++) pmoves[c] = 0; for (possibleMove = 0; possibleMove < numCols - 1; possibleMove++) { for (r = 0; r < numRows; r++) for (c = 0; c < numCols; c++) for (i = 0; i < 5; i++) tboard[r][c][i] = board[r][c][i]; for (r = 0; r < MAXBALLS; r++) for (i = 0; i < 9; i++) tballs[r][i] = balls[r][i]; clrTBottom(); tballsOnboard = ballsOnboard; tfirstFreeBall = firstFreeBall; eventListTop = 0; addtBall(possibleMove); while (tboardChanging) movetBalls(); for (c = 0; c < numCols - 1; c++) { if (tbottom[0][c][0] == TRUE) pmoves[possibleMove]++; if (tbottom[1][c][0] == TRUE) pmoves[possibleMove]++; } } mcnt = -1; mtop = 0; for (c = 0; c < numCols - 1; c++) { if (pmoves[c] >= mcnt) { if (pmoves[c] > mcnt) { mcnt = pmoves[c]; mtop = 0; pmoves[mtop++] = c; } else /* == */ pmoves[mtop++] = c; } } rv = pmoves[mtop /2]; eventListTop = 0; return(rv); } public static boolean checkForWinner() { boolean rv; rv = false; winningScore = getWinningScore(); if (computerScore >= winningScore) { whoseTurnL.setText("I Win"); winner = COMPUTER; rv = true; } if (humanScore >= winningScore) { whoseTurnL.setText("You Win"); winner = HUMAN; rv = true; /* Line1400*/ } return(rv); } public static void setupSBalllist() { int i; for (i = 0; i < MAXSBALLLIST; i++) { sBallList[i].nextBall = i + 1; } sBallList[MAXSBALLLIST-1].nextBall = -1; firstFreeSBall = 0; } public static int getFreeSBall() { int rv; rv = firstFreeSBall; firstFreeSBall = sBallList[firstFreeSBall].nextBall; if (rv == -1) { statusMsg.setText("Out of Memory for SBalls"); System.out.println("getFreeSBall: Out of Memory for SBalls"); } sBallList[rv].nextBall = -1; return(rv); } public static void recycleSBallList(int ballNum) { sBallList[ballNum].nextBall = firstFreeSBall; firstFreeSBall = ballNum; } public static void recycleSBalls(int sBoardNum) { int sbp, nb; sbp = sBalls[sBoardNum]; while (sbp != -1) { nb = sBallList[sbp].nextBall; recycleSBallList(sbp); sbp = nb; } sBalls[sBoardNum] = -1; } public static void recycleSBoard(int sBoardNum) { recycleSBalls(sBoardNum); sBoardRef[sBoardNum][NEXTBOARD] = firstFreeSBoard; firstFreeSBoard = sBoardNum; } public static void setupSBoards() { int i; for (i = 0; i < MAXSBOARDS; i++) { sBoardRef[i][NEXTBOARD] = i + 1; sBalls[i] = -1; } sBoardRef[MAXSBOARDS - 1][NEXTBOARD] = i + 1; firstFreeSBoard = 0; } public static int getNewSBoard() { int rv; rv = firstFreeSBoard; firstFreeSBoard = sBoardRef[firstFreeSBoard][NEXTBOARD]; if (rv == -1) { statusMsg.setText("Out of Memory for SBoards"); System.out.println("getNewSBoard: Out of Memory for SBoards"); } return(rv); } public static int addToSballsFrom0(int sBall, int ballNum, int r, int c) { int newSBall, sbp; newSBall = getFreeSBall(); sBallList[newSBall].location = balls[ballNum][LOCATION]; sBallList[newSBall].ballColor = balls[ballNum][BALLCOLOR]; sBallList[newSBall].indexR = balls[ballNum][INDEXR]; sBallList[newSBall].indexC = balls[ballNum][INDEXC]; sBallList[newSBall].whereInGate = balls[ballNum][WHEREINGATE]; sBallList[newSBall].changing = (balls[ballNum][CHANGING] == TRUE); sBallList[newSBall].nextBall = -1; /* ptr to sBallList */ if (sBalls[sBall] == -1) sBalls[sBall] = newSBall; else { sbp = sBalls[sBall]; while (sBallList[sbp].nextBall != -1) sbp = sBallList[sbp].nextBall; sBallList[sbp].nextBall = newSBall; } return(newSBall); } public static int addToSballsFromT(int sBall, int tBallNum) { int newSBall, sbp; newSBall = getFreeSBall(); sBallList[newSBall].location = tballs[tBallNum][LOCATION]; sBallList[newSBall].ballColor = tballs[tBallNum][BALLCOLOR]; sBallList[newSBall].indexR = tballs[tBallNum][INDEXR]; sBallList[newSBall].indexC = tballs[tBallNum][INDEXC]; sBallList[newSBall].whereInGate = tballs[tBallNum][WHEREINGATE]; sBallList[newSBall].changing = (tballs[tBallNum][CHANGING] == TRUE); sBallList[newSBall].nextBall = -1; /* ptr to sBallList */ if (sBalls[sBall] == -1) sBalls[sBall] = newSBall; else { sbp = sBalls[sBall]; while (sBallList[sbp].nextBall != -1) { sbp = sBallList[sbp].nextBall; } sBallList[sbp].nextBall = newSBall; } return(newSBall); } public static void setupTreeNodeList() { int i; maxTreeNodesT = 0; for (i = 0; i < MAXTREENODES; i++) { treeNodes[i].nextNode = i + 1; } treeNodes[MAXTREENODES-1].nextNode = -1; firstFreeTreeNode = 0; } public static int getFreeTreeNode() { int rv; rv = firstFreeTreeNode; if (rv != -1) { maxTreeNodesT++; maxTreeNodes = Math.max(maxTreeNodes, maxTreeNodesT); firstFreeTreeNode = treeNodes[firstFreeTreeNode].nextNode; // if (firstFreeTreeNode == -1) // { statusMsg.setText("Out of Memory for TreeNodes"); // System.out.println("getFreeTreeNode: Out of Memory for TreeNodes"); // } } return(rv); } public static void recycleTreeNode(int treeNodePtr) { maxTreeNodesT--; treeNodes[treeNodePtr].nextNode = firstFreeTreeNode; firstFreeTreeNode = treeNodePtr; } public static void setupEndNodeList() { int i; endNodeStart = -1; endNodeEnd = -1; for (i = 0; i < MAXENDNODES; i++) { endNodes[i].prevNode = i - 1; endNodes[i].nextNode = i + 1; } endNodes[MAXENDNODES-1].nextNode = -1; firstFreeEndNode = 0; } public static int getFreeEndNode() { int rv; rv = firstFreeEndNode; firstFreeEndNode = endNodes[firstFreeEndNode].nextNode; if (rv == -1) { statusMsg.setText("Out of Memory for EndNodes"); System.out.println("getFreeEndNode: Out of Memory for EndNodes"); } return(rv); } public static void deleteFromEndNodeList(int delEndNode) { int nn, pn, sbp; sbp = treeNodes[endNodes[delEndNode].treeNodePtr].sBoardPtr; sBoardRef[sbp][COUNT]--; if (sBoardRef[sbp][COUNT] == 0) { recycleSBoard(sbp); } recycleTreeNode(endNodes[delEndNode].treeNodePtr); if (delEndNode == endNodeStart) endNodeStart = endNodes[delEndNode].nextNode; if (delEndNode == endNodeEnd) endNodeEnd = endNodes[delEndNode].prevNode; nn = endNodes[delEndNode].nextNode; pn = endNodes[delEndNode].prevNode; if (pn != -1) endNodes[pn].nextNode = nn; if (nn != -1) endNodes[nn].prevNode = pn; if (firstFreeEndNode != -1) endNodes[firstFreeEndNode].prevNode = delEndNode; endNodes[delEndNode].nextNode = firstFreeEndNode; endNodes[delEndNode].prevNode = -1; firstFreeEndNode = delEndNode; } public static void addToEndNodeList(int treeNodeNum) { int gf; gf = getFreeEndNode(); if (endNodeEnd == -1) { endNodeStart = gf; endNodeEnd = gf; endNodes[gf].prevNode = -1; endNodes[gf].nextNode = -1; } else { endNodes[endNodeEnd].nextNode = gf; endNodes[gf].prevNode = endNodeEnd; endNodes[gf].nextNode = -1; endNodeEnd = gf; } endNodes[gf].treeNodePtr = treeNodeNum; } public static void copyBoardToSBoard0() { int r,c,i, bn; for (r = 0; r < numRows; r++) { for (c = 0; c < numCols; c++) { for (i = 0; i < BOARDINFOCOLS; i++) sboard[0][r][c][i] = board[r][c][i]; if (board[r][c][GATEHOLDS] == BALL) { bn = addToSballsFrom0(0, board[r][c][GATEBALLNUM], r, c); sboard[0][r][c][GATEBALLNUM] = bn; } } } } public static void copyStoTBoard(int sBoardPtr) { int r,c,i, pb, tbn, bn; tballsOnboard = -1; pb = -1; tbn = -1; for (r = 0; r < numRows; r++) { for (c = 0; c < numCols; c++) { for (i = 0; i < BOARDINFOCOLS; i++) tboard[r][c][i] = sboard[sBoardPtr][r][c][i]; if (sboard[sBoardPtr][r][c][GATEHOLDS] == BALL) { bn = sboard[sBoardPtr][r][c][GATEBALLNUM]; tbn = getFreetBall(); if (tballsOnboard == -1) tballsOnboard = tbn; tboard[r][c][GATEBALLNUM] = tbn; tballs[tbn][LOCATION] = sBallList[bn].location; tballs[tbn][BALLCOLOR] = sBallList[bn].ballColor; tballs[tbn][INDEXR] = sBallList[bn].indexR; tballs[tbn][INDEXC] = sBallList[bn].indexC; tballs[tbn][WHEREINGATE] = sBallList[bn].whereInGate; tballs[tbn][CHANGING] = FALSE; tballs[tbn][NEXTBALL] = -1; tballs[tbn][PREVBALL] = pb; if (pb != -1) tballs[pb][NEXTBALL] = tbn; pb = tbn; } } } if (tbn != -1) tballs[tbn][PREVBALL] = pb; } public static void copyTtoSBoard(int sBoardPtr) { int r,c,i, bn; for (r = 0; r < numRows; r++) { for (c = 0; c < numCols; c++) { for (i = 0; i < BOARDINFOCOLS; i++) sboard[sBoardPtr][r][c][i] = tboard[r][c][i]; if (tboard[r][c][GATEHOLDS] == BALL) { bn = addToSballsFromT(sBoardPtr, tboard[r][c][GATEBALLNUM]); sboard[sBoardPtr][r][c][GATEBALLNUM] = bn; /* bn is in SBallList */ } } } } public static void clrTBalls() { int i; for (i = 0; i < MAXBALLS; i++) { tballs[i][PREVBALL] = i - 1; tballs[i][NEXTBALL] = i + 1; } tballs[MAXBALLS-1][NEXTBALL] = -1; tfirstFreeBall = 0; tballsOnboard = -1; /* Line1700 */ } public static void prtTboard() { int r,c, tb; for (r = 0; r < numRows; r++) { for (c = 0; c < numCols - 1; c++) { if (tboard[r][c][GATETYPE] == REGULAR) if (tboard[r][c][GATEPOSITION] == LEFT) System.out.println("R: " + r + " C: " + c + " LEFT"); else System.out.println("R: " + r + " C: " + c + " RIGHT"); if (tboard[r][c][GATEHOLDS] == BALL) System.out.println("BALL: " + tboard[r][c][GATEBALLNUM]); } } tb = tballsOnboard; while (tb != -1) { System.out.println("Ball: " + tb + "IndexR: " + tballs[tb][INDEXR] + "IndexC: " + tballs[tb][INDEXC]); tb = tballs[tb][NEXTBALL]; } } public static int findBestMoveHard() { int i, newTreeNode, newTreeNodeCnt, delEndNode, tnp, newSBoard; int nextPlayer, rv, mtop, mcnt, r, c, saveScore, t, q; int pmoves[], qmoves[], endNodePtr; boolean endNodesChanging, ballFound; int tm; String thinkMsg; pmoves = new int[numCols]; qmoves = new int[numCols]; for (c = 0; c < numCols - 1; c++) { pmoves[c] = 1000; qmoves[c] = -1; /* Delete nothing on first time through */ } setupTreeNodeList(); setupEndNodeList(); setupSBoards(); setupSBalllist(); copyBoardToSBoard0(); /* Also copys to sballs[0] */ firstFreeSBoard = 1; sBoardRef[0][NEXTBOARD] = -1; sBoardRef[0][COUNT] = 0; for (i = 0; i < numCols - 1; i++) { ballFound = false; if ((i % 2) == 0) { if ((board[0][i+1][GATEPOSITION] == LEFT) && (board[0][i+1][GATEHOLDS] == BALL)) ballFound = true; } else { if ((board[0][i][GATEPOSITION] == RIGHT) && (board[0][i][GATEHOLDS] == BALL)) ballFound = true; } if (!ballFound) { newTreeNode = getFreeTreeNode(); treeNodes[newTreeNode].sBoardPtr = 0; treeNodes[newTreeNode].firstMove = i; treeNodes[newTreeNode].laneNumber = i; treeNodes[newTreeNode].accScore = 0; treeNodes[newTreeNode].whoseTurn = COMPUTER; treeNodes[newTreeNode].done = false; treeNodes[newTreeNode].numMoves = 1; treeNodes[newTreeNode].step[0] = i; treeNodes[newTreeNode].score[0] = 0; sBoardRef[0][COUNT]++; addToEndNodeList(newTreeNode); } } endNodesChanging = true; tm = -1; thinkMsg = new String("Thinking"); while (endNodesChanging) { endNodesChanging = false; endNodePtr = endNodeStart; while (endNodePtr != -1) { delEndNode = -1; tnp = endNodes[endNodePtr].treeNodePtr; tm++; if ((tm % 500) == 0) { tm = 0; thinkMsg = new String("Thinking"); statusMsg.setText(thinkMsg); } else { if ((tm % 50) == 0) { thinkMsg = thinkMsg + "*"; statusMsg.setText(thinkMsg); } } if (!treeNodes[tnp].done) { endNodesChanging = true; clrTBalls(); copyStoTBoard(treeNodes[tnp].sBoardPtr); clrTBottom(); eventListTop = 0; addtBall(treeNodes[tnp].laneNumber); tboardChanging = true; while (tboardChanging) movetBalls(); saveScore = treeNodes[tnp].accScore; for (r = 0; r < 2; r++) { for (c = 0; c < numCols - 1; c++) { if (treeNodes[tnp].whoseTurn == COMPUTER) { if (tbottom[r][c][0] == TRUE) treeNodes[tnp].accScore++; } else { if (tbottom[r][c][0] == TRUE) treeNodes[tnp].accScore--; } } } treeNodes[tnp].score[treeNodes[tnp].numMoves-1] = treeNodes[tnp].accScore - saveScore; nextPlayer = 0; if (Math.abs(treeNodes[tnp].accScore - saveScore) < MINREPEATSCORE) { if (treeNodes[tnp].whoseTurn == COMPUTER) { nextPlayer = HUMAN; treeNodes[tnp].done = false; } else { treeNodes[tnp].done = true; } } else /* Next Move with same player */ { treeNodes[tnp].done = false; nextPlayer = treeNodes[tnp].whoseTurn; } if (!treeNodes[tnp].done) { newSBoard = getNewSBoard(); sBoardRef[newSBoard][COUNT] = 0; copyTtoSBoard(newSBoard); /* Copy newly modified board */ newTreeNode = 0; newTreeNodeCnt = 0; for (i = 0; (i < numCols - 1) && (newTreeNode != -1); i++) { ballFound = false; if ((i % 2) == 0) { if ((tboard[0][i+1][GATEPOSITION] == LEFT) && (tboard[0][i+1][GATEHOLDS] == BALL)) ballFound = true; } else { if ((tboard[0][i][GATEPOSITION] == RIGHT) && (tboard[0][i][GATEHOLDS] == BALL)) ballFound = true; } if (!ballFound) { newTreeNode = getFreeTreeNode(); if (newTreeNode != -1) { newTreeNodeCnt++; treeNodes[newTreeNode].sBoardPtr = newSBoard; treeNodes[newTreeNode].firstMove = treeNodes[tnp].firstMove; treeNodes[newTreeNode].laneNumber = i; treeNodes[newTreeNode].accScore = treeNodes[tnp].accScore; treeNodes[newTreeNode].whoseTurn = nextPlayer; treeNodes[newTreeNode].done = false; sBoardRef[newSBoard][COUNT]++; addToEndNodeList(newTreeNode); /* Temp Stuff */ for (t = 0; t < treeNodes[tnp].numMoves; t++) { treeNodes[newTreeNode].step[t] = treeNodes[tnp].step[t]; treeNodes[newTreeNode].score[t] = treeNodes[tnp].score[t]; } treeNodes[newTreeNode].numMoves = treeNodes[tnp].numMoves + 1; treeNodes[newTreeNode].step[treeNodes[tnp].numMoves] = i; /* End of temp stuff */ } } } if (newTreeNodeCnt == 0) /* Ran out of memory to assign more */ treeNodes[tnp].done = true; delEndNode = endNodePtr; /* Not needed this one was not done and all new nodes are assigned */ } else /* treeNodes[tnp].done, add it to Pmoves[] then delete it */ { delEndNode = endNodePtr; } } if (treeNodes[tnp].done) { if (treeNodes[tnp].accScore < pmoves[treeNodes[tnp].firstMove]) { pmoves[treeNodes[tnp].firstMove] = treeNodes[tnp].accScore; delEndNode = qmoves[treeNodes[tnp].firstMove]; /* Delete old one */ qmoves[treeNodes[tnp].firstMove] = tnp; /* Don't delete tnp, it need it for Qmove Summary */ } } endNodePtr = endNodes[endNodePtr].nextNode; if (delEndNode != -1) { deleteFromEndNodeList(delEndNode); /* also handles recycling */ } } } endNodePtr = endNodeStart; while (endNodePtr != -1) /* They should have all been deleted by now */ { tnp = endNodes[endNodePtr].treeNodePtr; /* Find Worst Case for firstMove */ if (treeNodes[tnp].accScore < pmoves[treeNodes[tnp].firstMove]) { pmoves[treeNodes[tnp].firstMove] = treeNodes[tnp].accScore; qmoves[treeNodes[tnp].firstMove] = tnp; } endNodePtr = endNodes[endNodePtr].nextNode; } // for (q = 0; q < numCols - 1; q++) // { tnp = qmoves[q]; // if (tnp != -1) // { System.out.println("TNP: " + tnp + " + Lane: " + q); // for (t = 0; t < treeNodes[tnp].numMoves; t++) // { System.out.println(" Move: " + t // + " Step: " + treeNodes[tnp].step[t] // + " Score: " + treeNodes[tnp].score[t]); // } // } } mcnt = -100; mtop = 0; for (c = 0; c < numCols - 1; c++) { // System.out.println("C: " + c + " pmoves[c]: " + pmoves[c]); if ((pmoves[c] >= mcnt) && (pmoves[c] != 1000)) { if (pmoves[c] > mcnt) { mcnt = pmoves[c]; mtop = 0; pmoves[mtop++] = c; } else /* == */ pmoves[mtop++] = c; } } rv = pmoves[mtop /2]; eventListTop = 0; statusMsg.setText(""); return(rv); } // public static void main(String args[]) { // Rocks rocksApp = null; // rocksApp = new Rocks("Rocks Application"); // rocksApp.resize(MAXSCREENX + MSGWIDTH, MAXSCREENY); // rocksApp.show(true); // } }