-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathMastermindTester.java
More file actions
169 lines (145 loc) · 5.23 KB
/
MastermindTester.java
File metadata and controls
169 lines (145 loc) · 5.23 KB
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// Copyright (c) Michael M. Magruder (https://github.com/mikemag)
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
import java.io.FileReader;
import java.util.Scanner;
// This program tests students' solutions to the Mastermind scoring problem.
//
// Create a new subclass of StudentAlgorithm and place the student's scoring function in
// scoreCodewords(), converting inputs and outputs as necessary. Then add a new instance of the
// subclass to the algos array in main(), and run.
//
// An example is provided, as are a couple of helpers to convert inputs to common forms.
public class MastermindTester {
private static final String testFilename = "mastermind_4p6c.txt";
//-------------------------------------------------------------------------------------------
// This is an example using a fake student and a broken algorithm.
static class ExampleStudent extends StudentAlgorithm {
public ExampleStudent() {
super("ExampleJoe"); // Put your name or GitHub username here
}
// Return black hits (correct color and position) in [0] and white hits (correct color but wrong
// position) in [1].
public int[] scoreCodewords(String codeword1, String codeword2) {
// This algorithm likes the codewords to be in byte arrays.
byte[] secretDigits = codeStringToBytes(codeword1);
byte[] guessDigits = codeStringToBytes(codeword2);
// Note: this algorithm is weird and broken on purpose. Don't spend much time, if any,
// studying it. Replace it with your own!!
int b = 0;
int w = 0;
int used = 0;
for (int i = 0; i < 4; i++) {
if (guessDigits[i] == secretDigits[i]) {
b++;
used |= 1 << i;
} else {
for (int j = 0; j < 4; j++) {
if ((used & 1 << j) == 0 && guessDigits[i] == secretDigits[j]) {
w++;
used |= 1 << j;
break;
}
}
}
}
// Return the hit counts in the order required!
return new int[] {b, w};
}
}
// Abstract class for students' algorithms. Implement this with the student's code in
// scoreCodewords().
static abstract class StudentAlgorithm {
private final String name;
private int totalRun;
private int totalFailed;
private String firstFailure;
public StudentAlgorithm(String name) {
this.name = name;
}
// Return black hits (correct color and position) in [0] and white hits (correct color but wrong
// position) in [1].
abstract public int[] scoreCodewords(String codeword1, String codeword2);
// Codeword conversion helper: turn it into an array of bytes
public static byte[] codeStringToBytes(String s) {
byte[] r = s.getBytes();
for (int i = 0; i < r.length; i++) {
r[i] -= '0';
}
return r;
}
// Codeword conversion helper: turn it into an array of ints
public static int[] codeStringToInts(String s) {
int[] r = new int[s.length()];
int i = 0;
for (char c : s.toCharArray()) {
r[i++] = c - '0';
}
return r;
}
// Run a single test and record the result
public void runTest(String word1, String word2, int expectedB, int expectedW) {
totalRun++;
try {
int[] r = scoreCodewords(word1, word2);
if (r[0] != expectedB || r[1] != expectedW) {
totalFailed++;
if (firstFailure == null) {
firstFailure = String.format("%s vs %s expected %d%d, got %d%d",
word1, word2, expectedB, expectedW, r[0], r[1]);
}
}
} catch (Exception e) {
totalFailed++;
if (firstFailure == null) {
firstFailure = String.format("%s vs %s expected %d%d, got %s",
word1, word2, expectedB, expectedW, e);
}
}
}
@Override
public String toString() {
String r = String.format("%30s: passed %6.2f%%",
name, (float) (totalRun - totalFailed) / totalRun * 100.0);
if (firstFailure != null) {
r += ", first failure: " + firstFailure;
}
return r;
}
}
private static void runTestsFromFile(StudentAlgorithm[] algos) {
System.out.format("Testing %d scoring algorithms with file %s...\n", algos.length, testFilename);
try {
int total = 0;
FileReader fr = new FileReader(testFilename);
Scanner lineScanner = new Scanner(fr);
lineScanner.nextLine(); // Drop the header row
while (lineScanner.hasNextLine()) {
total++;
String line = lineScanner.nextLine();
String[] testData = line.split(",");
for (StudentAlgorithm a : algos) {
a.runTest(
testData[0],
testData[1],
Integer.parseInt(testData[2]),
Integer.parseInt(testData[3]));
}
}
System.out.format("Done running %,d test cases.\n\n", total);
} catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
StudentAlgorithm[] algos = {
new ExampleStudent(),
// Add more student algorithms here
};
runTestsFromFile(algos);
for (StudentAlgorithm a : algos) {
System.out.println(a);
}
}
}