package controller_test import ( "maps" "slices" "testing" "github.com/iliadenisov/galaxy/internal/controller" "github.com/iliadenisov/galaxy/internal/model/game" "github.com/stretchr/testify/assert" ) var ( attacker = game.ShipType{ Name: "Attacker", Drive: 8, Armament: 1, Weapons: 8, Shields: 8, Cargo: 0, } defender = game.ShipType{ Name: "Defender", Drive: 1, Armament: 1, Weapons: 1, Shields: 1, Cargo: 0, } ship = game.ShipType{ Name: "Ship", Drive: 10, Armament: 1, Weapons: 10, Shields: 10, Cargo: 0, } ) func TestDestructionProbability(t *testing.T) { probability := controller.DestructionProbability(ship.Weapons.F(), 1, ship.Shields.F(), 1, ship.EmptyMass()) assert.Equal(t, .5, probability) undefeatedShip := ship undefeatedShip.Shields = 55 probability = controller.DestructionProbability(ship.Weapons.F(), 1, undefeatedShip.Shields.F(), 1, undefeatedShip.EmptyMass()) assert.LessOrEqual(t, probability, 0.) disruptiveShip := ship disruptiveShip.Weapons = 40 probability = controller.DestructionProbability(disruptiveShip.Weapons.F(), 1, ship.Shields.F(), 1, ship.EmptyMass()) assert.GreaterOrEqual(t, probability, 1.) } func TestEffectiveDefence(t *testing.T) { assert.Equal(t, 10., controller.EffectiveDefence(ship.Shields.F(), 1, ship.EmptyMass())) attackerEffectiveDefence := controller.EffectiveDefence(attacker.Shields.F(), 1, attacker.EmptyMass()) defenderEffectiveDefence := controller.EffectiveDefence(defender.Shields.F(), 1, defender.EmptyMass()) // attacker's effective shields must be 'just' 4 times greater than defender's assert.InDelta(t, defenderEffectiveDefence*4, attackerEffectiveDefence, 0) } func TestCollectPlanetGroups(t *testing.T) { c, _ := newCache() assert.NoError(t, c.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 10)) // 1 #0 assert.NoError(t, c.CreateShips(Race_0_idx, ShipType_Cruiser, R0_Planet_0_num, 3)) // 2 #1 assert.NoError(t, c.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 3)) // 3 #2 c.ShipGroup(2).StateInSpace = &InSpace // 3 #2 -> In_Space assert.NoError(t, c.CreateShips(Race_0_idx, ShipType_Cruiser, R0_Planet_0_num, 1)) // 4 #3 c.ShipGroup(3).Destination = R1_Planet_1_num // 4 #3 -> Planet_1 assert.NoError(t, c.CreateShips(Race_1_idx, Race_1_Gunship, R1_Planet_1_num, 15)) // 5 #4 c.ShipGroup(4).Destination = R0_Planet_0_num // 5 #4 -> Planet_0 planetGroups := controller.CollectPlanetGroups(c) for pl := range planetGroups { switch pl { case R0_Planet_0_num: assert.Equal(t, 3, len(planetGroups[pl])) assert.Contains(t, planetGroups[pl], 0) assert.Contains(t, planetGroups[pl], 1) assert.Contains(t, planetGroups[pl], 4) default: assert.Fail(t, "planet #%d should not contain groups for battle", pl) } } } func TestFilterBattleOpponents(t *testing.T) { c, _ := newCache() assert.NoError(t, c.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 1)) // 0 assert.NoError(t, c.CreateShips(Race_0_idx, ShipType_Cruiser, R0_Planet_0_num, 1)) // 1 assert.NoError(t, c.CreateShips(Race_1_idx, Race_1_Gunship, R1_Planet_1_num, 15)) // 2 undefeatedShip := ship undefeatedShip.Shields = 100 assert.NoError(t, c.ShipClassCreate(Race_1_idx, undefeatedShip.Name, undefeatedShip.Drive.F(), int(undefeatedShip.Armament), undefeatedShip.Weapons.F(), undefeatedShip.Shields.F(), undefeatedShip.Cargo.F())) assert.NoError(t, c.CreateShips(Race_1_idx, undefeatedShip.Name, R1_Planet_1_num, 1)) // 3 cacheProbability := make(map[int]map[int]float64) assert.False(t, controller.FilterBattleOpponents(c, 0, 2, cacheProbability)) assert.Contains(t, cacheProbability, 0) assert.Contains(t, cacheProbability[0], 2) assert.InDelta(t, 0.396222, cacheProbability[0][2], 0.0000001) assert.False(t, controller.FilterBattleOpponents(c, 2, 0, cacheProbability)) assert.Contains(t, cacheProbability, 2) assert.Contains(t, cacheProbability[2], 0) assert.InDelta(t, 0.495, cacheProbability[2][0], 0.0001) // Test: same owner assert.True(t, controller.FilterBattleOpponents(c, 0, 0, cacheProbability)) assert.True(t, controller.FilterBattleOpponents(c, 0, 1, cacheProbability)) assert.True(t, controller.FilterBattleOpponents(c, 1, 0, cacheProbability)) // Test: reace reations assert.NoError(t, c.UpdateRelation(Race_0_idx, Race_1_idx, game.RelationPeace)) assert.True(t, controller.FilterBattleOpponents(c, 0, 2, cacheProbability)) assert.True(t, controller.FilterBattleOpponents(c, 2, 0, cacheProbability)) assert.NoError(t, c.UpdateRelation(Race_0_idx, Race_1_idx, game.RelationWar)) assert.LessOrEqual(t, controller.DestructionProbability(Cruiser.Weapons.F(), 1, undefeatedShip.Shields.F(), 1, undefeatedShip.EmptyMass()), 0.) assert.True(t, controller.FilterBattleOpponents(c, 1, 3, cacheProbability)) assert.NotContains(t, cacheProbability[1], 3) } func TestProduceBattles(t *testing.T) { c, g := newCache() race_C_name, race_D_name := "Race_C", "Race_D" race_C_idx, _ := c.AddRace(race_C_name) race_D_idx, _ := c.AddRace(race_D_name) assert.NoError(t, g.UpdateRelation(Race_0.Name, Race_1.Name, game.RelationWar.String())) assert.NoError(t, g.UpdateRelation(Race_1.Name, Race_0.Name, game.RelationWar.String())) assert.NoError(t, g.UpdateRelation(race_C_name, race_D_name, game.RelationWar.String())) assert.NoError(t, g.UpdateRelation(race_D_name, race_C_name, game.RelationWar.String())) assert.Equal(t, game.RelationPeace, c.Relation(Race_0_idx, race_C_idx)) assert.Equal(t, game.RelationPeace, c.Relation(Race_1_idx, race_C_idx)) assert.Equal(t, game.RelationPeace, c.Relation(Race_0_idx, race_D_idx)) assert.Equal(t, game.RelationPeace, c.Relation(Race_1_idx, race_D_idx)) // Race_0 assert.NoError(t, c.CreateShips(Race_0_idx, Race_0_Gunship, R0_Planet_0_num, 10)) // Race_1 c.CreateShipsUnsafe_T(Race_1_idx, c.MustShipClass(Race_1_idx, Race_1_Gunship).ID, R0_Planet_0_num, 11) // Race_C assert.NoError(t, c.ShipClassCreate(race_C_idx, Cruiser.Name, Cruiser.Drive.F(), int(Cruiser.Armament), Cruiser.Weapons.F(), Cruiser.Shields.F(), Cruiser.Cargo.F())) c.CreateShipsUnsafe_T(race_C_idx, c.MustShipClass(race_C_idx, Cruiser.Name).ID, R0_Planet_0_num, 12) // Race_D assert.NoError(t, c.ShipClassCreate(race_D_idx, Cruiser.Name, Cruiser.Drive.F(), int(Cruiser.Armament), Cruiser.Weapons.F(), Cruiser.Shields.F(), Cruiser.Cargo.F())) c.CreateShipsUnsafe_T(race_D_idx, c.MustShipClass(race_D_idx, Cruiser.Name).ID, R0_Planet_0_num, 13) battle := controller.ProduceBattles(c) assert.Len(t, battle, 1) b := battle[0] assert.Equal(t, R0_Planet_0_num, b.Planet) assert.Len(t, b.ObserverGroups, 4) assert.Len(t, b.InitialNumbers, 4) assert.ElementsMatch(t, slices.Collect(maps.Keys(b.ObserverGroups)), slices.Collect(maps.Keys(b.InitialNumbers))) assert.Equal(t, 10, int(b.InitialNumbers[0])) assert.Equal(t, 11, int(b.InitialNumbers[1])) assert.Equal(t, 12, int(b.InitialNumbers[2])) assert.Equal(t, 13, int(b.InitialNumbers[3])) if c.ShipGroup(0).Number == 0 { assert.Greater(t, c.ShipGroup(1).Number, uint(0)) } else { assert.Zero(t, c.ShipGroup(1).Number) } if c.ShipGroup(2).Number == 0 { assert.Greater(t, c.ShipGroup(3).Number, uint(0)) } else { assert.Zero(t, c.ShipGroup(3).Number) } }