/* * Shell from Sun's GraphApplet.java 1.3 98/03/18 * TicTac.java - start of 3d TicTacToe * Version 0 generation * Step 1, Set upcode for drawing a 4 x 4 x 3-d board. * Step 2, Identify in an array all possible 4-in-a-row lines * (there are a total of 76). I used a spreadsheet to calculate * positions. * Step 3, set up mouse-listner for position input. * Step 4, set up position reporting * Step 5, set up strategy * Step 6, final clean-up * Version 1. Enhancement * Change "Human" value to 8 (allow bit manipulation) * Show comment * Test for draw * Show scores --Planned: test for forks */ import java.awt.*; import java.awt.event.*; import java.awt.Graphics.*; import java.net.*; import java.applet.*; public class TicTac extends Applet implements MouseListener { /* Complete List of 4-in a row cubes A spreadsheet can be used as a CASE tool. */ int AllWins[][] = { /* horizontal */ {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}, {12, 13, 14, 15}, {16, 17, 18, 19}, {20, 21, 22, 23}, {24, 25, 26, 27}, {28, 29, 30, 31}, {32, 33, 34, 35}, {36, 37, 38, 39}, {40, 41, 42, 43}, {44, 45, 46, 47}, {48, 49, 50, 51}, {52, 53, 54, 55}, {56, 57, 58, 59}, {60, 61, 62, 63}, /* Vertical */ { 0, 4, 8, 12}, { 1, 5, 9, 13}, { 2, 6, 10, 14}, { 3, 7, 11, 15}, {16, 20, 24, 28}, {17, 21, 25, 29}, {18, 22, 26, 30}, {19, 23, 27, 31}, {32, 36, 40, 44}, {33, 37, 41, 45}, {34, 38, 42, 46}, {35, 39, 43, 47}, {48, 52, 56, 60}, {49, 53, 57, 61}, {50, 54, 58, 62}, {51, 55, 59, 63}, /* Front to Back */ { 0, 16, 32, 48}, { 1, 17, 33, 49}, { 2, 18, 34, 50}, { 3, 19, 35, 51}, { 4, 20, 36, 52}, { 5, 21, 37, 53}, { 6, 22, 38, 54}, { 7, 23, 39, 55}, { 8, 24, 40, 56}, { 9, 25, 41, 57}, {10, 26, 42, 58}, {11, 27, 43, 59}, {12, 28, 44, 60}, {13, 29, 45, 61}, {14, 30, 46, 62}, {15, 31, 47, 63}, /* Diagnols within Planes */ { 0, 5, 10, 15}, {16, 21, 26, 31}, {32, 37, 42, 47}, {48, 53, 58, 63}, { 3, 6, 9, 12}, {19, 22, 25, 28}, {35, 38, 41, 44}, {51, 54, 57, 60}, { 0, 20, 40, 60}, { 1, 21, 41, 61}, { 2, 22, 42, 62}, { 3, 23, 43, 63}, {12, 24, 36, 48}, {13, 25, 37, 49}, {14, 26, 38, 50}, {15, 27, 39, 51}, { 0, 17, 34, 51}, { 4, 21, 38, 55}, { 8, 25, 42, 59}, {12, 29, 46, 63}, { 3, 18, 33, 48}, { 7, 22, 37, 52}, {11, 26, 41, 56}, {15, 30, 45, 60}, /* And the Body Diagnals */ { 0, 21, 42, 63}, { 3, 22, 41, 60}, {12, 25, 38, 51}, {15, 26, 37, 48} }; /* The boxes are numbered 0..63, arranged x, y, z - with x the most significant. values are 0 - vacant; 1 - computer; 8 - human. */ /* WhatWins lists the win numbers associated with each box */ int WhatWins[][] = { {00, 16, 32, 48, 56, 64, 72}, {00, 17, 33, 57}, {00, 18, 34, 58}, {00, 19, 35, 52, 59, 68, 73}, {01, 16, 36, 65}, {01, 17, 37, 48}, {01, 18, 38, 52}, {01, 19, 39, 69}, {02, 16, 40, 66}, {02, 17, 41, 52}, {02, 18, 42, 48}, {02, 19, 43, 70}, {03, 16, 44, 52, 60, 67, 74}, {03, 17, 45, 61}, {03, 18, 46, 62}, {03, 19, 47, 48, 63, 71, 75}, {04, 20, 32, 49}, {04, 21, 33, 64}, {04, 22, 34, 68}, {04, 23, 35, 53}, {05, 20, 36, 56}, {05, 21, 37, 49, 57, 65, 72}, {05, 22, 38, 53, 58, 69, 73}, {05, 23, 39, 59}, {06, 20, 40, 60}, {06, 21, 41, 53, 61, 66, 74}, {06, 22, 42, 49, 62, 70, 75}, {06, 23, 43, 63}, {07, 20, 44, 53}, {07, 21, 45, 67}, {07, 22, 46, 71}, {07, 23, 47, 49}, { 8, 24, 32, 50}, { 8, 25, 33, 68}, { 8, 26, 34, 64}, { 8, 27, 35, 54}, { 9, 24, 36, 60}, { 9, 25, 37, 50, 61, 69, 75}, { 9, 26, 38, 54, 62, 65, 74}, { 9, 27, 39, 63}, {10, 24, 40, 56}, {10, 25, 41, 54, 57, 70, 73}, {10, 26, 42, 50, 58, 66, 72}, {10, 27, 43, 59}, {11, 24, 44, 54}, {11, 25, 45, 71}, {11, 26, 46, 67}, {11, 27, 47, 50}, {12, 28, 32, 51, 60, 68, 75}, {12, 29, 33, 61}, {12, 30, 34, 62}, {12, 31, 35, 55, 63, 64, 74}, {13, 28, 36, 69}, {13, 29, 37, 51}, {13, 30, 38, 55}, {13, 31, 39, 65}, {14, 28, 40, 70}, {14, 29, 41, 55}, {14, 30, 42, 51}, {14, 31, 43, 66}, {15, 28, 44, 55, 56, 71, 73}, {15, 29, 45, 57}, {15, 30, 46, 58}, {15, 31, 47, 51, 59, 67, 72} }; int SquareContents[]= new int[64]; /* Game result code is 0 - in-play; 1 - computer won; 8 - human won LastMove is the box-number of the computer's last turn Scores (human, computer, draw) */ int GameResult = 0, LastMove, GameScore[]={0,0,0}; String Comment = "Lets Play"; /* Projx returns the x coordinate of the point (x, y, z) onto the screen */ int Projx(int x, int y, int z) { int w = getSize().width / 8; return (w + w * x + (w * 76 * z / 100));} /* Projy returns the y coordinate of the point (x, y, z) onto the screen */ int Projy(int x, int y, int z) { int h = getSize().height / 6; return (h + h * y + (h * z /5)); } /** * Initialize the applet. Clear the board. */ public void init() { int i; addMouseListener(this); GameResult = 0; for (i=0;i<64;i++) SquareContents[i] = 0; } /* Draw four 4x4 boards. Use the projection functions to show the 3-d image */ public void DrawGrid(Graphics g) { int d1, d2, d3; for (d1=0; d1 < 4; d1++){ for (d2=0; d2 < 5; d2++) { g.drawLine(Projx(d2,d1,0), Projy(d2,d1,0), Projx(d2, d1, 4), Projy(d2, d1, 4)); //g.drawLine(Projx(d1,0, d2), Projy(d1,0, d2), // Projx(d1, 4, d2), Projy(d1, 4, d2)); g.drawLine(Projx(0, d1,d2), Projy(0,d1,d2), Projx(4, d1, d2), Projy(4, d1, d2)); }} } /* Draw the chips that mark the moves, Human in blue Computer in red, with the latest move marked with a white dot winning row shows as green If the game is over, prompt for rematch */ public void DrawGame(Graphics g) { int i, wx, wy, wz; for (i=0;i<64;i++) {wx = i/16; wy = (i % 16) / 4; wz = i % 4; if (SquareContents[i] == 8) {g.setColor(Color.blue); g.fillOval(Projx(wx, wy, wz)+20, Projy(wx, wy, wz), 40,20); } if (SquareContents[i] == 1) {g.setColor(Color.red); g.fillOval(Projx(wx, wy, wz)+20, Projy(wx, wy, wz), 40,20); if (i == LastMove) {g.setColor(Color.white); g.fillOval(Projx(wx, wy, wz)+30, Projy(wx, wy, wz)+5, 20,10);} } if (SquareContents[i] == 2) {g.setColor(Color.green); g.fillOval(Projx(wx, wy, wz)+20, Projy(wx, wy, wz), 40,20);} } g.setColor(Color.black); g.drawString(Comment, 20,40); g.drawString("Human:" + GameScore[0] + ", Computer:" + GameScore[1] + ", Draw:" + GameScore[2], 20,60); if (GameResult != 0) {g.setColor(Color.blue); g.drawRect(1,1,20,20); g.drawString("<-- Click Top Left Corner for Rematch", 20,20);} } /* Standard routine just invokes drawing the board and the chips */ public void paint(Graphics g) { DrawGrid(g); DrawGame(g); } /* Calculate an answering move */ void doAnswerMove(){ int sumvals[] = new int[76]; int blrow; int BestMoves [] = { // IMHO, the most valuable squares are the center, 21,22, 25, 26, 37, 38, 41, 42, // the corners, 0, 3, 12, 15, 48, 60, 63, // and the edges. 2, 3, 4, 7, 8, 11, 13, 14, 16, 19, 28, 31, 32, 35, 44, 47, 50, 51, 52, 55, 56, 59, 61, 62}; int i, j, k, num; // work variables /* Calculate the score for each of the sets of 4-in-a row boxes, number of computer's chips plus 8 times the number of human's chips. Note that where both human and computer have chips, neither can win. */ for (i=0;i<76;i++) {sumvals[i] = 0; for (j=0;j<4;j++) sumvals[i] += SquareContents[AllWins[i][j]]; } /* First check, did I loose? Look for 4 of the opponent's boxes in a row. If you find such a condition, paint all four green and conceed. */ for (i=0;i<76;i++) {if (sumvals[i] == 32) {for (j=0;j<4;j++) SquareContents[AllWins[i][j]] = 2; GameResult = 8; play(getCodeBase(), "audio/Congrats.wav"); Comment = "You won!"; GameScore[0]++; return; } } /* Second check, did I win? Look for 3 of the computer's boxes in a row. If you find this opportunity, paint the row green and say 'i won'*/ for (i=0;i<76;i++) {if (sumvals[i] == 3) {for (j=0;j<4;j++) SquareContents[AllWins[i][j]] = 2; GameResult = 1; play(getCodeBase(), "audio/IWon.wav"); Comment = "I won!"; GameScore[1]++; return; } } /* Check for a drawn game */ for (i=0, blrow=0;i<76;i++) {if (((sumvals[i] & 7) != 0) && ((sumvals[i] & 56) !=0)) blrow++;} if (blrow > 75) {GameResult = 64; Comment = "Drawn game."; GameScore[2]++; return; } /* Next, check if the opponent has 3 in a row, if so, BLOCK */ for (i=0;i<76;i++) {if (sumvals[i] == 24) {for (j=0;j<4;j++) {if (SquareContents[AllWins[i][j]] == 0) {SquareContents[AllWins[i][j]] = 1; LastMove = AllWins[i][j]; // mark last Comment = "Blocking."; return; } } } } /* check for a fork */ for (i=0;i<64;i++) {if (SquareContents[i] == 0) {for (j=0, num=0;j< WhatWins[i].length;j++) if (sumvals[(WhatWins[i][j])] == 2) num++; if (num > 1) {SquareContents[i] = 1; LastMove = i; Comment = "I have a fork!"; return; } } } /* check for opponent's fork */ for (i=0;i<64;i++) {if (SquareContents[i] == 0) {for (j=0, num=0;j< WhatWins[i].length;j++) if (sumvals[(WhatWins[i][j])] == 16) num++; if (num > 1) {SquareContents[i] = 1; LastMove = i; Comment = "Blocking your fork!"; return; } } } /* Next, check if I have two in a row, if so, insert a third for a threat */ for (i=0;i<76;i++) {if (sumvals[i] == 2) {for (j=0;j<4;j++) {if (SquareContents[AllWins[i][j]] == 0) {SquareContents[AllWins[i][j]] = 1; LastMove = AllWins[i][j]; // mark last Comment = "Watch out :-)"; return; } } } } /* Nothing significant, pick a space from the "best" */ for (i=0; i<40; i++) {if (SquareContents[BestMoves[i]] == 0) {SquareContents[BestMoves[i]] = 1; LastMove = BestMoves[i]; // mark last Comment = "It's a move."; return;} } } /** * The user has clicked in the applet. Figure out where * and see if a legal move is possible. If it is a legal * move, respond with a legal move (if possible). */ public void mouseReleased(MouseEvent e) { int h = getSize().height / 6; int w = getSize().width / 8; int wkx,wkrem, wky, wkz; int x = e.getX(); int y = e.getY(); /* invert the projection in Projx and Projy this uses a bit too much brute force (any suggestions for finesse?) */ wky = y/h - 1; wkrem = y % h; wkz = (5 * wkrem) / h; wkx = ((x - (w * 76 * wkrem / 20/h) ) / w) - 1; // Check the validity, on the board and not occupied int boxno = 16*wkx + 4 * wky + wkz; if ((wkx> -1) && (wkx < 4) && (wky> -1) && (wky < 4) && (wkz> -1) && (wkz < 4) && (SquareContents[boxno] == 0) && (GameResult == 0)) {SquareContents[boxno] = 8; doAnswerMove(); repaint();} if ((GameResult != 0) && (y < 20) && (x < 20)) {init(); repaint();} } /* place holders for other mouse events */ public void mousePressed(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public String getAppletInfo() { return "Plays 3-d Tic Tac Toe."; } }