@@ -12,7 +12,7 @@ import ( | |||
"time" | |||
) | |||
var stars []models.Star | |||
var stars []*models.Star | |||
var flights []models.Flight | |||
var links []models.Link | |||
@@ -60,6 +60,7 @@ func main() { | |||
} | |||
strategy.Execute(stars, flights, links) | |||
fmt.Println("done") | |||
} | |||
} | |||
@@ -74,10 +75,10 @@ func parseLine(text string) bool { | |||
var x, y int | |||
x, _ = strconv.Atoi(parts[i]) | |||
y, _ = strconv.Atoi(parts[i+1]) | |||
star := models.Star { | |||
Idx: i - 1, | |||
X: x, | |||
Y: y, | |||
star := &models.Star{ | |||
Idx: i - 1, | |||
X: x, | |||
Y: y, | |||
Richness: 0, | |||
Owner: -2, | |||
Ships: -2, | |||
@@ -92,11 +93,12 @@ func parseLine(text string) bool { | |||
var owner, _ = strconv.Atoi(parts[3]) | |||
var ships, _ = strconv.Atoi(parts[4]) | |||
var turns, _ = strconv.Atoi(parts[5]) | |||
star := &stars[idx] | |||
star := stars[idx] | |||
star.Richness = richness | |||
star.Owner = owner | |||
star.Ships = ships | |||
star.Turns = turns | |||
star.FlightsAllowed = 3 | |||
break | |||
case "link": | |||
var source_idx, _ = strconv.Atoi(parts[1]) | |||
@@ -129,5 +131,14 @@ func parseLine(text string) bool { | |||
return true | |||
} | |||
// Update star flight data | |||
for i, s := range stars { | |||
for _, f := range flights { | |||
if f.SourceStar == i { | |||
s.FlightsAllowed-- | |||
} | |||
} | |||
} | |||
return false | |||
} |
@@ -8,6 +8,7 @@ type Star struct { | |||
Owner int | |||
Ships int | |||
Turns int | |||
FlightsAllowed int | |||
} | |||
type Flight struct { |
@@ -32,7 +32,7 @@ func calculateDistanceCeiling(source *models.Star, target *models.Star) int { | |||
func flightTurnDistance(source, target *models.Star) int { | |||
if source.Idx == target.Idx { | |||
return 0; | |||
return 0 | |||
} | |||
return int(math.Ceil(float64(calculateDistanceCeiling(source, target)) / 10.0)) |
@@ -8,71 +8,82 @@ import ( | |||
type LinkerStrategy struct { | |||
} | |||
func (ls *LinkerStrategy) Execute(stars []models.Star, flights []models.Flight, links []models.Link) { | |||
func (ls *LinkerStrategy) Execute(stars []*models.Star, flights []models.Flight, links []models.Link) { | |||
friendly := make([]int, 10) | |||
friendlyDistanceMatrix := make(map[models.Star]map[models.Star]int) | |||
friendlyDistanceMatrix := make(map[models.Star]*models.Star) | |||
for i, s := range stars { | |||
// Skip unowned and enemy stars | |||
if s.Unowned() || s.Enemy() { | |||
continue | |||
} | |||
// Keep track of own stars | |||
// Keep track of friendly stars | |||
if s.OwnedByMe() || s.Friendly() { | |||
friendly = append(friendly, i) | |||
} | |||
friendlyDistanceMatrix[s] = make(map[models.Star]int) | |||
} | |||
// Keep a map of all the distances | |||
for i := 0; i < len(friendly); i++ { | |||
src := stars[i] | |||
for j := i + 1; j < len(friendly); j++ { | |||
dst, flightDistance := stars[j], 0 | |||
dst, distance := stars[j], 0 | |||
if src.Idx == dst.Idx { | |||
// Shouldn't happen, but oh well | |||
continue | |||
} | |||
if ls.linkedOrInProgress(&src, &dst, links, flights) { | |||
if ls.linkedOrInProgress(src, dst, links, flights) { | |||
continue | |||
} | |||
// The source is lower than the destination, so skip it | |||
if src.Y > dst.Y { | |||
continue | |||
} | |||
flightDistance = flightTurnDistance(&src, &dst) | |||
// We only want to map to friendlies, not own | |||
if !dst.Friendly() { | |||
continue | |||
} | |||
friendlyDistanceMatrix[src][dst] = flightDistance | |||
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 | |||
} | |||
} | |||
top3Picks := []struct { | |||
src *models.Star | |||
dst *models.Star | |||
distance int | |||
}{ | |||
{nil, nil, 300 * 300}, | |||
{nil, nil, 300 * 300}, | |||
{nil, nil, 300 * 300}, | |||
} | |||
var nextLinkSource, nextLinkTarget *models.Star | |||
minDistance := 300 * 300 | |||
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 | |||
} | |||
for src, dstmap := range friendlyDistanceMatrix { | |||
for dst, distance := range dstmap { | |||
for i := 0; i < len(top3Picks); i++ { | |||
if top3Picks[i].src == nil { | |||
top3Picks[i].src = &src | |||
top3Picks[i].dst = &dst | |||
break | |||
} | |||
if distance < top3Picks[i].distance { | |||
top3Picks[i].src = &src | |||
top3Picks[i].dst = &dst | |||
} | |||
} | |||
if ls.insufficientShipsForLinking(&src) { | |||
continue | |||
} | |||
distance := calculateDistanceCeiling(&src, dst) | |||
if distance < minDistance { | |||
nextLinkSource = &src | |||
nextLinkTarget = dst | |||
} | |||
} | |||
fmt.Println("done") | |||
if nextLinkSource != nil && nextLinkTarget != nil { | |||
// Send a ship out to link | |||
fmt.Printf("fly %d %d %d\n", nextLinkSource.Idx, nextLinkTarget.Idx, 2) | |||
} | |||
} | |||
func (s *LinkerStrategy) insufficientShipsForLinking(star *models.Star) bool { |
@@ -8,20 +8,11 @@ import ( | |||
type SimpleStrategy struct { | |||
} | |||
func (s *SimpleStrategy) Execute(stars []models.Star, flights []models.Flight, links []models.Link) { | |||
func (s *SimpleStrategy) Execute(stars []*models.Star, flights []models.Flight, links []models.Link) { | |||
for i, s := range stars { | |||
// Maximum flights per star per round is 3 | |||
total := 0 | |||
// Check if source star is already in flight | |||
inFlight := false | |||
for _, f := range flights { | |||
if f.SourceStar == i { | |||
inFlight = true | |||
} | |||
} | |||
if inFlight { | |||
// No more flights allowed for that node | |||
if s.FlightsAllowed <= 0 { | |||
continue | |||
} | |||
@@ -30,8 +21,8 @@ func (s *SimpleStrategy) Execute(stars []models.Star, flights []models.Flight, l | |||
continue | |||
} | |||
// Wait till we have at least 30 ships | |||
if s.Ships < 30 { | |||
// Wait till we have a sufficient number of ships | |||
if s.Ships < 10 { | |||
continue | |||
} | |||
@@ -46,30 +37,24 @@ func (s *SimpleStrategy) Execute(stars []models.Star, flights []models.Flight, l | |||
// 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 := calculateDistanceCeiling(&t, &s) | |||
////fmt.Println(flightTurnDistance) | |||
//if flightTurnDistance > 60 { | |||
// continue | |||
//} | |||
flightTurnDistance := flightTurnDistance(s, t) | |||
if flightTurnDistance > 6 { | |||
continue | |||
} | |||
// If enemy star, make sure we have enough ships to attack it | |||
//if t.Owner == 2 && (s.Ships - (t.Ships + (flightTurnDistance * t.Richness))) <= 1 { | |||
if t.Owner == 2 && (s.Ships/2)-(t.Ships+(6*t.Richness)) < 0 { | |||
insufficientShips := (s.Ships / 2) <= ((t.Ships + (flightTurnDistance * t.Richness)) + 5) | |||
if t.Owner == 2 && insufficientShips { | |||
continue | |||
} | |||
// TODO: Find best destination | |||
// Fly to this target, and skip processing all remaining potential target stars | |||
fmt.Printf("fly %d %d %d\n", i, j, s.Ships/2) | |||
total++ | |||
break | |||
} | |||
// We can only schedule 3 flights per round | |||
if total == 3 { | |||
s.FlightsAllowed-- | |||
break | |||
} | |||
} | |||
fmt.Println("done") | |||
} |