Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions shared/src/main/scala/com/mogproject/mogami/core/game/Branch.scala
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,16 @@ case class Branch(initialHash: StateHash,
}

def hasComment(pos: Int): Boolean = comments.contains(pos)

/**
* Create a truncated branch
*
* @param pos the point to truncate
*/
def truncated(pos: Int): Branch = {
val relPos = pos - offset
copy(moves = moves.take(relPos), finalAction = None, comments = comments.filterKeys(_ <= pos), hint = Some(BranchHint(history.take(relPos + 1))))
}
}

object Branch extends SfenBranchReader with KifBranchReader {
Expand Down
19 changes: 18 additions & 1 deletion shared/src/main/scala/com/mogproject/mogami/core/game/Game.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ case class Game(trunk: Branch = Branch(),
if (branchNo == 0) Some(trunk) else branches.isDefinedAt(branchNo - 1).option(branches(branchNo - 1))

def withBranch[A](branchNo: BranchNo)(f: Branch => A): Option[A] = getBranch(branchNo).map(f)

def createBranch(position: GamePosition, move: Move): Option[(Game, BranchNo)] = ???

def deleteBranch(branchNo: BranchNo): Option[Game] = ???
Expand Down Expand Up @@ -77,13 +77,30 @@ case class Game(trunk: Branch = Branch(),
} else {
getBranch(branchNo).flatMap(_.finalAction)
}

/**
* Create a truncated game at a specific position
*/
def truncated(gamePosition: GamePosition): Game = {
if (gamePosition.isTrunk) {
// delete branches if needed
copy(trunk = trunk.truncated(gamePosition.position), branches = branches.filter(_.offset <= gamePosition.position))
} else {
withBranch(gamePosition.branch) { br =>
copy(branches = branches.updated(gamePosition.branch, br.truncated(gamePosition.position)))
}.getOrElse(this)
}
}
}

object Game extends CsaGameReader with SfenGameReader with KifGameReader {

type BranchNo = Int // branch number: root = 0

case class GamePosition(branch: BranchNo, position: Int) {
require(branch >= 0, "branch must not be negative")
require(position >= 0, "position must not be negative")

def isTrunk: Boolean = branch == 0
}

Expand Down
6 changes: 6 additions & 0 deletions shared/src/main/scala/com/mogproject/mogami/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ package object mogami {
type Game = com.mogproject.mogami.core.game.Game
val Game = com.mogproject.mogami.core.game.Game

type Branch = com.mogproject.mogami.core.game.Branch
val Branch = com.mogproject.mogami.core.game.Branch

type GamePosition = com.mogproject.mogami.core.game.Game.GamePosition
val GamePosition = com.mogproject.mogami.core.game.Game.GamePosition

type GameStatus = com.mogproject.mogami.core.game.GameStatus.GameStatus
val GameStatus = com.mogproject.mogami.core.game.GameStatus

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -771,4 +771,46 @@ class GameSpec extends FlatSpec with MustMatchers with GeneratorDrivenPropertyCh
g1.getFinalAction(2) mustBe Some(Resign())
g1.getFinalAction(3) mustBe Some(IllegalMove(Move(BLACK, Some(Square(76)), Square(4), KING, false, false, None, None, false, None, false)))
}

"Game#truncated" must "return truncated games" in {
Game().truncated(GamePosition(0, 0)) mustBe Game()
Game().truncated(GamePosition(0, 1)) mustBe Game()
Game().truncated(GamePosition(1, 0)) mustBe Game()


val s1 = SfenExtendedGame(
SfenExtendedBranch(
"lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 0 2g2f 5a4b 2f2e",
None,
Map(1 -> "mv1", 2 -> "mv2", 3 -> "mv3")
),
Vector(
SfenExtendedBranch(
"2 7g7f 4b3b",
None,
Map(2 -> "m2")
),
SfenExtendedBranch(
"2 5g5f 4b3b",
Some("r"),
Map(2 -> "v2", 4 -> "v4")
),
SfenExtendedBranch(
"0",
Some("i 5i5a"),
Map.empty
)
)
)
val g1 = Game.parseSfenExtendedGame(s1)

g1.truncated(GamePosition(0, 3)) mustBe g1
g1.truncated(GamePosition(0, 2)).trunk.moves.length mustBe 2
g1.truncated(GamePosition(0, 2)).trunk.comments mustBe Map(1 -> "mv1", 2 -> "mv2")
g1.truncated(GamePosition(2, 3)).branches(2).comments mustBe Map(2 -> "v2")
g1.truncated(GamePosition(2, 4)).branches(2).status mustBe GameStatus.Playing
g1.truncated(GamePosition(0, 2)).branches.length mustBe 3
g1.truncated(GamePosition(0, 1)).branches.length mustBe 1
g1.truncated(GamePosition(0, 0)).branches.length mustBe 1
}
}