Skip to content

Commit

Permalink
fix: change game to run on an event loop and to have a state
Browse files Browse the repository at this point in the history
  • Loading branch information
jahrim committed Mar 7, 2023
1 parent 4613491 commit bf7d57b
Show file tree
Hide file tree
Showing 51 changed files with 783 additions and 233 deletions.
2 changes: 1 addition & 1 deletion chess/src/main/scala/io/github/chess/Main.scala
Expand Up @@ -12,7 +12,7 @@ import io.github.chess.engine.adapters.Adapter
import io.github.chess.engine.model.game.ChessGame
import io.github.chess.engine.ports.ChessPort
import io.github.chess.engine.services.ChessService
import io.github.chess.util.debug.Logger
import io.github.chess.util.scala.debug.Logger
import io.vertx.core.{Future, Promise, Vertx}

/** The main application. */
Expand Down
Expand Up @@ -6,8 +6,8 @@
*/
package io.github.chess.application

import io.github.chess.util.scala.option.OptionExtension.getOrThrow
import io.github.chess.engine.ports.ChessPort
import io.github.chess.util.option.OptionExtension.getOrThrow
import scalafx.stage.Stage

/** The context of this application. */
Expand Down
Expand Up @@ -10,12 +10,13 @@ import io.github.chess.application.{ChessApplicationComponent, ChessApplicationC
import io.github.chess.engine.model.board.{ChessBoard, Position}
import io.github.chess.engine.model.moves.{CaptureMove, CastlingMove, DoubleMove, Move}
import io.github.chess.engine.model.pieces.Piece
import io.github.chess.util.stateful.StatefulSystem
import io.github.chess.engine.model.game.ChessGameState.*
import io.github.chess.application.viewcontroller.fxutils.FXUtils.*
import io.github.chess.application.viewcontroller.controllers.template.Controller
import io.github.chess.application.viewcontroller.controllers.ChessBoardController.State
import io.github.chess.application.viewcontroller.controllers.ChessBoardController.State.*
import io.github.chess.application.viewcontroller.pages.components.{CellView, PieceView}
import io.github.chess.util.general.StatefulSystem
import javafx.scene.input.MouseEvent
import javafx.scene.layout.GridPane
import javafx.scene.layout.Pane
Expand Down Expand Up @@ -48,8 +49,9 @@ case class ChessBoardController private (
/** Retrieves the state of the chess engine service and shows it. */
def repaint(): Unit =
this.context.chessEngineProxy.getState.onComplete {
case Success(state) => this.repaint(state.chessBoard.pieces)
case Failure(exception) => throw exception
case Success(Running(state)) => this.repaint(state.chessBoard.pieces)
case Failure(exception) => throw exception
case _ =>
}

/**
Expand Down Expand Up @@ -96,15 +98,15 @@ case class ChessBoardController private (
* Performs the selection of a cell if it contains a piece of the playing team.
* Deselects the selected one otherwise.
*
* @param cell the specified cell
* @param clickedCell the specified cell
*/
private def performCheckedSelection(clickedCell: CellView): Unit =
this.context.chessEngineProxy.getState.onComplete {
case Success(value) =>
case Success(Running(status)) =>
Platform.runLater {
this.chessBoardBelief.get(clickedCell.position) match
case Some(piece) if piece.team == value.currentTurn => this.selectCell(clickedCell)
case _ => enter(NoneSelected)
case Some(piece) if piece.team == status.currentTurn => this.selectCell(clickedCell)
case _ => enter(NoneSelected)
}
case _ =>
}
Expand Down
Expand Up @@ -8,11 +8,12 @@ package io.github.chess.application.viewcontroller.controllers

import io.github.chess.engine.events.{
GameOverEvent,
PieceMovedEvent,
BoardChangedEvent,
PromotingPawnEvent,
TimePassedEvent
}
import io.github.chess.engine.model.configuration.Player
import io.github.chess.engine.model.game.ChessGameState.*
import io.github.chess.engine.model.game.GameOverCause
import io.github.chess.engine.model.pieces.PromotionPiece
import io.github.chess.application.ChessApplication.{start, given}
Expand Down Expand Up @@ -62,14 +63,14 @@ class GameController(override protected val stage: Stage)(using
this.surrenderButton.onMouseClicked = _ =>
this.currentPlayerBelief.foreach { this.context.chessEngineProxy.surrender(_) }
initView()
context.chessEngineProxy.subscribe[PieceMovedEvent](onPieceMoved)
context.chessEngineProxy.subscribe[BoardChangedEvent](onPieceMoved)
context.chessEngineProxy.subscribe[TimePassedEvent](onTimePassed)
context.chessEngineProxy.subscribe[GameOverEvent](onGameOver)
context.chessEngineProxy.subscribe[PromotingPawnEvent](onPromotingPawn)

private def initView(): Unit =
context.chessEngineProxy.getState.onComplete {
case Success(status) =>
case Success(Running(status)) =>
Platform.runLater {
this.currentPlayerBelief = Some(status.gameConfiguration.player(status.currentTurn))
chessBoardController.repaint(status.chessBoard.pieces)
Expand All @@ -80,9 +81,10 @@ class GameController(override protected val stage: Stage)(using
lastMoveText.setText("N/A")
}
case Failure(exception) => throw exception
case _ =>
}

private def onPieceMoved(event: PieceMovedEvent): Unit =
private def onPieceMoved(event: BoardChangedEvent): Unit =
Platform.runLater(() =>
this.currentPlayerBelief = Some(event.currentPlayer)
currentTurnText.setText(s"${event.currentPlayer.name} -> ${event.currentPlayer.team}")
Expand Down Expand Up @@ -128,6 +130,3 @@ class GameController(override protected val stage: Stage)(using
} // TODO add orElse to ifPresent
case None =>
}

// TODO: get access to the proxy for the chess engine service (as a given constructor parameter?)
// TODO: handle surrender logic
Expand Up @@ -6,8 +6,8 @@
*/
package io.github.chess.application.viewcontroller.pages.components

import io.github.chess.util.scala.number.NumberExtension.sameParityAs
import io.github.chess.engine.model.board.{Position, Rank}
import io.github.chess.util.number.NumberExtension.*
import io.github.chess.application.viewcontroller.configuration.InterfaceConfiguration.{
Colors,
Images
Expand Down
Expand Up @@ -6,7 +6,7 @@
*/
package io.github.chess.application.viewcontroller.pages.template

import io.github.chess.util.option.OptionExtension.getOrThrow
import io.github.chess.util.scala.option.OptionExtension.getOrThrow
import io.github.chess.application.viewcontroller.controllers.template.FXMLController
import io.github.chess.application.viewcontroller.pages.template.{Page, PageWithController}
import javafx.fxml.FXMLLoader
Expand Down
Expand Up @@ -11,8 +11,8 @@ import io.github.chess.engine.model.configuration.Player
import io.github.chess.engine.model.moves.Move
import io.github.chess.engine.model.pieces.Piece

/** Represents the event in which a piece was moved on the board. */
trait PieceMovedEvent extends Event:
/** Represents the event triggered when the chess board has changed. */
trait BoardChangedEvent extends Event:

/**
* The player that should be playing next.
Expand All @@ -21,7 +21,7 @@ trait PieceMovedEvent extends Event:
def currentPlayer: Player

/**
* The disposition of the board after the move was performed.
* The disposition of the board after it was changed.
* @return Current disposition of the board
*/
def boardDisposition: Map[Position, Piece]
Expand All @@ -32,25 +32,25 @@ trait PieceMovedEvent extends Event:
*/
def lastMove: Move

/** Object helper for PieceMovedEvent. */
object PieceMovedEvent:
/** Object helper for BoardChangedEvent. */
object BoardChangedEvent:

/**
* Creates an instance of the Piece Moved Event.
* Creates an instance of the Board Changed Event.
* @param currentPlayer the player that should be playing next
* @param boardDisposition current disposition of the board
* @param lastMove last move that was performed on the board
* @return The event containing all the changes applied due to the move
* @return The event containing all the changes applied to the board
*/
def apply(
currentPlayer: Player,
boardDisposition: Map[Position, Piece],
lastMove: Move
): PieceMovedEvent =
PieceMovedEventImpl(currentPlayer, boardDisposition, lastMove)
): BoardChangedEvent =
BoardChangedEventImpl(currentPlayer, boardDisposition, lastMove)

private case class PieceMovedEventImpl(
private case class BoardChangedEventImpl(
override val currentPlayer: Player,
override val boardDisposition: Map[Position, Piece],
override val lastMove: Move
) extends PieceMovedEvent
) extends BoardChangedEvent
Expand Up @@ -23,6 +23,12 @@ trait GameOverEvent extends Event:

/** Companion object of [[GameOverEvent]]. */
object GameOverEvent:
/**
* @param cause the cause of the game over
* @param winner an option containing the winner of the game, or
* an empty option if the game has no winner
* @return a new game over event
*/
def apply(cause: GameOverCause, winner: Option[Player] = None): GameOverEvent =
BasicGameOverEvent(cause, winner)

Expand Down
@@ -0,0 +1,29 @@
/*
* MIT License
* Copyright (c) 2023 Cesario Jahrim Gabriele & Derevyanchenko Maxim & Felice Mirko & Kentpayeva Madina
*
* Full license description available at: https://github.com/jahrim/PPS-22-chess/blob/master/LICENSE
*/
package io.github.chess.engine.events

import io.github.chess.engine.model.configuration.Player

/** An event triggered when the turn in the chess game has changed. */
trait TurnChangedEvent extends Event:

/** @return the player who is currently playing in the chess game */
def currentPlayer: Player

/** Companion object of [[TurnChangedEvent]]. */
object TurnChangedEvent:

/**
* @param currentPlayer the player who is currently playing in the chess game
* @return a new turn changed event
*/
def apply(currentPlayer: Player): TurnChangedEvent =
BasicTurnChangedEvent(currentPlayer)

/** Basic implementation of [[TurnChangedEvent]]. */
private case class BasicTurnChangedEvent(override val currentPlayer: Player)
extends TurnChangedEvent
Expand Up @@ -9,10 +9,8 @@ package io.github.chess.engine.model.board
import io.github.chess.engine.model.pieces.{Bishop, King, Knight, Pawn, Piece, Queen, Rook}
import io.github.chess.engine.model.game.Team.{BLACK, WHITE}
import ChessBoardBuilder.DSL.*
import io.github.chess.engine.events.PieceMovedEvent
import io.github.chess.engine.model.game.Team
import io.github.chess.engine.model.moves.Move
import io.vertx.core.Vertx

/** The trait representing the concept of a Chess Board. */
trait ChessBoard:
Expand Down
Expand Up @@ -8,9 +8,9 @@ package io.github.chess.engine.model.board

import io.github.chess.engine.model.game.Team
import io.github.chess.engine.model.pieces.{Bishop, King, Knight, Pawn, Piece, Queen, Rook}
import io.github.chess.util.exception.Require
import io.github.chess.util.general.GivenExtension.within
import io.github.chess.util.option.OptionExtension.given
import io.github.chess.util.scala.givens.GivenExtension.within
import io.github.chess.util.scala.exception.Require
import io.github.chess.util.scala.option.OptionExtension.given

import scala.annotation.targetName

Expand Down
Expand Up @@ -6,7 +6,7 @@
*/
package io.github.chess.engine.model.board

import io.github.chess.util.exception.OutsideBoardException
import io.github.chess.engine.model.board.exceptions.OutsideBoardException

/** Represents a column of the [[ChessBoard]]. */
enum File:
Expand Down
Expand Up @@ -6,7 +6,7 @@
*/
package io.github.chess.engine.model.board

import io.github.chess.util.exception.OutsideBoardException
import io.github.chess.engine.model.board.exceptions.OutsideBoardException

/** Represents a row of the [[ChessBoard]]. */
enum Rank:
Expand Down
Expand Up @@ -4,7 +4,7 @@
*
* Full license description available at: https://github.com/jahrim/PPS-22-chess/blob/master/LICENSE
*/
package io.github.chess.util.exception
package io.github.chess.engine.model.board.exceptions

/** Represents the situation in which a value (rank or file) goes outside the chess board. */
case class OutsideBoardException() extends RuntimeException("Value goes outside the chess board.")

0 comments on commit bf7d57b

Please sign in to comment.