Skip to content

Commit f18ef0a

Browse files
Merge pull request #920 from aldrinm/50_horserace
Java implementation of Horserace
2 parents 7793e08 + 929308e commit f18ef0a

File tree

2 files changed

+314
-1
lines changed

2 files changed

+314
-1
lines changed

50_Horserace/java/Horserace.java

Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
import java.util.ArrayList;
2+
import java.util.Arrays;
3+
import java.util.HashMap;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.Random;
7+
import java.util.Scanner;
8+
9+
/**
10+
* HORSERACE
11+
* <p>
12+
* Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)
13+
*/
14+
public class Horserace {
15+
16+
private static final String[] horseNames = {
17+
"JOE MAW",
18+
"L.B.J.",
19+
"MR.WASHBURN",
20+
"MISS KAREN",
21+
"JOLLY",
22+
"HORSE",
23+
"JELLY DO NOT",
24+
"MIDNIGHT"
25+
};
26+
public static final int MAX_DISTANCE = 28;
27+
public static final int NUM_HORSES = 8;
28+
29+
public static void main(String[] args) {
30+
printHeader();
31+
32+
Scanner scanner = new Scanner(System.in);
33+
Random random = new Random();
34+
35+
printHelp(scanner);
36+
37+
List<String> betNames = readBetNames(scanner);
38+
39+
boolean donePlaying = false;
40+
while (!donePlaying) {
41+
42+
int[] odds = generateOdds(random);
43+
int sumOdds = Arrays.stream(odds).sum();
44+
printOdds(sumOdds, odds);
45+
46+
Map<String, Bet> bets = takeBets(scanner, betNames);
47+
48+
var horsePositions = runRace(horseNames.length, sumOdds, odds, random);
49+
50+
printRaceResults(horsePositions, bets, sumOdds, odds);
51+
52+
donePlaying = readDonePlaying(scanner);
53+
}
54+
}
55+
56+
private static int[] generateOdds(Random random) {
57+
int[] odds = new int[NUM_HORSES];
58+
for (int i = 0; i < NUM_HORSES; i++) {
59+
odds[i] = (int) (10 * random.nextFloat() + 1);
60+
}
61+
return odds;
62+
}
63+
64+
private static void printOdds(int R, int[] D) {
65+
System.out.printf("%n%-28s%-14s%-14s%n%n", "HORSE", "NUMBER", "ODDS");
66+
for (int n = 0; n < horseNames.length; n++) {
67+
System.out.printf("%-28s% -14d%.6f :1%n", horseNames[n], n + 1, ((float) R / D[n]));
68+
}
69+
}
70+
71+
private static boolean readDonePlaying(Scanner scan) {
72+
System.out.println("DO YOU WANT TO BET ON THE NEXT RACE ?");
73+
System.out.print("YES OR NO? ");
74+
String choice = scan.nextLine();
75+
return !choice.equalsIgnoreCase("YES");
76+
}
77+
78+
/**
79+
* Simulate the race run, returning the final positions of the horses.
80+
*/
81+
private static int[] runRace(int numberOfHorses, int sumOdds, int[] odds, Random random) {
82+
int[] positionChange = new int[numberOfHorses];
83+
84+
System.out.println();
85+
System.out.println("1 2 3 4 5 6 7 8");
86+
87+
int totalDistance = 0;
88+
int[] currentPositions = new int[NUM_HORSES];
89+
int[] horsePositions = new int[NUM_HORSES];
90+
91+
while (totalDistance < MAX_DISTANCE) {
92+
System.out.println("XXXXSTARTXXXX");
93+
94+
for (int i = 0; i < numberOfHorses; i++) {
95+
horsePositions[i] = i + 1;
96+
positionChange[i] = calculatePositionChanges(sumOdds, odds[i], random);
97+
currentPositions[i] += positionChange[i];
98+
}
99+
100+
sortHorsePositionsBasedOnCurrent(currentPositions, horsePositions);
101+
102+
totalDistance = currentPositions[horsePositions[7] - 1];
103+
104+
boolean raceFinished = false;
105+
int i = 0;
106+
while (i < NUM_HORSES && !raceFinished) {
107+
int distanceToNextHorse = currentPositions[(horsePositions[i] - 1)] - (i < 1 ? 0 : currentPositions[(horsePositions[i - 1] - 1)]);
108+
if (distanceToNextHorse != 0) {
109+
int a = 0;
110+
while (a < distanceToNextHorse && !raceFinished) {
111+
System.out.println();
112+
if (currentPositions[horsePositions[i] - 1] >= MAX_DISTANCE) {
113+
raceFinished = true;
114+
}
115+
a++;
116+
}
117+
}
118+
119+
if (!raceFinished) {
120+
System.out.print(" " + horsePositions[i] + " "); // Print horse number
121+
}
122+
i++;
123+
}
124+
125+
if (!raceFinished) {
126+
//Print additional empty lines
127+
for (int a = 0; a < MAX_DISTANCE - totalDistance; a++) {
128+
System.out.println();
129+
}
130+
}
131+
132+
System.out.println("XXXXFINISHXXXX");
133+
System.out.println("\n");
134+
System.out.println("---------------------------------------------");
135+
System.out.println("\n");
136+
}
137+
138+
return horsePositions;
139+
}
140+
141+
/**
142+
* Sorts the horsePositions array in place, based on the currentPositions of the horses.
143+
* (bubble sort)
144+
*/
145+
private static void sortHorsePositionsBasedOnCurrent(int[] currentPositions, int[] horsePositions) {
146+
for (int l = 0; l < NUM_HORSES; l++) {
147+
int i = 0;
148+
/*
149+
uses a do-while instead of a for loop here, because in BASIC
150+
a FOR I=1 TO 0 causes at least one execution of the loop
151+
*/
152+
do {
153+
if (currentPositions[horsePositions[i] - 1] >= currentPositions[horsePositions[i + 1] - 1]) {
154+
int h = horsePositions[i];
155+
horsePositions[i] = horsePositions[i + 1];
156+
horsePositions[i + 1] = h;
157+
}
158+
i++;
159+
} while (i < (7 - l));
160+
}
161+
}
162+
163+
private static int calculatePositionChanges(int r, int d, Random random) {
164+
int positionChange = (int) (100 * random.nextFloat() + 1);
165+
166+
if (positionChange < 10) {
167+
positionChange = 1;
168+
} else {
169+
int s = (int) ((float) r / d + 0.5);
170+
if (positionChange < (s + 17)) {
171+
positionChange = 2;
172+
} else if (positionChange < s + 37) {
173+
positionChange = 3;
174+
} else if (positionChange < s + 57) {
175+
positionChange = 4;
176+
} else if (positionChange < s + 77) {
177+
positionChange = 5;
178+
} else if (positionChange < s + 92) {
179+
positionChange = 6;
180+
} else {
181+
positionChange = 7;
182+
}
183+
}
184+
185+
return positionChange;
186+
}
187+
188+
private static void printRaceResults(int[] m, Map<String, Bet> bets, int r, int[] d) {
189+
System.out.println("THE RACE RESULTS ARE:");
190+
int z9 = 1;
191+
for (int i = 7; i >= 0; i--) {
192+
int f = m[i];
193+
System.out.println();
194+
System.out.println(z9 + " PLACE HORSE NO. " + f + " AT " + (r / d[f - 1]) + ":1");
195+
z9++;
196+
}
197+
bets.forEach((betName, bet) -> {
198+
if (bet.horseNumber == m[7]) {
199+
int n = bet.horseNumber;
200+
System.out.println();
201+
System.out.printf("%s WINS $ %.2f %n", bet.betName, ((float) r / d[n]) * bet.amount);
202+
}
203+
});
204+
}
205+
206+
private static Map<String, Bet> takeBets(Scanner scanner, List<String> betNames) {
207+
Map<String, Bet> bets = new HashMap<>();
208+
System.out.println("--------------------------------------------------");
209+
System.out.println("PLACE YOUR BETS...HORSE # THEN AMOUNT");
210+
for (String betName : betNames) {
211+
boolean validInput = false;
212+
while (!validInput) {
213+
int horseNumber = readInt(betName, scanner);//Q in the original
214+
double betAmount = readDouble("?", scanner); //P in the original
215+
if (betAmount < 1 || betAmount > 100000) {
216+
System.out.println(" YOU CAN'T DO THAT!");
217+
} else {
218+
bets.put(betName, new Bet(betName, horseNumber, betAmount));
219+
validInput = true;
220+
}
221+
}
222+
}
223+
224+
return bets;
225+
}
226+
227+
private static void printHelp(Scanner scanner) {
228+
System.out.print("DO YOU WANT DIRECTIONS");
229+
230+
String directions = readChoice(scanner);
231+
232+
if (!directions.equalsIgnoreCase("NO")) {
233+
System.out.println("UP TO 10 MAY PLAY. A TABLE OF ODDS WILL BE PRINTED. YOU");
234+
System.out.println("MAY BET ANY + AMOUNT UNDER 100000 ON ONE HORSE.");
235+
System.out.println("DURING THE RACE, A HORSE WILL BE SHOWN BY ITS");
236+
System.out.println("NUMBER. THE HORSES RACE DOWN THE PAPER!");
237+
System.out.println();
238+
}
239+
}
240+
241+
private static String readChoice(Scanner scanner) {
242+
System.out.print("? ");
243+
return scanner.nextLine();
244+
}
245+
246+
private static int readInt(String prompt, Scanner scanner) {
247+
System.out.print(prompt);
248+
while (true) {
249+
System.out.print("? ");
250+
String input = scanner.nextLine();
251+
try {
252+
return Integer.parseInt(input);
253+
} catch (NumberFormatException e) {
254+
System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE");
255+
}
256+
}
257+
}
258+
259+
private static double readDouble(String prompt, Scanner scanner) {
260+
System.out.print(prompt);
261+
while (true) {
262+
System.out.print("? ");
263+
String input = scanner.nextLine();
264+
try {
265+
return Double.parseDouble(input);
266+
} catch (NumberFormatException e) {
267+
System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE");
268+
}
269+
}
270+
}
271+
272+
private static List<String> readBetNames(Scanner scanner) {
273+
int c = readInt("HOW MANY WANT TO BET ", scanner);
274+
System.out.println("WHEN ? APPEARS,TYPE NAME");
275+
List<String> names = new ArrayList<>();
276+
for (int i = 1; i <= c; i++) {
277+
System.out.print("? ");
278+
names.add(scanner.nextLine());
279+
}
280+
281+
return names;
282+
}
283+
284+
private static void printHeader() {
285+
System.out.println(" HORSERACE");
286+
System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
287+
System.out.println("\n\n");
288+
System.out.println("WELCOME TO SOUTH PORTLAND HIGH RACETRACK");
289+
System.out.println(" ...OWNED BY LAURIE CHEVALIER");
290+
}
291+
292+
private static class Bet {
293+
String betName;
294+
int horseNumber;
295+
double amount;
296+
297+
public Bet(String betName, int horseNumber, double amount) {
298+
this.betName = betName;
299+
this.horseNumber = horseNumber;
300+
this.amount = amount;
301+
}
302+
303+
@Override
304+
public String toString() {
305+
return "Bet{" +
306+
"betName='" + betName + '\'' +
307+
", horseNumber=" + horseNumber +
308+
", amount=" + amount +
309+
'}';
310+
}
311+
}
312+
}
313+

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up
127127
| 47_Hi-Lo | x | | x | x | x | x | x | x | x | x |
128128
| 48_High_IQ | x | x | x | | | | x | | | x |
129129
| 49_Hockey | x | | x | | | | x | | | x |
130-
| 50_Horserace | x | | x | | | | | | x | x |
130+
| 50_Horserace | x | x | x | | | | | | x | x |
131131
| 51_Hurkle | x | x | x | | | x | x | x | x | x |
132132
| 52_Kinema | x | x | x | | | x | x | x | | x |
133133
| 53_King | x | | x | | | | x | | x | x |

0 commit comments

Comments
 (0)