mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 10:54:51 +00:00
start to reversi logic
This commit is contained in:
@@ -95,7 +95,7 @@ public abstract class GameCanvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(Color color, int cell) {
|
public void drawDot(Color color, int cell) {
|
||||||
final float x = cells[cell].x() + gapSize;
|
final float x = cells[cell].x() + gapSize;
|
||||||
final float y = cells[cell].y() + gapSize;
|
final float y = cells[cell].y() + gapSize;
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ public abstract class GameCanvas {
|
|||||||
final float height = cells[cell].height() - gapSize * 2;
|
final float height = cells[cell].height() - gapSize * 2;
|
||||||
|
|
||||||
graphics.setFill(color);
|
graphics.setFill(color);
|
||||||
graphics.fillRect(x, y, width, height);
|
graphics.fillOval(x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resize(int width, int height) {
|
public void resize(int width, int height) {
|
||||||
|
|||||||
36
app/src/main/java/org/toop/app/canvas/ReversiCanvas.java
Normal file
36
app/src/main/java/org/toop/app/canvas/ReversiCanvas.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package org.toop.app.canvas;
|
||||||
|
|
||||||
|
import javafx.scene.layout.Background;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import org.toop.game.Game;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class ReversiCanvas extends GameCanvas{
|
||||||
|
private Game.Move[] mostRecentLegalMoves;
|
||||||
|
public ReversiCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked) {
|
||||||
|
super(color, width, height, 8, 8, 10, true, onCellClicked);
|
||||||
|
drawStartingDots();
|
||||||
|
}
|
||||||
|
public void drawStartingDots(){
|
||||||
|
drawDot(Color.BLACK,28);
|
||||||
|
drawDot(Color.WHITE,36);
|
||||||
|
drawDot(Color.BLACK,35);
|
||||||
|
drawDot(Color.WHITE,27);
|
||||||
|
}
|
||||||
|
public void drawLegalMoves(Game.Move[] moves){
|
||||||
|
mostRecentLegalMoves = moves;
|
||||||
|
for(Game.Move move : moves){
|
||||||
|
drawDot(Color.RED,move.position());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void removeLegalMoves(){
|
||||||
|
if (mostRecentLegalMoves != null){
|
||||||
|
for(Game.Move move : mostRecentLegalMoves){
|
||||||
|
drawDot(Color.GRAY,move.position()); //todo get current background color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mostRecentLegalMoves = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import org.toop.app.layer.Container;
|
|||||||
import org.toop.app.layer.Layer;
|
import org.toop.app.layer.Layer;
|
||||||
import org.toop.app.layer.NodeBuilder;
|
import org.toop.app.layer.NodeBuilder;
|
||||||
import org.toop.app.layer.containers.VerticalContainer;
|
import org.toop.app.layer.containers.VerticalContainer;
|
||||||
|
import org.toop.app.layer.layers.game.ReversiLayer;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
@@ -24,7 +25,7 @@ public final class MainLayer extends Layer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
final var othelloButton = NodeBuilder.button(AppContext.getString("othello"), () -> {
|
final var othelloButton = NodeBuilder.button(AppContext.getString("othello"), () -> {
|
||||||
App.activate(new MultiplayerLayer());
|
App.activate(new ReversiLayer());
|
||||||
});
|
});
|
||||||
|
|
||||||
final var creditsButton = NodeBuilder.button(AppContext.getString("credits"), () -> {
|
final var creditsButton = NodeBuilder.button(AppContext.getString("credits"), () -> {
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.toop.app.layer.layers.game;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import org.toop.app.App;
|
||||||
|
import org.toop.app.canvas.ReversiCanvas;
|
||||||
|
import org.toop.app.layer.*;
|
||||||
|
import org.toop.app.layer.containers.HorizontalContainer;
|
||||||
|
import org.toop.app.layer.containers.VerticalContainer;
|
||||||
|
import org.toop.app.layer.layers.MainLayer;
|
||||||
|
import org.toop.game.reversi.Reversi;
|
||||||
|
import org.toop.game.reversi.ReversiAI;
|
||||||
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
|
public class ReversiLayer extends Layer{
|
||||||
|
private ReversiCanvas canvas;
|
||||||
|
private Reversi reversi;
|
||||||
|
private ReversiAI reversiAI;
|
||||||
|
public ReversiLayer(){
|
||||||
|
super("bg-secondary"); //make reversiboard background dark green
|
||||||
|
|
||||||
|
canvas = new ReversiCanvas(Color.GREEN,(App.getHeight() / 100) * 75, (App.getHeight() / 100) * 75, (cell) -> {
|
||||||
|
IO.println("clicked reversi cell: "+cell);
|
||||||
|
});
|
||||||
|
reversi = new Reversi() ;
|
||||||
|
reversiAI = new ReversiAI();
|
||||||
|
|
||||||
|
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reload() {
|
||||||
|
popAll();
|
||||||
|
canvas.resize((App.getHeight() / 100) * 75, (App.getHeight() / 100) * 75);
|
||||||
|
|
||||||
|
for (int i = 0; i < reversi.board.length; i++) {
|
||||||
|
final char value = reversi.board[i];
|
||||||
|
|
||||||
|
if (value == 'B') {
|
||||||
|
canvas.drawDot(Color.BLACK, i);
|
||||||
|
} else if (value == 'W') {
|
||||||
|
canvas.drawDot(Color.WHITE, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final var backButton = NodeBuilder.button(AppContext.getString("back"), () -> {
|
||||||
|
App.activate(new MainLayer());
|
||||||
|
});
|
||||||
|
|
||||||
|
final Container controlContainer = new VerticalContainer(5);
|
||||||
|
controlContainer.addNodes(backButton);
|
||||||
|
|
||||||
|
final Container informationContainer = new HorizontalContainer(15);
|
||||||
|
|
||||||
|
addContainer(controlContainer, Pos.BOTTOM_LEFT, 2, -2, 0, 0);
|
||||||
|
addContainer(informationContainer, Pos.TOP_LEFT, 2, 2, 0, 0);
|
||||||
|
addGameCanvas(canvas, Pos.CENTER, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@ public abstract class Game {
|
|||||||
|
|
||||||
public record Move(int position, char value) {}
|
public record Move(int position, char value) {}
|
||||||
|
|
||||||
|
public record Score(int player1Score, int player2Score) {}
|
||||||
|
|
||||||
public static final char EMPTY = (char)0;
|
public static final char EMPTY = (char)0;
|
||||||
|
|
||||||
public final int rowSize;
|
public final int rowSize;
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
package org.toop.game.othello;
|
|
||||||
|
|
||||||
import org.toop.game.TurnBasedGame;
|
|
||||||
|
|
||||||
public final class Othello extends TurnBasedGame {
|
|
||||||
Othello() {
|
|
||||||
super(8, 8, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Move[] getLegalMoves() {
|
|
||||||
return new Move[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public State play(Move move) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package org.toop.game.othello;
|
|
||||||
|
|
||||||
import org.toop.game.AI;
|
|
||||||
import org.toop.game.Game;
|
|
||||||
|
|
||||||
public final class OthelloAI extends AI<Othello> {
|
|
||||||
@Override
|
|
||||||
public Game.Move findBestMove(Othello game, int depth) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
74
game/src/main/java/org/toop/game/reversi/Reversi.java
Normal file
74
game/src/main/java/org/toop/game/reversi/Reversi.java
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package org.toop.game.reversi;
|
||||||
|
|
||||||
|
import org.toop.game.Game;
|
||||||
|
import org.toop.game.TurnBasedGame;
|
||||||
|
import org.toop.game.tictactoe.TicTacToe;
|
||||||
|
|
||||||
|
public final class Reversi extends TurnBasedGame {
|
||||||
|
private int movesTaken;
|
||||||
|
public static final char FIRST_MOVE = 'B';
|
||||||
|
|
||||||
|
|
||||||
|
public Reversi() {
|
||||||
|
super(8, 8, 2);
|
||||||
|
addStartPieces();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Reversi(Reversi other) {
|
||||||
|
super(other);
|
||||||
|
this.movesTaken = other.movesTaken;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void addStartPieces() {
|
||||||
|
board[27] = 'W';
|
||||||
|
board[28] = 'B';
|
||||||
|
board[35] = 'B';
|
||||||
|
board[36] = 'W';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Move[] getLegalMoves() {
|
||||||
|
char[][] boardGrid = makeBoardAGrid();
|
||||||
|
if(currentTurn == 1){
|
||||||
|
|
||||||
|
}
|
||||||
|
return new Move[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public char[][] makeBoardAGrid() {
|
||||||
|
char[][] boardGrid = new char[8][8];
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
boardGrid[i / 8][i % 8] = board[i];
|
||||||
|
}
|
||||||
|
return boardGrid;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public State play(Move move) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getCurrentPlayer() {
|
||||||
|
if (currentTurn == 0){
|
||||||
|
return 'B';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'W';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Game.Score getScore(){
|
||||||
|
int player1Score = 0, player2Score = 0;
|
||||||
|
for (int count = 0; count < 63; count++) {
|
||||||
|
if (board[count] == 'W') {
|
||||||
|
player1Score += 1;
|
||||||
|
}
|
||||||
|
if (board[count] == 'B') {
|
||||||
|
player2Score += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Game.Score(player1Score, player2Score);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
11
game/src/main/java/org/toop/game/reversi/ReversiAI.java
Normal file
11
game/src/main/java/org/toop/game/reversi/ReversiAI.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package org.toop.game.reversi;
|
||||||
|
|
||||||
|
import org.toop.game.AI;
|
||||||
|
import org.toop.game.Game;
|
||||||
|
|
||||||
|
public final class ReversiAI extends AI<Reversi> {
|
||||||
|
@Override
|
||||||
|
public Game.Move findBestMove(Reversi game, int depth) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
79
game/src/test/java/org/toop/game/tictactoe/ReversiTest.java
Normal file
79
game/src/test/java/org/toop/game/tictactoe/ReversiTest.java
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package org.toop.game.tictactoe;
|
||||||
|
|
||||||
|
import org.toop.game.Game;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.toop.game.reversi.Reversi;
|
||||||
|
import org.toop.game.reversi.ReversiAI;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class ReversiTest {
|
||||||
|
private Reversi game;
|
||||||
|
private ReversiAI ai;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setup() {
|
||||||
|
game = new Reversi();
|
||||||
|
ai = new ReversiAI();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCorrectStartPiecesPlaced() {
|
||||||
|
assertNotNull(game);
|
||||||
|
assertEquals('W',game.board[27]);
|
||||||
|
assertEquals('B',game.board[28]);
|
||||||
|
assertEquals('B',game.board[35]);
|
||||||
|
assertEquals('W',game.board[36]);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
void testGetLegalMovesAtStart() {
|
||||||
|
Game.Move[] moves = game.getLegalMoves();
|
||||||
|
assertNotNull(moves);
|
||||||
|
assertTrue(moves.length > 0);
|
||||||
|
assertEquals(new Game.Move(19,'B'),moves[0]);
|
||||||
|
assertEquals(new Game.Move(26,'B'),moves[0]);
|
||||||
|
assertEquals(new Game.Move(37,'B'),moves[0]);
|
||||||
|
assertEquals(new Game.Move(44,'B'),moves[0]);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
void testMakeValidMoveFlipsPieces() {
|
||||||
|
game.play(new Game.Move(19, 'B'));
|
||||||
|
assertEquals('B', game.board[19]);
|
||||||
|
assertEquals('B', game.board[27], "Piece should have flipped to B");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
void testMakeInvalidMoveDoesNothing() {
|
||||||
|
char[] before = game.board.clone();
|
||||||
|
game.play(new Game.Move(0, 'B'));
|
||||||
|
assertArrayEquals(before, game.board, "Board should not change on invalid move");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
void testTurnSwitchesAfterValidMove() {
|
||||||
|
char current = game.getCurrentPlayer();
|
||||||
|
game.play(game.getLegalMoves()[0]);
|
||||||
|
assertNotEquals(current, game.getCurrentPlayer(), "Player turn should switch after a valid move");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
void testCountScoreCorrectly() {
|
||||||
|
Game.Score score = game.getScore();
|
||||||
|
assertEquals(2, score.player1Score()); // Black
|
||||||
|
assertEquals(2, score.player2Score()); // White
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
void testAISelectsLegalMove() {
|
||||||
|
Game.Move move = ai.findBestMove(game,4);
|
||||||
|
assertNotNull(move);
|
||||||
|
assertTrue(containsMove(game.getLegalMoves(),move), "AI should always choose a legal move");
|
||||||
|
}
|
||||||
|
private boolean containsMove(Game.Move[] moves, Game.Move move) {
|
||||||
|
for (Game.Move m : moves) {
|
||||||
|
if (m.equals(move)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user