mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 21:55:42 +00:00
fix Swift tests
This commit is contained in:
@@ -1,20 +1,24 @@
|
||||
BUG: action points not updating on new turn (because no update on start turn)
|
||||
BUG: rest button not updating
|
||||
|
||||
PERF: deterministic vs non-deterministic MonteCarloTreeNodes
|
||||
PERF: trylock and move on rather than waiting during selection
|
||||
PERF: multiple random playthroughs at a time
|
||||
PERF: simple weights for terrain?
|
||||
PERF: cache dirty state of game status
|
||||
PERF: improve 2-tile-away performance
|
||||
PERF: (possibly big) combine Move options in AI GetActions
|
||||
PERF: (possibly big) combine Move options in AI GetActions with barriers around attacks etc
|
||||
PERF: (possibly big) test perf of recursive Simulate without parent pointers
|
||||
PERF: further special-case root MonteCarloTreeNode to not call GetAvailableActions
|
||||
PERF: MapIndex as 8-bit?
|
||||
PERF: Replace HeroSPtr with unique_ptr?
|
||||
PERF: Don't track history in simulation games
|
||||
PERF: specialize small ints in Croissant
|
||||
|
||||
HEALTH: add tests for IsLegal
|
||||
HEALTH: add tests for most Engine interface commands
|
||||
HEALTH: no HeroSPtrs in public Engine methods
|
||||
* HEALTH: no Hero references in public Engine methods, only HeroInfo
|
||||
HEALTH: make PostActionUnchecked available only in game copies
|
||||
HEALTH: fix Swift tests
|
||||
|
||||
RULES: no archery over mountains
|
||||
RULES: no movement after moving adjacent enemy
|
||||
@@ -23,4 +27,3 @@ RULES: flanking, except in castles
|
||||
|
||||
PLAYABILITY: map editor
|
||||
|
||||
SAFETY: make PostActionUnchecked available only in game copies
|
||||
|
||||
@@ -57,27 +57,5 @@ public struct Hero : Codable {
|
||||
public let battalion : Battalion
|
||||
|
||||
public let actionPoints : ActionPoints
|
||||
/*
|
||||
init(heroId: HeroId, playerId: PlayerId, name: String, strength: Double, agility: Double, constitution: Double,
|
||||
charisma: Double, intelligence: Double, wisdom: Double, integrity: Double, ambition: Double,
|
||||
gregariousness: Double, bravery: Double, vigor: Double, mage: Bool, location: Coordinates, battalion: Battalion, actionPoints: ActionPoints) {
|
||||
self.heroId = heroId
|
||||
self.playerId = playerId
|
||||
self.name = name
|
||||
self.strength = strength
|
||||
self.agility = agility
|
||||
self.constitution = constitution
|
||||
self.charisma = charisma
|
||||
self.intelligence = intelligence
|
||||
self.wisdom = wisdom
|
||||
self.integrity = integrity
|
||||
self.ambition = ambition
|
||||
self.gregariousness = gregariousness
|
||||
self.bravery = bravery
|
||||
self.vigor = vigor
|
||||
self.mage = mage
|
||||
self.location = location
|
||||
self.battalion = battalion
|
||||
self.actionPoints = actionPoints
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ class CroissantDecoderTests: XCTestCase {
|
||||
data.append(stringObject: "player") // key
|
||||
data.append(hexString: "42532A") // value, 21290
|
||||
data.append(stringObject: "actor") // key
|
||||
data.append(hexString: "4312D687") // value, 1234567
|
||||
data.append(hexString: "4204D2") // value, 1234567
|
||||
data.append(stringObject: "direction") // key
|
||||
data.append(hexString: "4101") // value, 1
|
||||
data.append(stringObject: "type") // key
|
||||
@@ -342,7 +342,7 @@ class CroissantDecoderTests: XCTestCase {
|
||||
data.append(stringObject: "Attack east") // value
|
||||
|
||||
let decoded = try! ActionDescriptor(from: try! CroissantDecoder(withData: data))
|
||||
let expectedAction = ActionDescriptor(player: 21290, actor: 1234567, direction: .east, type: .meleeAttack, description: "Attack east")
|
||||
let expectedAction = ActionDescriptor(player: 21290, actor: 1234, direction: .east, target: nil, type: .meleeAttack, description: "Attack east")
|
||||
XCTAssertEqual(decoded, expectedAction)
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ class CroissantDecoderTests: XCTestCase {
|
||||
data.append(stringObject: "player") // key
|
||||
data.append(hexString: "42532A") // value, 21290
|
||||
data.append(stringObject: "actor") // key
|
||||
data.append(hexString: "4312D687") // value, 1234567
|
||||
data.append(hexString: "4204D2") // value, 1234567
|
||||
data.append(stringObject: "direction") // key
|
||||
data.append(hexString: "4101") // value, 1
|
||||
data.append(stringObject: "type") // key
|
||||
@@ -361,7 +361,7 @@ class CroissantDecoderTests: XCTestCase {
|
||||
data.append(stringObject: "Attack east") // value
|
||||
|
||||
let decoded = try! [ActionDescriptor](from: try! CroissantDecoder(withData: data))
|
||||
let expectedActionArray = [ActionDescriptor(player: 21290, actor: 1234567, direction: .east, type: .meleeAttack, description: "Attack east")]
|
||||
let expectedActionArray = [ActionDescriptor(player: 21290, actor: 1234, direction: .east, target: nil, type: .meleeAttack, description: "Attack east")]
|
||||
XCTAssertEqual(decoded, expectedActionArray)
|
||||
}
|
||||
|
||||
@@ -371,14 +371,14 @@ class CroissantDecoderTests: XCTestCase {
|
||||
data.append(stringObject: "player") // key
|
||||
data.append(hexString: "42532A") // value, 21290
|
||||
data.append(stringObject: "type") // key
|
||||
data.append(hexString: "4102") // value, 2 (end turn)
|
||||
data.append(hexString: "4104") // value, 4 (end turn)
|
||||
data.append(stringObject: "description") // key
|
||||
data.append(stringObject: "End turn") // value
|
||||
data.append(hexString: "0x65") // 5-element map
|
||||
data.append(stringObject: "player") // key
|
||||
data.append(hexString: "42532A") // value, 21290
|
||||
data.append(stringObject: "actor") // key
|
||||
data.append(hexString: "4312D687") // value, 1234567
|
||||
data.append(hexString: "4204D2") // value, 1234567
|
||||
data.append(stringObject: "direction") // key
|
||||
data.append(hexString: "4101") // value, 1
|
||||
data.append(stringObject: "type") // key
|
||||
@@ -389,9 +389,9 @@ class CroissantDecoderTests: XCTestCase {
|
||||
let decoder = try CroissantDecoder(withData: data)
|
||||
let decoded = try [ActionDescriptor](from: decoder)
|
||||
|
||||
let heroAction = ActionDescriptor(player: 21290, actor: 1234567, direction: .east, type: .meleeAttack, description: "Attack east")
|
||||
let endTurnAction = ActionDescriptor(player: 21290, actor: nil, direction: nil, type: .endTurn, description: "End turn")
|
||||
let expectedActions = AvailableActions([endTurnAction, heroAction])
|
||||
let heroAction = ActionDescriptor(player: 21290, actor: 1234, direction: .east, target: nil, type: .meleeAttack, description: "Attack east")
|
||||
let endTurnAction = ActionDescriptor(player: 21290, actor: nil, direction: nil, target: nil, type: .endTurn, description: "End turn")
|
||||
let expectedActions = [endTurnAction, heroAction]
|
||||
|
||||
XCTAssertEqual(decoded, expectedActions)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ import XCTest
|
||||
class PlayerGameModelTest: XCTestCase {
|
||||
|
||||
class PlayerClientInterfaceMock : PlayerClientInterface {
|
||||
func run() {
|
||||
}
|
||||
|
||||
let playerId: PlayerId
|
||||
var hexMap : HexMap? = HexMap(rowCount: 2, columnCount: 2, oddRowsShorter: false, terrainValues: [.plains, .mountain, .castle, .forest])
|
||||
var history = TurnHistory()
|
||||
@@ -18,10 +21,11 @@ class PlayerGameModelTest: XCTestCase {
|
||||
var allHeroes : [Hero]?
|
||||
var oneHero : Hero?
|
||||
var myTurn = false
|
||||
var availableActions : AvailableActions?
|
||||
var availableActions : [ActionDescriptor]?
|
||||
var actionResult : ActionResult?
|
||||
|
||||
private(set) var updateCallback : ((TurnHistoryEntry?) -> Void)?
|
||||
private(set) var actionCallback : ((TurnHistoryEntry?) -> Void)?
|
||||
private(set) var gameOverCallback : ((GameStatus?) -> Void)?
|
||||
|
||||
func getAllHeroes(_ handler: @escaping ([Hero]?) -> Void) {
|
||||
handler(allHeroes)
|
||||
@@ -35,7 +39,7 @@ class PlayerGameModelTest: XCTestCase {
|
||||
handler(myTurn)
|
||||
}
|
||||
|
||||
func getAvailableActions(_ handler: @escaping (AvailableActions?) -> Void) {
|
||||
func getAvailableActions(_ handler: @escaping ([ActionDescriptor]?) -> Void) {
|
||||
handler(availableActions)
|
||||
}
|
||||
|
||||
@@ -47,8 +51,9 @@ class PlayerGameModelTest: XCTestCase {
|
||||
handler(actionResult)
|
||||
}
|
||||
|
||||
func registerUpdateCallback(_ updateCallback: @escaping (TurnHistoryEntry?) -> Void) {
|
||||
self.updateCallback = updateCallback
|
||||
func register(actionCallback: @escaping (TurnHistoryEntry?) -> Void, gameOverCallback: @escaping (GameStatus?) -> Void) {
|
||||
self.actionCallback = actionCallback
|
||||
self.gameOverCallback = gameOverCallback
|
||||
}
|
||||
|
||||
init(withPlayerId: PlayerId) {//, hexMap: HexMap, history: TurnHistory) {
|
||||
@@ -57,6 +62,16 @@ class PlayerGameModelTest: XCTestCase {
|
||||
}
|
||||
|
||||
class ViewControllerMock : GenericViewController {
|
||||
var endTurnEnabled: Bool = false
|
||||
|
||||
var restEnabled: Bool = false
|
||||
|
||||
var playerTotalSize: Int32 = 1
|
||||
|
||||
var opponentTotalSize: Int32 = 2
|
||||
|
||||
var gameStatus: String = "Game running"
|
||||
|
||||
var model: PlayerGameModel!
|
||||
var selectedHero: Hero?
|
||||
var isPlayersTurn: Bool = false
|
||||
@@ -107,17 +122,19 @@ class PlayerGameModelTest: XCTestCase {
|
||||
}
|
||||
|
||||
func testRegistersUpdateCallback() {
|
||||
XCTAssertNil(interface.updateCallback)
|
||||
XCTAssertNil(interface.actionCallback)
|
||||
model = PlayerGameModel(withClientInterface: interface, viewController: controller)
|
||||
XCTAssertNotNil(interface.updateCallback)
|
||||
model.ready()
|
||||
XCTAssertNotNil(interface.actionCallback)
|
||||
}
|
||||
|
||||
func testAllHeroes_containsAllHeroes() {
|
||||
interface.allHeroes = [HERO1, HERO2]
|
||||
XCTAssertTrue(controller.placedHeroIds.isEmpty)
|
||||
model = PlayerGameModel(withClientInterface: interface, viewController: controller)
|
||||
model.ready()
|
||||
assertAfterMainQueueCallbacks {
|
||||
XCTAssertEqual(controller.placedHeroIds.count, 2)
|
||||
XCTAssertGreaterThanOrEqual(controller.placedHeroIds.count, 2)
|
||||
XCTAssertTrue(controller.placedHeroIds.contains(HERO1.heroId))
|
||||
XCTAssertTrue(controller.placedHeroIds.contains(HERO2.heroId))
|
||||
}
|
||||
@@ -126,9 +143,10 @@ class PlayerGameModelTest: XCTestCase {
|
||||
func testUpdateCallback_removedHeroes_removesHeroes() {
|
||||
interface.allHeroes = [HERO1, HERO2]
|
||||
model = PlayerGameModel(withClientInterface: interface, viewController: controller)
|
||||
let newTurnHistoryEntry = TurnHistoryEntry(actionId: 123, message: "a turn entry", changedHeroes: nil, removedHeroes: [HERO1.heroId], nextPlayer: 0)
|
||||
model.ready()
|
||||
let newTurnHistoryEntry = TurnHistoryEntry(actionId: 123, message: "a turn entry", changedHeroes: nil, removedHeroes: [HERO1.heroId], nextPlayer: 0, nextRound: 1)
|
||||
XCTAssertTrue(controller.removedHeroCoordinates.isEmpty)
|
||||
interface.updateCallback!(newTurnHistoryEntry)
|
||||
interface.actionCallback!(newTurnHistoryEntry)
|
||||
assertAfterMainQueueCallbacks {
|
||||
XCTAssertEqual(controller.removedHeroCoordinates.count, 1)
|
||||
XCTAssertEqual(controller.removedHeroCoordinates.first!, HERO1.location)
|
||||
@@ -142,12 +160,15 @@ class PlayerGameModelTest: XCTestCase {
|
||||
func testUpdateCallback_becomesMyTurn_selectsHero() {
|
||||
interface.allHeroes = [HERO1, HERO2]
|
||||
model = PlayerGameModel(withClientInterface: interface, viewController: controller)
|
||||
model.ready()
|
||||
XCTAssertNil(controller.selectedHero)
|
||||
let newTurnHistoryEntry = TurnHistoryEntry(actionId: 123, message: "other player finished", changedHeroes: nil, removedHeroes: nil, nextPlayer: PLAYER_ID)
|
||||
interface.availableActions = [ActionDescriptor(player: PLAYER_ID, actor: HERO1.heroId, direction: HexMap.Direction.east, type: .move, description: "move east")]
|
||||
interface.updateCallback!(newTurnHistoryEntry)
|
||||
let newTurnHistoryEntry = TurnHistoryEntry(actionId: 123, message: "other player finished", changedHeroes: nil, removedHeroes: nil, nextPlayer: PLAYER_ID, nextRound: 1)
|
||||
interface.availableActions = [ActionDescriptor(player: PLAYER_ID, actor: HERO1.heroId, direction: HexMap.Direction.east, target: nil, type: .move, description: "move east")]
|
||||
interface.actionCallback!(newTurnHistoryEntry)
|
||||
assertAfterMainQueueCallbacks {
|
||||
XCTAssertEqual(controller.selectedHero!.heroId, HERO1.heroId)
|
||||
assertAfterMainQueueCallbacks {
|
||||
XCTAssertEqual(controller.selectedHero!.heroId, HERO1.heroId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ let HERO1 = Hero(heroId: 123,
|
||||
gregariousness: 10,
|
||||
bravery: 5,
|
||||
vigor: 4,
|
||||
volleys: 5,
|
||||
mage: false,
|
||||
location: Coordinates(row: MapIndex(0), column: MapIndex(0)),
|
||||
battalion: BATTALION1,
|
||||
@@ -58,6 +59,7 @@ let HERO2 = Hero(heroId: 9998,
|
||||
gregariousness: 100,
|
||||
bravery: 7,
|
||||
vigor: 99,
|
||||
volleys: 9,
|
||||
mage: true,
|
||||
location: Coordinates(row: MapIndex(1), column: MapIndex(0)),
|
||||
battalion: BATTALION2,
|
||||
|
||||
@@ -140,6 +140,7 @@ ShardokResult ShardokEngine::PostActionUnchecked(ActionDescriptor action, bool g
|
||||
if (actingHero->IsDestroyed()) {
|
||||
removedHeroes.push_back(heroId);
|
||||
hexMap->RemoveOccupant(actingHero->GetLocation());
|
||||
allHeroes[heroId].reset();
|
||||
} else {
|
||||
changedHeroes.push_back(actingHero->GetInfo());
|
||||
}
|
||||
@@ -182,8 +183,8 @@ AvailableActions ShardokEngine::GetAvailableActions(PlayerId playerId) {
|
||||
actions.reserve(heroesForPlayer[playerId].size() * 6 + 2);
|
||||
|
||||
for (HeroSPtr hero : heroesForPlayer[playerId]) {
|
||||
if (hero == nullptr) continue;
|
||||
HeroId heroId = hero->GetId();
|
||||
if (hero->IsDestroyed()) continue;
|
||||
if (hero->GetRemainingActionPoints() < MIN_ACTION_POINTS_TO_ACT) continue;
|
||||
Coords currentCoords = hero->GetLocation();
|
||||
|
||||
@@ -229,6 +230,7 @@ GameStatus ShardokEngine::UpdateGameStatus(bool atEndOfRound) const {
|
||||
bool attackerStanding = false;
|
||||
for (PlayerId attackerId = 0; attackerId < numAttackers; attackerId++) {
|
||||
for (HeroSPtr hero : heroesForPlayer[attackerId]) {
|
||||
if (hero == nullptr) continue;
|
||||
if (hero->GetBattalion()->GetSize() > 0 ||
|
||||
hero->GetVigor() > 0) {
|
||||
attackerStanding = true;
|
||||
@@ -246,8 +248,7 @@ GameStatus ShardokEngine::UpdateGameStatus(bool atEndOfRound) const {
|
||||
bool defenderStanding = false;
|
||||
for (PlayerId defenderId = numAttackers; defenderId < numAttackers + numDefenders; defenderId++) {
|
||||
for (HeroSPtr hero : heroesForPlayer[defenderId]) {
|
||||
if (hero->GetBattalion()->GetSize() > 0 ||
|
||||
hero->GetVigor() > 0) {
|
||||
if (hero != nullptr) {
|
||||
defenderStanding = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ private:
|
||||
const PlayerId numDefenders;
|
||||
|
||||
const HeroIdList maxHeroIdForPlayer;
|
||||
const HeroList allHeroes; // HeroId is the index
|
||||
HeroList allHeroes; // HeroId is the index
|
||||
const HexMapSPtr hexMap;
|
||||
vector<const HeroList> heroesForPlayer;
|
||||
|
||||
@@ -58,7 +58,9 @@ protected:
|
||||
|
||||
if (gameStatus.state == GameStatus::gameRunning) {
|
||||
for (HeroSPtr hero : heroesForPlayer[currentPlayer]) {
|
||||
hero->SetRemainingActionPoints(hero->GetMaxActionPoints());
|
||||
if (hero != nullptr) {
|
||||
hero->SetRemainingActionPoints(hero->GetMaxActionPoints());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,7 +126,7 @@ public:
|
||||
throw ShardokException("Trying to end turn for player " + std::to_string(pid) + ", but turn belongs to " + std::to_string(currentPlayer));
|
||||
}
|
||||
for (HeroSPtr hero : heroesForPlayer[currentPlayer]) {
|
||||
if (!hero->IsDestroyed()) {
|
||||
if (hero != nullptr) {
|
||||
hero->Rest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user