Based on the comments to the question, I worked out 2 solutions. One based on map, the other still uses slices:
Using map (map[int]Unit
like @David-Maze suggested)
package main
import (
"fmt"
"slices"
)
type Game struct {
Map *TileMap
}
type TileMap struct {
Units map[int]Unit
}
func (tilemap *TileMap) removeByKey(key int) {
delete(tilemap.Units, key)
}
func (tilemap *TileMap) getUnitsByEmpire(empire int) []int {
units := []int{}
for key, unit := range tilemap.Units {
if unit.Empire == empire {
units = append(units, key)
}
}
slices.SortStableFunc(units, func(a, b int) int {
if a < b {
return -1
}
if a > b {
return 1
}
return 0
})
return units
}
type Unit struct {
X, Y, Empire int
}
type Army []int
func (army Army) removeByKey(tilemap *TileMap) []int {
tilemap.removeByKey(army[0])
return slices.Delete(army, 0, 1)
}
func (army Army) X(tilemap *TileMap) int {
return tilemap.Units[army[0]].X
}
func (army Army) setX(tilemap *TileMap, x int) {
for _, key := range army {
if entry, ok := tilemap.Units[key]; ok {
entry.X = x
tilemap.Units[key] = entry
}
}
}
func (army Army) Y(tilemap *TileMap) int {
return tilemap.Units[army[0]].Y
}
func (army Army) setY(tilemap *TileMap, y int) {
for _, key := range army {
if entry, ok := tilemap.Units[key]; ok {
entry.Y = y
tilemap.Units[key] = entry
}
}
}
func (army Army) print(name string) {
fmt.Println()
fmt.Println(name, "len:", len(army), "cap", cap(army), ":")
fmt.Printf("%+v\n", army)
for _, unit := range army {
fmt.Printf("%+v\n", unit)
}
}
func main() {
game := Game{}
game.Map = &TileMap{}
game.Map.Units = map[int]Unit{
0: Unit{X: 0, Y: 0, Empire: 0},
1: Unit{X: 0, Y: 0, Empire: 0},
2: Unit{X: 0, Y: 0, Empire: 0},
10: Unit{X: 1, Y: 1, Empire: 1},
11: Unit{X: 1, Y: 1, Empire: 1},
12: Unit{X: 1, Y: 1, Empire: 1},
20: Unit{X: 2, Y: 2, Empire: 2},
21: Unit{X: 2, Y: 2, Empire: 2},
30: Unit{X: 3, Y: 3, Empire: 3},
31: Unit{X: 3, Y: 3, Empire: 3},
40: Unit{X: 4, Y: 4, Empire: 4},
41: Unit{X: 4, Y: 4, Empire: 4},
42: Unit{X: 4, Y: 4, Empire: 4},
}
fmt.Println("game.Map.Units:", len(game.Map.Units))
fmt.Printf("%+v\n", game.Map.Units)
for key, unit := range game.Map.Units {
fmt.Printf("%d: %+v\n", key, unit)
}
attackers := Army(game.Map.getUnitsByEmpire(1))
attackers.print("attackers")
defenders := Army(game.Map.getUnitsByEmpire(3))
defenders.print("defenders")
x := defenders.X(game.Map)
y := defenders.Y(game.Map)
round := 0
attackerRandomValues := []int{9, 0, 0, 9}
defenderRandomValues := []int{0, 9, 9, 0}
for len(attackers) > 0 && len(defenders) > 0 {
round++
r1 := 0
r2 := 0
for r1 == r2 {
//r1 = rand.Intn(10)
//r2 = rand.Intn(10)
r1, attackerRandomValues = attackerRandomValues[0], attackerRandomValues[1:]
r2, defenderRandomValues = defenderRandomValues[0], defenderRandomValues[1:]
}
attackerWon := r1 > r2
if attackerWon {
defenders = defenders.removeByKey(game.Map)
}
defenderWon := r1 < r2
if defenderWon {
attackers = attackers.removeByKey(game.Map)
}
fmt.Println("\nround:", round)
attackers.print("attackers")
defenders.print("defenders")
fmt.Println("\ngame.Map.Units:", len(game.Map.Units))
fmt.Printf("%+v\n", game.Map.Units)
for key, unit := range game.Map.Units {
fmt.Printf("%d: %+v\n", key, unit)
}
}
attackersWon := len(attackers) > 0
if attackersWon {
attackers.setX(game.Map, x)
attackers.setY(game.Map, y)
fmt.Println("\nAttackers won!")
attackers.print("attackers")
}
defendersWon := len(defenders) > 0
if defendersWon {
fmt.Println("\nDefenders won!")
defenders.print("defenders")
}
fmt.Println("\ngame.Map.Units:", len(game.Map.Units))
fmt.Printf("%+v\n", game.Map.Units)
for key, unit := range game.Map.Units {
fmt.Printf("%d: %+v\n", key, unit)
}
}
https://goplay.tools/snippet/DybcFaj1I29
Using slices (like I suggested myself during the question)
package main
import (
"fmt"
"slices"
)
type Game struct {
Map *TileMap
}
type TileMap struct {
Units []Unit
}
func (tilemap *TileMap) removeById(id int) []Unit {
for i := range tilemap.Units {
if tilemap.Units[i].Id == id {
return tilemap.removeUnitByIndex(i)
}
}
return nil
}
func (tilemap *TileMap) removeUnitByIndex(i int) []Unit {
return slices.Delete(tilemap.Units, i, i+1)
}
func (tilemap *TileMap) getUnitsByEmpire(empire int) []*Unit {
units := []*Unit{}
for i := range tilemap.Units {
if tilemap.Units[i].Empire == empire {
units = append(units, &tilemap.Units[i])
}
}
return units
}
type Unit struct {
Id, X, Y, Empire int
}
type Army []*Unit
func (army Army) removeUnitByIndex(i int) Army {
return slices.Delete(army, i, i+1)
}
func (army Army) X() int {
return army[0].X
}
func (army Army) setX(x int) {
for _, unit := range army {
unit.X = x
}
}
func (army Army) Y() int {
return army[0].Y
}
func (army Army) setY(y int) {
for _, unit := range army {
unit.Y = y
}
}
func (army Army) print(name string) {
fmt.Println()
fmt.Println(name, "len:", len(army), "cap", cap(army), ":")
fmt.Printf("%+v\n", army)
for _, unit := range army {
fmt.Printf("%+v\n", unit)
}
}
func main() {
game := Game{}
game.Map = &TileMap{}
game.Map.Units = append(game.Map.Units, Unit{Id: 0, X: 0, Y: 0, Empire: 0}, Unit{Id: 1, X: 0, Y: 0, Empire: 0}, Unit{Id: 2, X: 0, Y: 0, Empire: 0})
game.Map.Units = append(game.Map.Units, Unit{Id: 10, X: 1, Y: 1, Empire: 1}, Unit{Id: 11, X: 1, Y: 1, Empire: 1}, Unit{Id: 12, X: 1, Y: 1, Empire: 1})
game.Map.Units = append(game.Map.Units, Unit{Id: 20, X: 2, Y: 2, Empire: 2}, Unit{Id: 21, X: 2, Y: 2, Empire: 2})
game.Map.Units = append(game.Map.Units, Unit{Id: 30, X: 3, Y: 3, Empire: 3}, Unit{Id: 31, X: 3, Y: 3, Empire: 3})
game.Map.Units = append(game.Map.Units, Unit{Id: 40, X: 4, Y: 4, Empire: 4}, Unit{Id: 41, X: 4, Y: 4, Empire: 4}, Unit{Id: 42, X: 4, Y: 4, Empire: 4})
fmt.Println("game.Map.Units:", len(game.Map.Units), cap(game.Map.Units))
fmt.Printf("%+v\n", game.Map.Units)
for _, unit := range game.Map.Units {
fmt.Printf("%+v\n", unit)
}
killed := []int{}
attackers := Army(game.Map.getUnitsByEmpire(1))
attackers.print("attackers")
defenders := Army(game.Map.getUnitsByEmpire(3))
defenders.print("defenders")
x := defenders.X()
y := defenders.Y()
round := 0
attackerRandomValues := []int{9, 0, 0, 9}
defenderRandomValues := []int{0, 9, 9, 0}
for len(attackers) > 0 && len(defenders) > 0 {
round++
r1 := 0
r2 := 0
for r1 == r2 {
//r1 = rand.Intn(10)
//r2 = rand.Intn(10)
r1, attackerRandomValues = attackerRandomValues[0], attackerRandomValues[1:]
r2, defenderRandomValues = defenderRandomValues[0], defenderRandomValues[1:]
}
attackerWon := r1 > r2
if attackerWon {
killed = append(killed, defenders[0].Id)
defenders = defenders.removeUnitByIndex(0)
}
defenderWon := r1 < r2
if defenderWon {
killed = append(killed, attackers[0].Id)
attackers = attackers.removeUnitByIndex(0)
}
fmt.Println("\nround:", round)
attackers.print("attackers")
defenders.print("defenders")
fmt.Println("\nkilled:", killed)
fmt.Println("\ngame.Map.Units:", len(game.Map.Units), cap(game.Map.Units))
fmt.Printf("%+v\n", game.Map.Units)
for _, unit := range game.Map.Units {
fmt.Printf("%+v\n", unit)
}
}
attackersWon := len(attackers) > 0
if attackersWon {
attackers.setX(x)
attackers.setY(y)
fmt.Println("\nAttackers won!")
attackers.print("attackers")
}
defendersWon := len(defenders) > 0
if defendersWon {
fmt.Println("\nDefenders won!")
defenders.print("defenders")
}
fmt.Println("\nRemoving killed units ...")
fmt.Println("\ngame.Map.Units:", len(game.Map.Units), cap(game.Map.Units))
fmt.Printf("%+v\n", game.Map.Units)
for _, unit := range game.Map.Units {
fmt.Printf("%+v\n", unit)
}
for _, id := range killed {
game.Map.Units = game.Map.removeById(id)
}
fmt.Println("\ngame.Map.Units:", len(game.Map.Units), cap(game.Map.Units))
fmt.Printf("%+v\n", game.Map.Units)
for _, unit := range game.Map.Units {
fmt.Printf("%+v\n", unit)
}
}
https://goplay.tools/snippet/sLPbCPyRoGG
Please feel free to comment to improve the code posted!