diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2025-07-24 05:25:12 -0400 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2025-07-24 12:22:10 -0400 |
| commit | e78e8fb6ae67e9cd188515c1c806dfa2751327c4 (patch) | |
| tree | 373b070a267caafce3016f97ab0dd07f7e4cdb74 /go/game/ai.go | |
| parent | ed473052c558fbda6bb03d9083b425cb2e7a808f (diff) | |
| download | muhqs-game-e78e8fb6ae67e9cd188515c1c806dfa2751327c4.tar.gz muhqs-game-e78e8fb6ae67e9cd188515c1c806dfa2751327c4.zip | |
support street actions
Diffstat (limited to 'go/game/ai.go')
| -rw-r--r-- | go/game/ai.go | 105 |
1 files changed, 72 insertions, 33 deletions
diff --git a/go/game/ai.go b/go/game/ai.go index 7b20d187..07440899 100644 --- a/go/game/ai.go +++ b/go/game/ai.go @@ -122,11 +122,16 @@ func selectRandomTargets(rand *rand.Rand, targets *Targets) error { var ErrNoPath = errors.New("no path found") -func (m *Map) generateMapGraphFor(u *Unit) *dijkstra.Graph { +func generateGraph(tiles []*Tile) *dijkstra.Graph { graph := dijkstra.NewGraph() - for _, t := range m.AllTiles() { + for _, t := range tiles { graph.AddMappedVertex(t.Position.String()) } + return graph +} + +func (m *Map) generateMapGraphFor(u *Unit) *dijkstra.Graph { + graph := generateGraph(m.AllTiles()) for _, t := range m.AllTiles() { tId := t.Position.String() @@ -146,35 +151,65 @@ func (m *Map) generateMapGraphFor(u *Unit) *dijkstra.Graph { return graph } -// func (m *Map) generateMovementRangeGraphFor(u *Unit) *dijkstra.Graph { -// origin := TileOrContainingPermTile(u).Position -// graph := dijkstra.NewGraph() -// for _, t := range tilesInRangeFromOrigin(m, origin, u.Movement.Range, true) { -// graph.AddMappedVertex(t.Position.String()) -// } - -// for _, t := range TilesInRange(m, u, u.Movement.Range) { -// tId := t.Position.String() -// for _, neighbour := range tilesInRangeFromOrigin(m, t.Position, 1, true) { -// if !IsPositionInRange(neighbour.Position, origin, u.Movement.Range) { -// continue -// } - -// if u.IsAvailableTile(neighbour) { -// cost := 2 -// if t.OnDiagonal(neighbour) { -// cost = 3 -// } -// log.Printf("add %v -> %v: %d", tId, neighbour.Position.String(), int64(cost)) -// err := graph.AddMappedArc(tId, neighbour.Position.String(), int64(cost)) -// if err != nil { -// log.Panicf("Failed to add mapped arc: %s", err) -// } -// } -// } -// } -// return graph -// } +func (m *Map) generateMovementRangeGraphFor(u *Unit) *dijkstra.Graph { + origin := TileOrContainingPermTile(u).Position + graph := generateGraph(tilesInRangeFromOrigin(m, origin, u.Movement.Range, true)) + + // Add connections for all tiles and their neighbours + for _, t := range tilesInRangeFromOrigin(m, origin, u.Movement.Range, true) { + tId := t.Position.String() + for _, neighbour := range TilesInRangeFromOrigin(m, t.Position, 1) { + // Skip neighbours not in movement range + if !IsPositionInRange(neighbour.Position, origin, u.Movement.Range) { + continue + } + + if u.IsAvailableTile(neighbour) { + cost := 2 + if t.OnDiagonal(neighbour) { + cost = 3 + } + err := graph.AddMappedArc(tId, neighbour.Position.String(), int64(cost)) + if err != nil { + log.Panicf("Failed to add mapped arc: %s", err) + } + } + } + } + return graph +} + +func (m *Map) generateConnectedMovementRangeGraphFor(u *Unit, conn TileType) *dijkstra.Graph { + origin := TileOrContainingPermTile(u).Position + graph := generateGraph(tilesInRangeFromOrigin(m, origin, u.Movement.Range, true)) + + // Add connections for all tiles and their neighbours + for _, t := range tilesInRangeFromOrigin(m, origin, u.Movement.Range, true) { + tId := t.Position.String() + // Skip tiles with different types + if t.Type != conn { + continue + } + for _, neighbour := range TilesInRangeFromOrigin(m, t.Position, 1) { + // Skip neighbours not in movement range or with different type + if !IsPositionInRange(neighbour.Position, origin, u.Movement.Range) || neighbour.Type != conn { + continue + } + + if u.IsAvailableTile(neighbour) { + cost := 2 + if t.OnDiagonal(neighbour) { + cost = 3 + } + err := graph.AddMappedArc(tId, neighbour.Position.String(), int64(cost)) + if err != nil { + log.Panicf("Failed to add mapped arc: %s", err) + } + } + } + } + return graph +} func findPathTo(graph *dijkstra.Graph, u *Unit, pos Position) (dijkstra.BestPath, error) { srcId, err := graph.GetMapping(TileOrContainingPermTile(u).Position.String()) @@ -276,14 +311,17 @@ func moveAwayFromEnemies(ai *UnitAI) Action { return nil } + // A Movement graph is not sufficient because we have to check the distance to units potentially not in range. graph := ai.s.Map().generateMapGraphFor(ai.u) var farest *Tile var farestEnemyDistance int64 - for _, availableTile := range ai.u.MoveRangeTiles(ai.s.Map()) { + // Check all reachable tiles + for _, availableTile := range ai.u.MoveRangeTiles() { var nearestEnemy int64 = -1 for _, enemyUnit := range ai.s.EnemyUnits(ai.u.Controller()) { + // Get distance to the enemy unit p, err := findPathTo(graph, enemyUnit, availableTile.Position) if err != nil { continue @@ -299,6 +337,7 @@ func moveAwayFromEnemies(ai *UnitAI) Action { } } + // No move possible if farest == nil { return nil } @@ -331,7 +370,7 @@ func actionFromPaths(ai *UnitAI, graph *dijkstra.Graph, paths []*dijkstra.BestPa var x, y int _, _ = fmt.Sscanf(mapping, "(%d, %d)", &x, &y) nextStep := m.TileAt(Position{X: x, Y: y}) - if slices.Contains(ai.u.MoveRangeTiles(m), nextStep) { + if slices.Contains(ai.u.MoveRangeTiles(), nextStep) { target = nextStep } else { break |
