// Solution to Mastermind import java.util.*; public class Mastermind { public static Scanner in; public static int numCases; public static int l,c,n; // l = length, c = #colors, n = #guesses made public static String alphabet = "ABCDEFGHIJKLMNOPQRST"; public static char guesses[][]; // past guesses public static int b[]; // past responses (black) public static int w[]; // past responses (white) public static String[] possible; // list of possible solutions left public static int bwcount[][]; // scores for possible next guess public static void main(String[] args) { in = new Scanner(System.in); // numCases = in.nextInt(); numCases = myNextInt(); for (int i = 0; i < numCases; i++) { // l = in.nextInt(); l = myNextInt(); bwcount = new int[l+1][l+1]; // c = in.nextInt(); c = myNextInt(); // n = in.nextInt(); n = myNextInt(); guesses = new char[n][l]; b = new int[n]; w = new int[n]; for (int j = 0; j < n; j++) { // String g = in.nextString(); String g = myNextString(); for (int k = 0; k < l; k++) { guesses[j][k] = g.charAt(k); } b[j] = myNextInt(); w[j] = myNextInt(); } // System.out.println("Case " + (i+1)); solve(); } } // Solve one instance of mastermind. Approach is brute-force: // First, determine what solutions are still possible after the // guesses have been processed (at most 2000). Then for each of the // (at most 32768) possible next guesses, calculate how // many solutions are left in the worst case if that is the next guess. public static void solve() { String colors = alphabet.substring(0,c); // Create a list of all the possible combinations that // have not been ruled out by the set of guesses. ArrayList possible = new ArrayList(); String next = "AAAAAAAAAAAAAAAAAAAA".substring(0,l); while (!next.equals("")) { if (allowed(next,"")) { possible.add(next); } next = getNext(next); } // Now try every possible guess to see which one to make: next = "AAAAAAAAAAAAAAAAAAAA".substring(0,l); String bestSoFar = next; int minLeft = possible.size(); while (!next.equals("")) { for (int i = 0; i <= l; i++) for (int j = 0; j <= l; j++) bwcount[i][j] = 0; for (int i = 0; i < possible.size(); i++) { String g = possible.get(i); allowed(g,next); } bwcount[l][0] = 0; // DON'T COUNT SOLUTION AS A "REMAINING POSSIBILITY" int maxLeft = 0; for (int i = 0; i <= l; i++) for (int j = 0; j <= l; j++) if (bwcount[i][j] > maxLeft) maxLeft = bwcount[i][j]; if (maxLeft < minLeft) { minLeft = maxLeft; bestSoFar = next; } next = getNext(next); } System.out.println(bestSoFar+" "+minLeft); } // getNext -- return the lexicographically next string after "current" public static String getNext(String current) { char max = alphabet.charAt(c-1); int i = current.length()-1; while (i >= 0 && current.charAt(i) == max) i--; if (i >= 0) return current.substring(0,i)+(char)(1+(int)current.charAt(i))+ "AAAAAAAAAAAAAAAAAAAA".substring(0,current.length()-i-1); else return ""; } // allowed -- returns true if and only if the guess "next" is consistent // with responses to the guesses already made. public static boolean allowed(String next, String guess) { if (guess.equals("")) { for (int i = 0; i < n; i++) { // see if string "next" is compatible with the guesses made so far // for each letter in guess and for each letter in next, see if // there is a match; this will give us the "black pin" count: int black = 0; String temp = ""; String nxttemp = ""; for (int j = 0; j < l; j++) { if (guesses[i][j] == next.charAt(j)) { black++; } else { temp = temp+guesses[i][j]; nxttemp = nxttemp+next.charAt(j); } } if (black != b[i]) return false; int white = 0; for (int j = 0; j < temp.length(); j++) { String c = temp.substring(j,j+1); int loc; if ((loc = nxttemp.indexOf(c)) >= 0) { white++; nxttemp = nxttemp.substring(0,loc)+nxttemp.substring(loc+1); } } if (white != w[i]) return false; } return true; } int black = 0; String temp = ""; String nxttemp = ""; for (int j = 0; j < l; j++) { if (guess.charAt(j) == next.charAt(j)) { black++; } else { temp = temp+guess.charAt(j); nxttemp = nxttemp+next.charAt(j); } } int white = 0; for (int j = 0; j < temp.length(); j++) { String c = temp.substring(j,j+1); int loc; if ((loc = nxttemp.indexOf(c)) >= 0) { white++; nxttemp = nxttemp.substring(0,loc)+nxttemp.substring(loc+1); } } bwcount[black][white]++; return true; } // Modified "nextInt" to allow me to insert comments in the input file: public static int myNextInt() { String token = in.next(); while (token.charAt(0) == '#') { in.nextLine(); token = in.next(); } return Integer.parseInt(token); } // Modified "nextString" to allow me to insert comments in the input file: public static String myNextString() { String token = in.next(); while (token.charAt(0) == '#') { in.nextLine(); token = in.next(); } return token; } }