// Tutil.java package com.palserv.ttt; import java.util.*; /** The Tutil class is a "utility" class. The methods of this class act in support of the various classes in the Ttst.java file, which, along with this file, make up the "ttt" package. @author Peter Loeb */ /* it will make understanding this code easier if we draw a little picture which shows the "convention" I have used in naming the squares of the board: 1 | 2 | 3 - + - + - 4 | 5 | 6 - + - + - 7 | 8 | 9 */ public class Tutil { /* The tir[][] array is a list of all possible "three in a row" (winning combinations). */ int tir[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 1, 4, 7 }, { 2, 5, 8 }, { 3, 6, 9 }, { 1, 5, 9 }, { 3, 5, 7 }, }; /* The cmb[][] array is a list of all possible "double play" combinations. Within each group of five, the first number refers to the "common" square. The second and third numbers, along with the common square make a row which can be found in tir[][]. Likewise for the fourth and fifth numbers. Perhaps an example will help. Then again, perhaps not. In the third quintuplet, (3, 1, 2, 6, 9), the number "3" is the common square. We can form two rows: (3, 1, 2) and (3, 6, 9). */ int cmb[][] = { { 1, 2, 3, 4, 7 }, { 2, 1, 3, 5, 8 }, { 3, 1, 2, 6, 9 }, { 1, 2, 3, 5, 9 }, { 3, 1, 2, 5, 7 }, { 4, 5, 6, 1, 7 }, { 5, 4, 6, 2, 8 }, { 6, 4, 5, 3, 9 }, { 5, 4, 6, 1, 9 }, { 5, 4, 6, 3, 7 }, { 7, 8, 9, 1, 4 }, { 8, 7, 9, 2, 5 }, { 9, 7, 8, 3, 6 }, { 9, 7, 8, 1, 5 }, { 7, 8, 9, 3, 5 }, { 1, 4, 7, 5, 9 }, { 7, 1, 4, 3, 5 }, { 5, 4, 6, 1, 9 }, { 5, 4, 6, 3, 7 }, { 9, 3, 6, 1, 5 }, { 3, 6, 9, 5, 7 }, { 5, 1, 9, 3, 7 }, }; /* figure a move */ int figMov(String cps, String om) { /* arguments: cps - board om - opponent's color ("X" or "O") logic: return move to make */ int c = 0, mov = 0, b = 0, bm = 0; for (int i = 0; i < 9; i ++) { String ss = cps.substring(i,i + 1); if (ss .equals("B")) { c ++; // count blanks mov = i + 1; // capture move in case only one blank } else { b ++; // count non-blanks bm = i + 1; // capture square in case only non-blank } } if (c == 1) { return mov; } // only one blank; move there // if no non-blanks, then return a random number from 1-9 if (b == 0) { return (((int) Math.random() * 9) + 1); } if (b == 1) { // if only one non-blank /* if that move is in the center, then move in a random corner, else move in center */ if (bm == 5) { int t[] = { 1, 3, 7, 9 }; return t[(int) Math.random() * 4]; } else { return 5; } } String wm = getDiffCol(om); // if I have two in a row, fill it in mov = someInRow(wm, cps, 2); if (mov > 0) { return mov; } // if opp has two in a row, block it mov = someInRow(om, cps, 2); if (mov > 0) { return mov; } // check for "trick" position if (cps.equals("XBBBOBBBX") || cps.equals("BBXBOBXBB")) { int t[] = { 2, 4, 6, 8 }; return t[(int) Math.random() * 4]; } // if I have double play, go for it mov = doublePlay(wm, cps, "D"); if (mov > 0) { return mov;} // if opp has double play, block it mov = doublePlay(om, cps, "D"); if (mov > 0) { return mov;} // if I have double play on next move, go for it mov = doublePlay(wm, cps, "N"); if (mov > 0) { return mov;} // if opp has double play on next move, block it mov = doublePlay(om, cps, "N"); if (mov > 0) { return mov;} // if I have "one in row" then get another in row mov = someInRow(wm, cps, 1); if (mov > 0) { return mov;} // if opp has "one in row" then block mov = someInRow(om, cps, 1); if (mov > 0) { return mov;} // return random blank int j = 0; int t[] = new int[9]; for (int i = 0; i < 9; i ++) { if (cps.substring(i,i + 1).equals("B")) { t[j] = i + 1; j ++; } } if (j == 0) { System.err.println("figmov: no blanks"); System.exit(0); } return t[(int) Math.random() * j]; } // see if game is over and if so, who won int gamOvr(String xbor, String ocol) { /* arguments: xbor - board ocol - opponent's color ("X" or "O") return values: 0 - game not over yet 1 - opponent wins 2 - program wins 3 - tie; game is over */ if (xbor.length() != 9) { System.err.println("gamovr: board invalid length: "+xbor.length()); System.exit(1); } String s[] = new String[3]; String mycol = getDiffCol(ocol); int blnk = 0; for (int i = 0; i < 8; i ++) { for (int j = 0; j < 3; j ++) { s[j] = xbor.substring(tir[i][j] - 1, tir[i][j]); } if (s[0].equals(s[1]) && s[0].equals(s[2])) { if (s[0].equals(ocol)) { return 1; } if (s[0].equals(mycol)) { return 2; } } } for (int i = 0; i < 9; i ++) { if (xbor.substring(i,i + 1).equals("B")) { blnk ++; } } if (blnk == 0) { return 3; } return 0; } // apply a move to the board String aplyMov(String b, int m, String col) { /* arguments: b - board m - move (1-9) col - color ("X" or "O") logic: return the updated board with the move applied */ String br, suf; if (m < 1 || m > 9) { System.err.println("aplyMov: move out of range:" + m); System.exit(0); } // set br to the string up to the move if (m == 1) { br = ""; } else { br = b.substring(0, m - 1); } br += col; // add the move // set suf to the string after the move if (m == 9) { suf = ""; } else { suf = b.substring(m,9); } br += suf; // append to br return br; } // get the opposite color String getDiffCol(String s) { /* argument: s - color ("X" or "O") logic: return opposite color */ if (s.equals("X")) { return "O"; } else { if (s.equals("O")) { return "X"; } else { System.err.println("getDiffCol: invalid arg: "+s); System.exit(0); } } return " "; } // counts number of each color in an array of values int countem(String mycol, String oppcol, String vals[]) { /* arguments: mycol - color ("X" or "O") to look for oppcol - color ("X" or "O") to avoid vals - all other arguments; probably 2 or 5 logic: if any of the vals[] contain oppcol then return -1 return the number of mycol found in vals[] */ int c = 0; for (int i = 0; i < vals.length; i ++) { if (vals[i].equals(oppcol)) { return -1; } if (vals[i].equals(mycol)) { c ++; } } return c; } // returns move for a double play int getbx(int i, String s1, String s2, String s3, String s4) { /* arguments: i - combination number (index into cmb[]) s1 - contents of board for cmb[i][1] s2 - contents of board for cmb[i][2] s3 - contents of board for cmb[i][3] s4 - contents of board for cmb[i][4] logic: return move to make double play possibility We will call the contents of board for cmb[i][0] "s0", although this is not a variable used in this routine. Keep in mind that the nature of cmb[][] is such that s1 and s2 form a row with s0 and so do s3 and s4. When we enter this routine, we know that s0 is blank and one of s1-s4 has the coler we want. We want to find the row which has nothing filled in, yet. Then pick one from that row. */ if (s1.equals("B") && s2.equals("B")) { return cmb[i][((int) Math.random() * 2) + 1]; // cmb[i][1] or cmb[i][2] } else { if (s3.equals("B") && s4.equals("B")) { return cmb[i][((int) Math.random() * 2) + 3]; // cmb[i][3] or cmb[i][4] } else { System.err.println("error in getbx;"+i+s1+s2+s3+s4); System.exit(0); } } return -1; } /* find out how many of a color (with the rest blank) are in any row on the board */ int someInRow(String qm, String brd, int n) { /* arguments: qm - color ("X" or "O") brd - board n - requested number logic: Return the move number for a blank in a row which has the requested number filled */ String xm = getDiffCol(qm); String s[] = new String[3]; int b; for (int i = 0; i < 8; i ++) { b = 0; for (int j = 0; j < 3; j ++) { s[j] = brd.substring(tir[i][j] - 1, tir[i][j]); if (s[j].equals("B")) { b = tir[i][j]; } } if (countem(qm, xm, s) == n) { return b; } } return 0; } // find move for double play int doublePlay(String zm, String brd, String nd) { /* arguments: zm - "X" or "O"; which color we are looking at brd - board nd - "D" double play on this move or "N" double play on next move. logic: return move which will create double play */ String xm = getDiffCol(zm); String s[] = new String[5]; int c, d; for (int i = 0; i < 22; i ++) { for (int j = 0; j < 5; j ++) { s[j] = brd.substring(cmb[i][j] - 1, cmb[i][j]); } if (s[0].equals("B")) { if (nd.equals("D")) { c = countem(zm, xm, makArr2(s[1], s[2])); d = countem(zm, xm, makArr2(s[3], s[4])); if (c == 1 && d == 1) { return cmb[i][0]; } } else { c = countem(zm, xm, makArr4(s[1], s[2], s[3], s[4])); if (c == 1) { return getbx(i, s[1], s[2], s[3], s[4]); } } } } return 0; } // create an array out of two strings String[] makArr2(String s1, String s2) { String r[] = { s1, s2 }; return r; } // create an array out of four strings String[] makArr4(String s1, String s2, String s3, String s4) { String r[] = { s1, s2, s3, s4 }; return r; } }