HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Noughts and Crosses GUI game in Java - Part 1/2: AI

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
partjavagameandguinoughtscrosses

Problem

(See also Noughts and Crosses GUI game in Java - Part 2/2: GUI)

I was working on a GUI game of Noughts and Crosses, and this is what I finally got:

Unfortunately, the entire source code for the program does not fit in a single, so I have to try to split them in logical parts: this post is about Model and a little bit of Controller in MVC-pattern.

AIThread.java:

```
package net.coderodde.game.crosses;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;

/**
* This thread is responsible for running the AI.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Oct 7, 2015)
*/
class AIThread extends Thread {

private static final double LARGE = 1e10;

private final ConfigurationFrame configurationFrame;
private final GameFrame gameFrame;
private final JProgressBar progressBar;
private final TicTacToeGrid grid;
private final TicTacToePanel canvas;
private final MoveGenerator moveGenerator;
private final HeuristicFunction heuristicFunction;
private final int maximumDepth;

AIThread(ConfigurationFrame configurationFrame,
GameFrame gameFrame,
TicTacToeGrid grid,
TicTacToePanel canvas,
JProgressBar progressBar,
MoveGenerator moveGenerator,
HeuristicFunction heuristicFunction,
int maximumDepth) {
this.configurationFrame = configurationFrame;
this.gameFrame = gameFrame;
this.grid = grid;
this.canvas = canvas;
this.progressBar = progressBar;
this.moveGenerator = moveGenerator;
this.heuristicFunction = heuristicFunction;
this.maximumDepth = maximumDepth;
}

@Override
public void run() {
canvas.lock(); // Make sure that the user's clicks do not modify the
// grid.

Solution

Thread safety is pretty poor.

Instead of making threads I suggest you change the WorkerThreads into Callable and make the call() do only a single workItemList and return the best move.

Then you can submit it to a ExecutorService's invokeAll() which will distribute the work over several cores automatically. (You can get a ExecutorService using Executors.newCachedThreadPool())

This should be created and held by canvas to allow the executor and it threads to be reused as needed.

for (int i = 0; i  wt.getBestValue()) {
        bestValue = wt.getBestValue();
        bestState = wt.getBestState();
    }
}

Code Snippets

for (int i = 0; i < cores; ++i) {
    workItemLists.add(new WorkerCallable(workItemListCapacity,
                                         moveGenerator,
                                         heuristicFunction,
                                         maximumDepth,
                                         progressBar));
}

canvas.getExecutorService().invokeAll(workItemLists);

TicTacToeGrid bestState = workItemLists.get(0).getBestState();
double bestValue = workItemLists.get(0).getBestValue();


for (WorkerCallable wt : workItemLists) {
    if (bestValue > wt.getBestValue()) {
        bestValue = wt.getBestValue();
        bestState = wt.getBestState();
    }
}

Context

StackExchange Code Review Q#106915, answer score: 4

Revisions (0)

No revisions yet.