|
- package strategies
-
- import (
- "botg/models"
- "fmt"
- )
-
- const (
- capturingShipThreshold int = 10
- )
-
- type LinkerStrategy struct {
- }
-
- func (ls *LinkerStrategy) Execute(stars []*models.Star, flights []models.Flight, links []models.Link) int {
- // Send back ships, attack, then link
- issuedCommands := 0
- issuedCommands += ls.sendHomiesBack(stars, flights, links)
- issuedCommands += ls.attack(stars, flights, links)
- issuedCommands += ls.linkFriendlies(stars, flights, links)
- // Do something randomly, whatever now
- if issuedCommands == 0 {
- // Not sure what
- }
- return issuedCommands
- }
-
- func (ls *LinkerStrategy) attack(stars []*models.Star, flights []models.Flight, links []models.Link) int {
- issuedCommands := 0
- for _, s := range stars {
- // No more flights allowed for that node
- if s.FlightsAllowed <= 0 {
- continue
- }
-
- // Only process owned stars
- if s.Owner != 0 || s.Ships == 0 {
- continue
- }
-
- // Wait till we have a sufficient number of ships
- if ls.insufficientShipsForCapturing(s) {
- continue
- }
-
- //fmt.Printf("Links: %d\n", len(links))
- //fmt.Printf("SOURCE => IDX=%d, X=%d, Y=%d, OWNER=%d, RICH=%d, SHIPS=%d\n", s.Idx, s.X, s.Y, s.Owner, s.Richness, s.Ships)
- // Determine target for this source
- for _, t := range stars {
- // Only target non-owned or enemy stars
- if !t.Unowned() && !t.Enemy() {
- continue
- }
-
- // In the process of capturing the star anyway
- if t.Capturing {
- continue
- }
-
- // Check if ship is within distance
- //fmt.Printf("TARGET => IDX=%d, X=%d, Y=%d, OWNER=%d, RICH=%d, SHIPS=%d\n", t.Idx, t.X, t.Y, t.Owner, t.Richness, t.Ships)
- flightTurnDistance := flightTurnDistance(s, t)
- if flightTurnDistance > 6 {
- continue
- }
-
- shipClause := (s.Ships / 2)
- if s.Ships > 20 {
- shipClause = s.Ships - 10
- }
-
- enemyShipCountWithinFlight := t.Ships
- turns := flightTurnDistance
-
- if t.Turns < turns {
- turns -= t.Turns
- enemyShipCountWithinFlight += t.Richness
- }
-
- for 5 < turns {
- enemyShipCountWithinFlight += t.Richness
- turns -= 5
- }
-
- insufficientShips := shipClause <= (enemyShipCountWithinFlight + 10)
- if t.Enemy() && insufficientShips {
- continue
- }
-
- shipCount := shipClause
- if shipCount < 6 {
- shipCount = 6
- }
-
- // TODO: Find best destination
- // Fly to this target, and skip processing all remaining potential target stars
- fmt.Printf("fly %d %d %d\n", s.Idx, t.Idx, shipCount)
- t.Capturing = true
- t.CapturedBy = s.Idx
- issuedCommands++
- s.FlightsAllowed--
- break
- }
- }
- return issuedCommands
- }
-
- func (ls *LinkerStrategy) linkFriendlies(stars []*models.Star, flights []models.Flight, links []models.Link) int {
- issuedCommands := 0
- friendly := make([]int, 10)
- friendlyDistanceMatrix := make(map[*models.Star]*models.Star)
- for i, s := range stars {
- if s.OwnedByMe() || s.Friendly() {
- friendly = append(friendly, i)
- }
- }
-
- // Keep a map of all the distances
- for i := 0; i < len(friendly); i++ {
- src := stars[friendly[i]]
-
- if src.FlightsAllowed <= 0 {
- continue
- }
-
- for j := i + 1; j < len(friendly); j++ {
- dst, distance := stars[friendly[j]], 0
- if src.Idx == dst.Idx {
- // Shouldn't happen, but oh well
- continue
- }
-
- if ls.linkedOrInProgress(src, dst, links, flights) {
- continue
- }
-
- // We only want to map to friendlies, not own
- if !dst.Friendly() {
- continue
- }
-
- distance = calculateDistanceCeiling(src, dst)
- currentLowest, exists := friendlyDistanceMatrix[src]
- if exists {
- currentDistance := calculateDistanceCeiling(src, currentLowest)
- if currentDistance < distance {
- continue
- }
- }
- // Only add it if it's the currently closest friendly star from source
- friendlyDistanceMatrix[src] = dst
- }
- }
-
- for src, dst := range friendlyDistanceMatrix {
- // If the source is not owned by me, must be a different closer commander
- // so skip it
- if !src.OwnedByMe() {
- continue
- }
-
- if ls.insufficientShipsForLinking(src) {
- continue
- }
-
- if src.FlightsAllowed > 0 {
- // Send a couple of ships out to link
- issuedCommands++
- fmt.Printf("fly %d %d %d\n", src.Idx, dst.Idx, 2)
- src.FlightsAllowed--
- }
- }
- return issuedCommands
- }
-
- func (ls *LinkerStrategy) sendHomiesBack(stars []*models.Star, flights []models.Flight, links []models.Link) int {
- issuedCommands := 0
- for _, s := range stars {
- if s.OwnedByMe() && s.Captured() && ls.insufficientShipsForCapturing(s) && s.FlightsAllowed > 0 {
-
- if s.Ships <= 5 {
- continue
- }
-
- richnessRoundsToCapture := capturingShipThreshold / s.Richness
-
- if richnessRoundsToCapture == 0 {
- richnessRoundsToCapture = 1
- }
-
- timeToCapture := s.Turns + (richnessRoundsToCapture - 1) * 5
- capturingStar := stars[s.CapturedBy]
-
- if !ls.insufficientShipsForCapturing(capturingStar) {
- continue
- }
-
- distanceToOrigin := flightTurnDistance(capturingStar, s)
- if distanceToOrigin < timeToCapture {
- s.FlightsAllowed--
- issuedCommands++
- fmt.Printf("fly %d %d %d\n", s.Idx, capturingStar.Idx, s.Ships - 3)
- }
- }
- }
- return issuedCommands
- }
-
- func (s *LinkerStrategy) insufficientShipsForLinking(star *models.Star) bool {
- return star.Ships < 5
- }
-
- func (s* LinkerStrategy) insufficientShipsForCapturing(star *models.Star) bool {
- return star.Ships < capturingShipThreshold
- }
-
- func (s *LinkerStrategy) linkedOrInProgress(src *models.Star, dst *models.Star, links []models.Link, flights []models.Flight) bool {
- linking := false
-
- for _, l := range links {
- if (l.SourceStar == src.Idx && l.TargetStar == dst.Idx) || (l.SourceStar == dst.Idx && l.TargetStar == src.Idx) {
- linking = true
- break
- }
- }
-
- for _, f := range flights {
- if (f.SourceStar == src.Idx && f.TargetStar == dst.Idx) || (f.SourceStar == dst.Idx && f.TargetStar == src.Idx) {
- linking = true
- break
- }
- }
-
- return linking
- }
|