Skip to content

Commit

Permalink
Merge pull request #70 from SlaynAndKorpil/2dimArray
Browse files Browse the repository at this point in the history
2dim array
  • Loading branch information
SlaynAndKorpil authored May 12, 2020
2 parents 3c7ed9f + c19d338 commit 6582f5f
Show file tree
Hide file tree
Showing 31 changed files with 299 additions and 621 deletions.
1 change: 0 additions & 1 deletion .idea/runConfigurations/Main.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions console/src/console/ConsoleConsole.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package console

import framework.{ConsoleDebugger, ConsoleError, ConsoleOutput}

sealed trait ConsoleConsole extends ConsoleOutput {
override val name = "console-interface"
}
Expand Down
6 changes: 0 additions & 6 deletions console/src/console/ConsoleDebugger.scala

This file was deleted.

6 changes: 0 additions & 6 deletions console/src/console/ConsoleError.scala

This file was deleted.

17 changes: 0 additions & 17 deletions console/src/console/ConsoleOutput.scala

This file was deleted.

4 changes: 2 additions & 2 deletions console/src/console/InputInterpreter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,8 @@ class InputInterpreter extends ChessIO with CommandRegistrator {
* Parses a move command.
*/
def parseMove(move: String): CommandResult = {
val from = Square(move.head, move(1).asDigit)
val to = Square(move(2), move(3).asDigit)
val from = Sqr(move.head, move(1).asDigit)
val to = Sqr(move(2), move(3).asDigit)
val moveInput = MoveParams(from, to)
receiveInput(moveInput)
NoMessage
Expand Down
150 changes: 53 additions & 97 deletions framework/src/framework/BoardMap.scala
Original file line number Diff line number Diff line change
@@ -1,84 +1,22 @@
package framework

import scala.collection.AbstractMap
import framework.ChessBoard.columnLetter

import scala.xml._

/**
* A chess board. Stores pieces in a 2 dimensional system (columns and rows).
*
* @author Felix Lehner
* @version
*/
final case class BoardMap(key1: Char, value1: Column,
key2: Char, value2: Column,
key3: Char, value3: Column,
key4: Char, value4: Column,
key5: Char, value5: Column,
key6: Char, value6: Column,
key7: Char, value7: Column,
key8: Char, value8: Column)
extends AbstractMap[Char, Column] with Map[Char, Column] with Serializable {

override def size = 8

override def apply(key: Char): Column =
if (key == key1) value1
else if (key == key2) value2
else if (key == key3) value3
else if (key == key4) value4
else if (key == key5) value5
else if (key == key6) value6
else if (key == key7) value7
else if (key == key8) value8
else throw new NoSuchElementException("key not found: " + key)

override def contains(key: Char): Boolean =
(key == key1) || (key == key2) || (key == key3) || (key == key4) || (key == key5) || (key == key6) || (key == key7) || (key == key7) || (key == key8)

def get(key: Char): Option[Column] =
if (key == key1) Some(value1)
else if (key == key2) Some(value2)
else if (key == key3) Some(value3)
else if (key == key4) Some(value4)
else if (key == key5) Some(value5)
else if (key == key6) Some(value6)
else if (key == key7) Some(value7)
else if (key == key8) Some(value8)
else None

def iterator = Iterator((key1, value1), (key2, value2), (key3, value3), (key4, value4), (key5, value5), (key6, value6), (key7, value7), (key8, value8))

def +[V1 >: Column](kv: (Char, V1)): Map[Char, V1] = throw new UnsupportedOperationException("size of this map limited to 8")

def updated(key: Char, value: Column): BoardMap =
if (key == key1) new BoardMap(key1, value, key2, value2, key3, value3, key4, value4, key5, value5, key6, value6, key7, value7, key8, value8)
else if (key == key2) new BoardMap(key1, value1, key2, value, key3, value3, key4, value4, key5, value5, key6, value6, key7, value7, key8, value8)
else if (key == key3) new BoardMap(key1, value1, key2, value2, key3, value, key4, value4, key5, value5, key6, value6, key7, value7, key8, value8)
else if (key == key4) new BoardMap(key1, value1, key2, value2, key3, value3, key4, value, key5, value5, key6, value6, key7, value7, key8, value8)
else if (key == key5) new BoardMap(key1, value1, key2, value2, key3, value3, key4, value4, key5, value, key6, value6, key7, value7, key8, value8)
else if (key == key6) new BoardMap(key1, value1, key2, value2, key3, value3, key4, value4, key5, value5, key6, value, key7, value7, key8, value8)
else if (key == key7) new BoardMap(key1, value1, key2, value2, key3, value3, key4, value4, key5, value5, key6, value6, key7, value, key8, value8)
else if (key == key8) new BoardMap(key1, value1, key2, value2, key3, value3, key4, value4, key5, value5, key6, value6, key7, value7, key8, value)
else throw new NoSuchElementException("key not found: " + key)

def -(key: Char): Map[Char, Column] = throw new UnsupportedOperationException("size of this map has to be 8")

override def foreach[U](f: ((Char, Column)) => U): Unit = {
f((key1, value1))
f((key2, value2))
f((key3, value3))
f((key4, value4))
f((key5, value5))
f((key6, value6))
f((key7, value7))
f((key8, value8))
}

final case class BoardMap(pieces: Array[Array[Piece]]) {
/**
* @param sqr coordinates of the wanted piece
* @return the chess square at a specific position on the board, [[scala.None]] if the sqr does not exist
*/
def getPiece(sqr: Square): Option[Piece] =
if (sqr.isValid) Some(apply(sqr._1).pieceAt(sqr._2))
def getPiece(sqr: Sqr): Option[Piece] =
if (isValid(sqr)) Some(pieces(sqr._2 - 1)(sqr._1 - 1))
else None

/**
Expand All @@ -89,28 +27,45 @@ final case class BoardMap(key1: Char, value1: Column,
* @return the piece at some specified position
*/
@inline
def apply(sqr: Square): Piece = getPiece(sqr) getOrElse NoPiece
def apply(sqr: Sqr): Piece = getPiece(sqr) getOrElse NoPiece

/**
* Updates the board.
* Returns the unchanged BoardMap object if coordinates are invalid.
*
* @param square the coordinate of the square to updated
* @param piece the piece the square shall be updated to
* @return a ChessBoard with updated squares.
* @return a BoardMap with updated squares.
*/
def updated(square: Square, piece: Piece): BoardMap = {
val updated = this(square._1).updated(square._2, piece)
this.updated(square._1, updated)
def updated(square: Sqr, piece: Piece): BoardMap = {
if (isValid(square)) {
val updated = pieces(square._2 - 1).updated(square._1 - 1, piece)
BoardMap(pieces.updated(square._2 - 1, updated))
} else this
}

/**
* Empties a square.
* Checks if a pair of coordinates describes a valid position on this BoardMap.
*
* @param sqr the given [[framework.Sqr]]
* @return `true` if sqr is valid, otherwise `false`
*/
def isValid(sqr: Sqr): Boolean = {
val outerLen = pieces.length

// needs to be lazy because pieces(0) might fail so we first need to test for outerLen > 0
lazy val innerLen = pieces(0).length

outerLen > 0 && innerLen > 0 &&
0 < sqr.column && sqr.column <= pieces(0).length && 0 < sqr.row && sqr.row <= pieces.length
}

/**
* Empties a square by placing a [[framework.NoPiece]] at this position.
*
* @param sqr the square to be emptied
*/
def emptySquare(sqr: Square): BoardMap =
if (sqr.isValid) updated(sqr, NoPiece)
else this
def emptySquare(sqr: Sqr): BoardMap = updated(sqr, NoPiece)

/**
* Makes a chess move.
Expand All @@ -121,53 +76,54 @@ final case class BoardMap(key1: Char, value1: Column,
* @param piece the moving piece
* @return the board after the move
*/
def movePiece(from: Square, to: Square, piece: Piece): BoardMap = {
def movePiece(from: Sqr, to: Sqr, piece: Piece): BoardMap = {
var result = this

//testing for en passant and castling
piece match {
case Pawn(_, _) if apply(to).isEmpty && from.column != to.column =>
result = result.emptySquare(Square(to.column, from.row))
result = result.emptySquare(Sqr(to.column, from.row))
case King(color, moved) if !moved && (to.column == 'c' || to.column == 'g') =>
val row = ChessBoard.ClassicalValues.piecesStartLine(color)
val col = if (to.column == 'c') 'd' else 'f'
val emptyCol = if (to.column == 'c') 'a' else 'h'
result = result.updated(Square(col, row), Rook(color)).emptySquare(Square(emptyCol, row))
result = result.updated(Sqr(col, row), Rook(color)).emptySquare(Sqr(emptyCol, row))
case _ =>
}

val resPiece = Piece(piece.identifier, piece.color, moved = true)
result.updated(to, resPiece).emptySquare(from)
}

def toXml: NodeSeq = {
for (x <- 0 to 7; col = columnLetter(x + 1)) yield
<col>{
var result: IndexedSeq[scala.xml.Elem] = IndexedSeq()
pieces(x).indices.foreach(i =>
if (pieces(x)(i).nonEmpty) result = result :+ pieces(x)(i).toXml.copy(label = "l" + (i + 1)))
result
}</col> copy (label = col.toUpper.toString)
}

def filter(predicate: Piece => Boolean): BoardMap =
BoardMap(pieces map ( _.filter(predicate) ))

/**
* Formats the board as a [[String]].
*
* @usecase Used in consoleUI to show the board in console
* @return a formatted representation of the board
* @return a fancy formatted representation of the board
*/
override def toString: String = {
val separationLine: String = " +---+---+---+---+---+---+---+---+\n"
val lines = for (x <- 1 to 8; c = ChessBoard.columnLetter(x)) yield c + " " + apply(c)
lines mkString(" 1 2 3 4 5 6 7 8\n" + separationLine, "\n" + separationLine, "\n" + separationLine)
val lines = for (x <- (0 to 7).reverse) yield (x+1) + pieces(x).mkString(" | ", " | ", " |")
lines mkString(" a b c d e f g h\n" + separationLine, "\n" + separationLine, "\n" + separationLine)
}
}


object BoardMap {
def apply(from: Map[Char, Column]): BoardMap =
if (from.size >= 8) {
val seq = from.toSeq
BoardMap(seq(0), seq(1), seq(2), seq(3), seq(4), seq(5), seq(6), seq(7))
}
else throw new UnsupportedOperationException("size of this map has to be 8")

def apply(from: scala.IndexedSeq[(Char, Column)]): BoardMap =
if (from.size >= 8) BoardMap(from(0), from(1), from(2), from(3), from(4), from(5), from(6), from(7))
else throw new UnsupportedOperationException("size of this map has to be 8")
def fill(piece: Piece): BoardMap = BoardMap(Array.fill(8)(Array.fill(8)(piece)))

def apply(kv1: (Char, Column), kv2: (Char, Column), kv3: (Char, Column), kv4: (Char, Column), kv5: (Char, Column),
kv6: (Char, Column), kv7: (Char, Column), kv8: (Char, Column)): BoardMap =
new BoardMap(kv1._1, kv1._2, kv2._1, kv2._2, kv3._1, kv3._2, kv4._1, kv4._2,
kv5._1, kv5._2, kv6._1, kv6._2, kv7._1, kv7._2, kv8._1, kv8._2)
def empty(): BoardMap = fill(NoPiece)
}
2 changes: 1 addition & 1 deletion framework/src/framework/BoardMeta.scala
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ trait BoardMeta {

if (promoPiece != NoPiece) {
gameStatus match {
case PromoReq(sqr: Square) =>
case PromoReq(sqr: Sqr) =>
val updatedHistory =
PromotionMove(history.head.startPos, history.head.piece, sqr, history.head.captured, promoPiece) :: this.history.tail
val result = updated(sqr, promoPiece).clone(gameStatus = StandardReq, history = updatedHistory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ object GameStatus {
else if (state == StandardReq.toString) Right(StandardReq)
else if (contains(state, "PromoReq(", ")")) {
val sqr = state.substring(9, last)
val result = Square(sqr)
val result = Sqr(sqr)
result match {
case Some(square) => Right(PromoReq(square))
case _ => failMessage
Expand Down Expand Up @@ -60,7 +60,7 @@ case object StandardReq extends Active {
}

/** Waiting for a promotion */
case class PromoReq(on: Square) extends Active
case class PromoReq(on: Sqr) extends Active

/** Waiting for an answer to a draw offer. */
case object DrawAcceptanceReq extends Active
Expand Down
Loading

0 comments on commit 6582f5f

Please sign in to comment.