79389257

Date: 2025-01-26 20:38:41
Score: 1.5
Natty:
Report link

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!

Reasons:
  • Blacklisted phrase (1): to comment
  • Long answer (-1):
  • Has code block (-0.5):
  • User mentioned (1): @David-Maze
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: scratch