commit af377191b8d65ee2d5b805babf053edc45e9a8f6 Author: peet Date: Fri Feb 23 21:44:58 2024 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af665ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/sbt.xml b/.idea/sbt.xml new file mode 100644 index 0000000..c90073e --- /dev/null +++ b/.idea/sbt.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..d75732f --- /dev/null +++ b/build.sbt @@ -0,0 +1,8 @@ +ThisBuild / version := "0.1.0-SNAPSHOT" + +ThisBuild / scalaVersion := "3.4.0" + +lazy val root = (project in file(".")) + .settings( + name := "kva" + ) diff --git a/src/main/scala/ScalaGo/REPL.scala b/src/main/scala/ScalaGo/REPL.scala new file mode 100644 index 0000000..23b2191 --- /dev/null +++ b/src/main/scala/ScalaGo/REPL.scala @@ -0,0 +1,71 @@ +package ScalaGo + +import ScalaGo.* +import ScalaGo.Color.* +import ScalaGo.FieldContent.* + +import scala.io.StdIn +import SimpleList.* + +object REPL: + + /** + * This function runs and evaluates game states and transitions + * until the global variable gs reaches the passed end state + * + * @param endState run until this state is reached + */ + def repl(endState: GameState): Unit = + while gs != endState + do + ??? + + /** + * Return a String depicting the content of the field + * + * @param c the FieldContent to depict + * @return String depicting the FieldContent + */ + def getFieldContentString(c: FieldContent): String = + ??? + + /** + * Return a String displaying the current state of the board. If the previous board is supplied it is used to + * determine differences between the boards to highlight them. + * + * @param b board to return as string + * @param prev previous board to highlight differences + * @return String representation of the current board + */ + def getFieldString(b: Goboard, prev: Goboard): String = + var boardBuilder = new StringBuilder() + + ??? + + return boardBuilder.toString() + + /** + * Print the board to the standard output + * + * @param b current board + * @param pB previous board, may be used to detect and higlight differences + */ + def printBoard(b: Goboard, pB: Goboard): Unit = + println(getFieldString(b, pB)) + + /** + * Print which player's turn it is to standard output + */ + def printCurrentPlayer(): Unit = + ??? + + /** + * Print the players' score to standard output + * + * @param stonesWhite number of white stones on the board + * @param fieldsWhite number of fields enclosed by white stones + * @param stonesBlack number of black stones on the board + * @param fieldsBlack number of fields enclosed by black stones + */ + def printFinalScore(stonesWhite: Int, fieldsWhite: Int, stonesBlack: Int, fieldsBlack: Int): Unit = + ??? diff --git a/src/main/scala/ScalaGo/ScalaGo.scala b/src/main/scala/ScalaGo/ScalaGo.scala new file mode 100644 index 0000000..dcf5ccf --- /dev/null +++ b/src/main/scala/ScalaGo/ScalaGo.scala @@ -0,0 +1,287 @@ +package ScalaGo + +import SimpleList.* + +object ScalaGo: + + + /** + * Type for specifying a stone's or field's position + */ + type Position = (Int, Int) + + /** + * Color of a player or stone + */ + enum Color: + case Black, White, Nobody + + import Color.* + + /** + * FieldContent models the different fields the game board can have. + */ + enum FieldContent (color: Color): + + /** + * A stone of a specific color. + * + * @param color color of the stone + */ + case Stone (color: Color) extends FieldContent (color: Color) + + /** + * An empty field. + * Has another color than Nobody if a stone was removed from this field in the last round; Referred to as RemovedStone in this case + * + * @param color color the stone belonged if a stone was removed from this field in the last round; Nobody if there was no stone + */ + case Empty (color: Color) extends FieldContent (color) + + import ScalaGo.FieldContent.* + + + /** + * The game state controls the progression of the game. + * + * The transitions array contains tuples of functions and target states. + * If the function of a tuple evaluates to true the target state is activated. + * + * @param player who's turn it is + * @param transitions array of a tuple of transition functions and next GameState + * @param startAction function to execute when entering the state + */ + case class GameState(player: Color, transitions: Array[(String => Boolean, GameState)], startAction: () => Unit) + + + /** + * Chain of stones + * + * @param color color of the stones + * @param position positions of the stones + * @param liberties positions of the chain's liberties + */ + case class Chain(color: Color, position: SimpleList[Position], liberties: SimpleList[Position]) + + + // Custom exceptions + case class OutOfBoardException(msg: String) extends Exception + + case class InvalidBordsizeException(msg: String) extends Exception + + case class InvalidMoveException(msg: String = "This move is not possible!") extends Exception + + + /** + * Alias type for the game board + */ + type Goboard = Array[Array[FieldContent]] + + var board: Goboard = null // The current board + var prevBoard: Goboard = null // The previous board (used for detecting repeating positions) + var prevPrevBoard: Goboard = null // The board before the last board (used for detecting repeating positions) + + var gs: GameState = null // Starting GameState, this global variable is used throughout the implementation + + def main(args: Array[String]): Unit = + + ??? + //val (start, end) = buildStartToEndStates() + + //gs = start + + //REPL.repl(end) + + + /** + * Generate all necessary states with transitions for the game + * + * @return a tuple of the start and the end states + */ + def buildStartToEndStates(): (GameState, GameState) = + ??? + + /** + * Output the current board an player and afterwards remove old RemovedStone markers + */ + def outputBoardAndPlayer(): Unit = + ??? + + /** + * Remove all RemovedStone markers from the board + * + * @param b board to remove from + */ + def removeOldRemovedStones(b: Goboard): Unit = + ??? + + /** + * Remove stones of each chain's positions where the chain has no liberties + * + * @param chains list of chains + * @param c only remove stones of this color + * @param b board to remove the stones from + */ + def removeStonesOfZeroChains(chains: SimpleList[Chain], c: Color, b: Goboard): Unit = + ??? + + /** + * Remove all stones of chains with zero liberties starting with the opposing players color and then remove remaining + * chains with zero liberties of the own color + * + * @param b board to remove the stones from + */ + def killChains(b: Goboard): Unit = + ??? + + /** + * Tests if two boards are identical with regard to only Empty and Stones. + * + * @param b1 board one + * @param b2 board two + * @return true if both boards represent equal positions, false otherwise + */ + def equalBoardPositions(b1: Goboard, b2: Goboard): Boolean = + ??? + + /** + * Create a real copy of the board + * + * @param b board to copy + * @return an identical board at a different memory location + */ + def copyBoard(b: Goboard): Goboard = + ??? + + /** + * Set a position within a board. Thows an OutOfBoardException if the position is not within the board. + * + * @param b the board to place the field in + * @param pos the position + * @param fc the new content of the field at position + */ + def setPosition(b: Goboard, pos: Position, fc: FieldContent): Unit = + ??? + + /** + * Test if a field is only surrounded by stones of one color. This search may span multiple Empty fields. + * + * @param pos start position + * @param c color to match + * @param b board to search + * @return true if the field is only surrounded by stones of the given color, false otherwise + */ + def isSurroundedByOnly(pos: Position, c: Color, b: Goboard): Boolean = + ??? + + /** + * Calculate the score according to the area covered by the players + * + */ + def calculateScore(): Unit = + ??? + + /** + * Generate a board of size*size dimensions. + * + * @param size the horizontal and vertical dimension of the board + * @return true if a valid board could be printed, false otherwise + */ + def buildBoardTransition(size: String): Boolean = + ??? + + /** + * Parse a player's input to detect a stone placement command and place a stone + * + * @param command input from the player + * @return true if the command could be understood, false otherwise + */ + def placeStoneTransition(command: String): Boolean = + ??? + + /** + * Parse a player's input to detect the 'pass' command + * + * @param command input from the player + * @return true if the command could be understood, false otherwise + */ + def passTransition(command: String): Boolean = + if command.equals("pass") then return true + else return false + + /** + * Get the contents of a field by row,column indices. + * + * This is a convenience function that directly calls getFieldConten(p: Position, b: Goboard) + * + * @param row row index + * @param column column index + * @param b the board + * @return the FieldContent which may be OutOfBounds + */ + def getFieldContent(row: Int, column: Int, b: Goboard): FieldContent = getFieldContent((row, column), b) + + /** + * Get the contents of a field by Position. + * + * @param p the position + * @param b the board + * @return the FieldContent which may be OutOfBounds + */ + def getFieldContent(p: Position, b: Goboard): FieldContent = + ??? + + /** + * Used with the exploreChain function to add stones' position to the chain + * + * @param chain chain to extend + * @param pos position to check + * @param b board to use + */ + def addAdjacentStones(chain: Chain, pos: Position, b: Goboard): Unit = ??? + + /** + * Explore all positions of a chain and apply passed function to all fields surrounding the chain's positions + * + * @param chain chain to explore + * @param apply apply this function to all fields surrounding the chain's positions + * @param b the board to use while exploring the chain + */ + def exploreChain(chain: Chain, apply: (Chain, Position, Goboard) => Unit, b: Goboard): Unit = + ??? + + /** + * Find all chains on the board + * + * @param b board to search for chains + * @return list of chains + */ + def findChains(b: Goboard): SimpleList[Chain] = + ??? + + /** + * Used with the exploreChain function to add the positions of liberties to the chain + * + * @param chain chain to add the liberties to + * @param pos position to search for a libertie + * @param b board to use + */ + def addLiberties(chain: Chain, pos: Position, b: Goboard): Unit = ??? + /** + * Find all positions that are liberties along a chain + * + * @param chains chain to search for libertie positions + * @param b board to use + */ + def updateLiberties(chains: SimpleList[Chain], b: Goboard): Unit = + ??? + + /** + * Check if the position is already a position of the chain + * + * @param pos position to check + * @param chains chain to search + * @return true if the position is already in the chain's position list + */ + def isPositionInChains(pos: Position, chains: SimpleList[Chain]): Boolean = + ??? diff --git a/src/main/scala/ScalaGo/SimpleList.scala b/src/main/scala/ScalaGo/SimpleList.scala new file mode 100644 index 0000000..25acc7b --- /dev/null +++ b/src/main/scala/ScalaGo/SimpleList.scala @@ -0,0 +1,39 @@ +package ScalaGo + +object SimpleList: + + /** + * Implements a basic linked list. + * + * @param entry entry of the list element, 'None' if not provided + * @param next next element of the list, 'null' if not provided + * @tparam A type of the list's entries + */ + class SimpleList[A](var entry: Option[A] = None, var next: SimpleList[A] = null) + + /** + * Append an item to the SimpleList + * + * @param list the list + * @param item append this item + */ + def append[A](list: SimpleList[A], item: A): Unit = ??? + + /** + * Determines the length of the SimpleList. + * + * @param list the list + * @return the length + */ + def length[A](list: SimpleList[A]): Int = ??? + + /** + * Tests if the SimpleList contains a given element. + * + * Tests for equality are done via '=='. + * + * @param list the list + * @param item search for this item + * @return true if the SimpleList contains the item, false if not + */ + def contains[A](list: SimpleList[A], item: A): Boolean = ???