patternjavaMinor
Tic-Tac-Toe machine learning
Viewed 0 times
toetictaclearningmachine
Problem
I recently started getting into machine learning and I wanted to write a "beginner program" which would learn to play Tic Tac Toe. This code was inspired by a different program I saw, meaning some ideas (like saving the valid moves in a
You can either play against the AI or let it play against itself. You can choose whether or not to save the data in a text file via JSON. When playing against the AI, it uses that file as a base. It would be very nice to get some kind of feedback on this.
```
import com.google.gson.*;
import com.google.gson.reflect.*;
import java.util.*;
import java.lang.*;
import java.io.*;
import java.nio.file.*;
import java.nio.charset.Charset;
public class run{
private static ArrayList player1States;
private static ArrayList player1Choices;
private static ArrayList player1AccessedChoices;
private static ArrayList player1MovesChosen;
private static ArrayList player2States;
private static ArrayList player2Choices;
private static ArrayList player2AccessedChoices;
private static ArrayList player2MovesChosen;
private static ArrayList savedStates;
private static ArrayList savedChoices;
private static int maxMovesInChoiceString;
public static void main(String[] args)throws Exception{
Scanner s = new Scanner(System.in);
System.out.println("mode?(1 = PvAI / 2 = AItraining):");
int mode = s.nextInt();
while(mode != 1 && mode != 2){
System.out.println("Not a valid mode. Choose again(1 = PvAI / 2 = AItraining):");
mode = s.nextInt();
}
if(!fileExists("./", "AI.txt")){
saveResults(0);
}
if(mode==2){
System.out.println("Improve file?(1 = yes/ 2 = no)");
int ov = s.nextInt();
while(ov != 1 && ov != 2){
System.out.println("Not a valid choice. Choose again(1 = yes / 2 = no:");
ov = s.nextInt();
}
String) are not from me.You can either play against the AI or let it play against itself. You can choose whether or not to save the data in a text file via JSON. When playing against the AI, it uses that file as a base. It would be very nice to get some kind of feedback on this.
```
import com.google.gson.*;
import com.google.gson.reflect.*;
import java.util.*;
import java.lang.*;
import java.io.*;
import java.nio.file.*;
import java.nio.charset.Charset;
public class run{
private static ArrayList player1States;
private static ArrayList player1Choices;
private static ArrayList player1AccessedChoices;
private static ArrayList player1MovesChosen;
private static ArrayList player2States;
private static ArrayList player2Choices;
private static ArrayList player2AccessedChoices;
private static ArrayList player2MovesChosen;
private static ArrayList savedStates;
private static ArrayList savedChoices;
private static int maxMovesInChoiceString;
public static void main(String[] args)throws Exception{
Scanner s = new Scanner(System.in);
System.out.println("mode?(1 = PvAI / 2 = AItraining):");
int mode = s.nextInt();
while(mode != 1 && mode != 2){
System.out.println("Not a valid mode. Choose again(1 = PvAI / 2 = AItraining):");
mode = s.nextInt();
}
if(!fileExists("./", "AI.txt")){
saveResults(0);
}
if(mode==2){
System.out.println("Improve file?(1 = yes/ 2 = no)");
int ov = s.nextInt();
while(ov != 1 && ov != 2){
System.out.println("Not a valid choice. Choose again(1 = yes / 2 = no:");
ov = s.nextInt();
}
Solution
public class run{It's more common to give classes capitalized noun names. So
Runner rather run. But in this case, I'd tend to call it something like TicTacToe or TicTacToeGame. Although perhaps you are running inside some other framework that provides the name. In that case of course, you're stuck with it. private static ArrayList player1States;
private static ArrayList player1Choices;
private static ArrayList player1AccessedChoices;
private static ArrayList player1MovesChosen;
private static ArrayList player2States;
private static ArrayList player2Choices;
private static ArrayList player2AccessedChoices;
private static ArrayList player2MovesChosen;
private static ArrayList savedStates;
private static ArrayList savedChoices;
private static int maxMovesInChoiceString;Why are these
static? Half of these seem specific to a particular game. They should be fields of a game object, not class fields. Or two Player objects. It's also customary to make the variable type the interface rather than the implementation. So
List rather than ArrayList. This makes it easier to change the implementation in the future. mainYou have a lot of code in your
main method--five pages worth. Try to move some of that out into other methods. Possibly into different classes. int ov = s.nextInt();You use
ov several times. Presumably it has some meaning to you. Will it have the same meaning to you in six months? It's not obvious to me what it represents, so it's likely not to be obvious to other readers. If you write it out rather than abbreviating, it's often easier to remember. if (counter % 2 == 0){
while (true){
currentState = addMark(currentState, getNextMove(currentState, 2), 'O');
winner = checkWin(currentState);
if (winner != ' ') break;
currentState = addMark(currentState, getNextMove(currentState, 1), 'X');
winner = checkWin(currentState);
if (winner != ' ') break;
}
}else{
while (true){
currentState = addMark(currentState, getNextMove(currentState, 1), 'X');
winner = checkWin(currentState);
if (winner != ' ') break;
currentState = addMark(currentState, getNextMove(currentState, 2), 'O');
winner = checkWin(currentState);
if (winner != ' ') break;
}
}This seems longer than necessary. Consider
char player = (counter % 2 == 0) ? 'O' : 'X';
while (winner != ' ') {
currentState = addMark(currentState, getNextMove(currentState, (player == 'X') ? 1 : 2), player);
winner = checkWin(currentState);
player = (player == 'X') ? 'O' : 'X';
}No more writing everything four times.
You could get it shorter by changing
getNextMove to take a letter rather than a number. What are beads?
These methods would be easier to follow if they had names that better fit what they were doing.
char[] charArray = player1Choices.get(index).toCharArray();
charArray[x] = Integer.toString(move).charAt(0);
player1Choices.set(index, new String(charArray));Why do you keep swapping to and from a
String? Why not just make it a char array and only turn it into a String if you need one? Since arrays are mutable, you wouldn't even have to set the choice afterwards.Code Snippets
public class run{private static ArrayList<String> player1States;
private static ArrayList<String> player1Choices;
private static ArrayList<Integer> player1AccessedChoices;
private static ArrayList<Integer> player1MovesChosen;
private static ArrayList<String> player2States;
private static ArrayList<String> player2Choices;
private static ArrayList<Integer> player2AccessedChoices;
private static ArrayList<Integer> player2MovesChosen;
private static ArrayList<String> savedStates;
private static ArrayList<String> savedChoices;
private static int maxMovesInChoiceString;int ov = s.nextInt();if (counter % 2 == 0){
while (true){
currentState = addMark(currentState, getNextMove(currentState, 2), 'O');
winner = checkWin(currentState);
if (winner != ' ') break;
currentState = addMark(currentState, getNextMove(currentState, 1), 'X');
winner = checkWin(currentState);
if (winner != ' ') break;
}
}else{
while (true){
currentState = addMark(currentState, getNextMove(currentState, 1), 'X');
winner = checkWin(currentState);
if (winner != ' ') break;
currentState = addMark(currentState, getNextMove(currentState, 2), 'O');
winner = checkWin(currentState);
if (winner != ' ') break;
}
}char player = (counter % 2 == 0) ? 'O' : 'X';
while (winner != ' ') {
currentState = addMark(currentState, getNextMove(currentState, (player == 'X') ? 1 : 2), player);
winner = checkWin(currentState);
player = (player == 'X') ? 'O' : 'X';
}Context
StackExchange Code Review Q#119323, answer score: 4
Revisions (0)
No revisions yet.