board) { int playerDiscs = board.countDiscs(player); int opponentDiscs = board.countDiscs(board.getOpponent(player)); return playerDiscs - opponentDiscs; } public static void scoreMoves(ArrayList<OthelloMove> moves) { for (OthelloMove mv : moves) { mv.setEval(squareValues[mv.getIdx()]); } } public static float eval(int player, OthelloBoard board) { float value = 0.0f; int phase = board.getPhase(); if (phase == OthelloBoard.PHASE_OPENING) { value = 100 * mobilityDiff(player, board) + 100 * potentialMobilityDiff(player, board) + 800 * cornerSquaresDiff(player, board) - 200 * badXSquaresDiff(player, board) - 200 * badCSquaresDiff(player, board); } else if (phase == OthelloBoard.PHASE_MIDGAME) { value = 100 * mobilityDiff(player, board) + 100 * potentialMobilityDiff(player, board) + 900 * cornerSquaresDiff(player, board) - 250 * badXSquaresDiff(player, board) - 200 * badCSquaresDiff(player, board); } else if (phase == OthelloBoard.PHASE_ENDGAME) { value = discsDiff(player, board); } else { System.out.println("Erro na heuristica: fase indeterminada."); } return value; }}TestandoJa temos as pecas necessarias para criar a engine, o que nos faltae implementar um game loop e criar uma GUI simples. A classeOthelloPiece nos ajuda a desenhar as pecas. Segue a classe:import javax.swing.*;import java.awt.*;import java.awt.geom.*;public class OthelloPiece{ private int color; private int size; public OthelloPiece(int color, int size) { this.color = color; this.size = size; } public void draw(Graphics g, int x, int y) { Color col = null; if (color == OthelloBoard.WHITE) col = Color.white; else col = Color.black; g.setColor(col); g.fillOval(x, y, size, size); }} A classe OthelloPanel abaixo implementa a GUI e o game loop:import javax.swing.*;import java.awt.*;import java.awt.event.*;import java.util.ArrayList;import java.util.Random;import java.util.concurrent.*;public class OthelloPanel extends JPanel implements Runnable{ private int cellSize; private int pieceSize; private OthelloBoard board = null; private int humanColor; private int cpuColor; private boolean waitingInput = false; private boolean finished = false; public static final int HUMAN = 100; public static final int CPU = 200; private int lastMoveIndex; public OthelloPanel(int cellSize, int startPlayer) { board = new OthelloBoard(); if (startPlayer == HUMAN) this.humanColor = OthelloBoard.BLACK; else this.humanColor = OthelloBoard.WHITE; this.cpuColor = 3 - this.humanColor; this.cellSize = cellSize; this.pieceSize = (int)(cellSize * 0.75); this.setDoubleBuffered(true); int screenSize = (2 + OthelloBoard.BOARD_SIZE) * cellSize; this.setPreferredSize(new Dimension(screenSize, screenSize)); this.addMouseWatcher(); UIManager.put("OptionPane.noButtonText", "N\u00E3o"); UIManager.put("OptionPane.yesButtonText", "Sim"); } private boolean isFinished() { return board.checkEnd(); } private boolean isHumanTurn() { return humanColor == board.getCurrentPlayer(); } private void doLogic() { if (isFinished()) { finished = true; return; } //verifica somente uma vez se existem lances validos //caso existam, espera por input //caso contrario, faz lance fantasma if (isHumanTurn()) { if (waitingInput) return; ArrayList<OthelloMove> moves = board.getAllMoves(humanColor); if (moves.get(0).getFlipSquares() == null) { board.makeMove(moves.get(0)); waitingInput = false; } else { waitingInput = true; } } //dispacha uma nova Thread minimax, e espera a busca terminar else { int maxDepth = 6; boolean solve = board.getPhase() == OthelloBoard.PHASE_ENDGAME; CountDownLatch signal = new CountDownLatch(1); MinimaxOthello AI = new MinimaxOthello(board.cloneBoard(), maxDepth, signal, solve); new Thread(AI).start(); try { signal.await(); } catch(InterruptedException exception) { exception.printStackTrace(); } OthelloMove mv = AI.getBestFound(); board.makeMove(mv); //repaint(); lastMoveIndex = mv.getIdx(); System.out.println("AI move: " + mv.getIdx()); } } private void doInput(int index) { if (isHumanTurn()) { int[] cells = board.getCells(); if (cells[index] != OthelloBoard.EMPTY) return; ArrayList<Integer> flips = board.getFlips(index, humanColor); if (flips.size() > 0) { OthelloMove mv = new OthelloMove(); mv.setFlipSquares(flips); mv.setIdx(index); mv.setPlayer(humanColor); board.makeMove(mv); lastMoveIndex = index;