Skip to content

Commit

Permalink
Added forager selection and scrum effect.
Browse files Browse the repository at this point in the history
  • Loading branch information
pguillory committed Nov 26, 2011
1 parent eaac4eb commit f45c53d
Show file tree
Hide file tree
Showing 13 changed files with 13,767 additions and 78 deletions.
2 changes: 1 addition & 1 deletion Army.go
Expand Up @@ -33,7 +33,7 @@ func (this *Army) IsSoldierAt(p Point) bool {
}

func (this *Army) IsBerzerkerAt(p Point) bool {
return (this.CountAt(p) >= 12)
return (this.CountAt(p) >= 15)
//return (this.CountAt(p) >= 20 && this.terrain.EnemiesVisibleFrom(p) < this.terrain.AlliesVisibleFrom(p))
}

Expand Down
59 changes: 43 additions & 16 deletions Bot.go
Expand Up @@ -7,28 +7,28 @@ type Bot struct {
terrain, update *Terrain
mystery *Mystery
potentialEnemy *PotentialEnemy
distanceToTrouble *TravelDistance
scrum *Scrum
distanceToFood, distanceToTrouble, distanceToDoom *TravelDistance
army *Army
predictions *Predictions
command *Command
hud *os.File
hudCenter Point
}

func (this *Bot) Ready() {
VerifySituationSize()

this.terrain = new(Terrain)
//this.distanceToEnemy = DistanceToEnemy(this.terrain)
//this.distanceToFriendlyHill = DistanceToFriendlyHill(this.terrain)
//this.mystery = NewMystery(this.terrain)
//this.forageScent = NewForageScent(this.terrain, this.distanceToEnemy, this.distanceToFriendlyHill, this.mystery)
//this.battleScent = NewBattleScent(this.terrain, this.distanceToEnemy, this.distanceToFriendlyHill, this.mystery)
this.mystery = NewMystery(this.terrain)
this.potentialEnemy = NewPotentialEnemy(this.terrain)
this.distanceToTrouble = DistanceToTrouble(this.terrain, this.mystery, this.potentialEnemy)
this.army = NewArmy(this.terrain)
this.predictions = NewPredictions(this.terrain)
this.command = NewCommand(this.terrain, this.army, this.predictions, this.distanceToTrouble)
this.scrum = NewScrum()
this.distanceToFood = DistanceToFood(this.terrain)
this.distanceToTrouble = DistanceToTrouble(this.terrain, this.mystery, this.potentialEnemy, this.scrum)
this.distanceToDoom = DistanceToDoom(this.terrain, this.mystery, this.potentialEnemy, this.scrum)
this.command = NewCommand(this.terrain, this.army, this.predictions, this.scrum, this.distanceToFood, this.distanceToTrouble, this.distanceToDoom)

this.hud = NewLog("hud", "txt")
}
Expand Down Expand Up @@ -61,6 +61,13 @@ func (this *Bot) Go(issueOrder func(int, int, byte), done func()) {

this.mystery.Calculate()
this.potentialEnemy.Calculate()
this.army.Calculate()
this.predictions.Calculate()
/*
this.distanceToFood.Calculate()
this.distanceToTrouble.Calculate()
this.distanceToDoom.Calculate()
*/
this.command.Calculate()

this.command.ForEach(func(move Move) {
Expand All @@ -69,8 +76,9 @@ func (this *Bot) Go(issueOrder func(int, int, byte), done func()) {
done()

// TODO: do this in a goroutine
this.hud.WriteString(fmt.Sprintf("%v\n", this.ColorString()))
//this.hud.WriteString(fmt.Sprintf("turn %v, times: map %v, dH %v, dE %v, myst %v, for %v, army %v, pred %v, comm %v\n", turn, this.terrain.time, this.distanceToFriendlyHill.time, this.distanceToEnemy.time, this.mystery.time, this.forageScent.time, this.army.time, this.predictions.time, this.command.time))
this.hud.WriteString(fmt.Sprintf("\n%v\n", this.ColorString()))
this.hud.WriteString(fmt.Sprintf("turn %v, times: map %v, myst %v, potE %v, army %v, pred %v, dF %v, dT %v, dD %v, comm %v", turn,
this.terrain.time, this.mystery.time, this.potentialEnemy.time, this.army.time, this.predictions.time, this.distanceToFood.time, this.distanceToTrouble.time, this.distanceToDoom.time, this.command.time))
//NewTurnLog("map", "txt").WriteString(this.terrain.String())
//NewTurnLog("mystery", "txt").WriteString(this.mystery.String())
//NewTurnLog("potentialEnemy", "txt").WriteString(this.potentialEnemy.String())
Expand All @@ -83,7 +91,19 @@ func (this *Bot) Go(issueOrder func(int, int, byte), done func()) {
}

func (this *Bot) ColorString() string {
return GridToColorString(func(p Point) ColorChar {
ForEachPoint(func(p Point) {
if this.terrain.At(p).HasFriendlyHill() {
this.hudCenter = p
}
})

topLeftCorner := this.hudCenter.Plus(Point{-25, -85})
if cols < 170 {
topLeftCorner.col -= (cols - 170) / 2
}

return GridToColorString(func(p1 Point) ColorChar {
p := p1.Plus(topLeftCorner)
s := this.terrain.At(p)

background := BLACK + HIGH_INTENSITY
Expand All @@ -92,9 +112,6 @@ func (this *Bot) ColorString() string {
}

style := 0
if this.army.IsSoldierAt(p) {
style = UNDERLINE
}

switch {
case s.HasLand():
Expand All @@ -109,7 +126,13 @@ func (this *Bot) ColorString() string {
}
case s.HasAnt():
if s.IsFriendly() {
return ColorChar{'a' + byte(s.owner), GREEN, background, style}
if this.army.IsBerzerkerAt(p) {
return ColorChar{'a' + byte(s.owner), MAGENTA, background, style}
//} else if this.army.IsSoldierAt(p) {
// return ColorChar{'a' + byte(s.owner), CYAN, background, style}
} else {
return ColorChar{'a' + byte(s.owner), GREEN, background, style}
}
} else {
return ColorChar{'a' + byte(s.owner), RED, background, style}
}
Expand All @@ -120,7 +143,11 @@ func (this *Bot) ColorString() string {
return ColorChar{' ', BLACK, HIGH_INTENSITY + RED, style}
}
}
return ColorChar{'.', HIGH_INTENSITY + BLACK, background, style}
if this.potentialEnemy.At(p) {
return ColorChar{'.', RED, background, style}
} else {
return ColorChar{'.', HIGH_INTENSITY + BLACK, background, style}
}
case s.HasWater():
return ColorChar{'%', BLUE, background, style}
}
Expand Down
73 changes: 60 additions & 13 deletions Command.go
@@ -1,3 +1,10 @@
/*
TODO:
break into two modules
tactical
scent-based
*/

package main

//import "fmt"
Expand All @@ -8,21 +15,24 @@ type Command struct {
terrain *Terrain
army *Army
predictions *Predictions
distanceToTrouble, distanceToFood *TravelDistance
foragers *PointSet
scrum *Scrum
distanceToFood, distanceToTrouble, distanceToDoom *TravelDistance
moves, enemyMoves *MoveSet
enemyDestinations *PointSet
friendlyFocus, maxFriendlyFocus *Focus
//dirs [MAX_ROWS][MAX_COLS]Direction
//len int
}

func NewCommand(terrain *Terrain, army *Army, predictions *Predictions, distanceToTrouble *TravelDistance) *Command {
func NewCommand(terrain *Terrain, army *Army, predictions *Predictions, scrum *Scrum, distanceToFood, distanceToTrouble, distanceToDoom *TravelDistance) *Command {
this := new(Command)
this.terrain = terrain
this.army = army
this.predictions = predictions
this.scrum = scrum
this.distanceToFood = distanceToFood
this.distanceToTrouble = distanceToTrouble
this.distanceToDoom = distanceToDoom

this.Calculate()
return this
Expand Down Expand Up @@ -52,6 +62,8 @@ func (this *Command) Reset() {
if s.HasWater() || s.HasFood() {
this.moves.ExcludeMovesTo(p)
this.enemyMoves.ExcludeMovesTo(p)
} else if s.HasFriendlyHill() {
this.moves.ExcludeMovesTo(p)
}
})
}
Expand Down Expand Up @@ -94,6 +106,8 @@ func (this *Command) PruneOutfocusedMoves() {
//log.WriteString(fmt.Sprintf("friendlyFocus: %v ms\n", timer.times["friendlyFocus"]))
//log.WriteString(fmt.Sprintf("%v\n\n", this.friendlyFocus))

this.scrum.Reset()

for i := 0; i < 10; i++ {
//log.WriteString(fmt.Sprintf("\n\n*** iteration %v ***\n\n", i))

Expand All @@ -117,6 +131,10 @@ func (this *Command) PruneOutfocusedMoves() {
//log.WriteString(fmt.Sprintf("ExcludeMovesTo(%v)\n", p))
this.moves.ExcludeMovesTo(p)
changed = true

ForEachNeighbor(p, func(p2 Point) {
this.scrum.Include(p2)
})
}
})
timer.Stop()
Expand Down Expand Up @@ -153,6 +171,7 @@ func (this *Command) DoomedAntsTakeHeart() {
})
}

/*
func (this *Command) ValueAt(p Point) float32 {
//if this.friendlyFocus.At(p) >= this.maxFriendlyFocus.At(p) {
// return this.forageScent.At(p) - float32(this.friendlyFocus.At(p)) * 1e30
Expand All @@ -166,6 +185,7 @@ func (this *Command) ForageValueAt(p Point) float32 {
d := this.distanceToFood.At(p)
return -float32(d * d)
}
*/

/*
func (this *Command) ArmyValueAt(p Point) float32 {
Expand All @@ -179,22 +199,52 @@ func (this *Command) ArmyValueAt(p Point) float32 {
func (this *Command) PickBestMoves() {
//log := NewTurnLog("PickBestMoves", "txt")

foragers := AssignForagers(this.terrain)

list := this.moves.OrderedList(func(move Move) float32 {
//if this.army.IsSoldierAt(move.from) {
// return this.ArmyValueAt(move.Destination()) - this.ArmyValueAt(move.from)
//}
if this.foragers.Includes(move.from) {
return this.ForageValueAt(move.Destination()) - this.ValueAt(move.from)
destination := move.Destination()

var result int
switch {
case foragers.Includes(move.from):
result += this.distanceToFood.At(move.from)
result -= this.distanceToFood.At(destination)
case this.distanceToTrouble.At(move.from) < MAX_TRAVEL_DISTANCE:
result += this.distanceToTrouble.At(move.from)
result -= this.distanceToTrouble.At(destination)
default:
result += this.distanceToDoom.At(move.from)
result -= this.distanceToDoom.At(destination)
}
return this.ValueAt(move.Destination()) - this.ValueAt(move.from)

//fromFocus := this.friendlyFocus.At(move.from)
//if fromFocus >= this.maxFriendlyFocus.At(move.from) {
// result -= int(fromFocus) * 10
//} else {
// result += int(fromFocus) * 10
//}
//
//toFocus := this.friendlyFocus.At(destination)
//if toFocus >= this.maxFriendlyFocus.At(move.from) {
// result += int(toFocus) * 10
//} else {
// result -= int(toFocus) * 10
//}

return float32(result)
})

list.ForBestWorst(func(move Move) bool {
return this.moves.Includes(move)
}, func(move Move) {
// best move
//log.WriteString(fmt.Sprintf("Select %v\n", move))
this.moves.Select(move)
}, func(move Move) {
// worst move
if this.moves.At(move.from).IsMultiple() {
//log.WriteString(fmt.Sprintf("Exclude %v\n", move))
this.moves.Exclude(move)
Expand Down Expand Up @@ -226,13 +276,6 @@ func (this *Command) SaveCrushedAntsAt(p Point) {
// p2 = neighbor(p, WEST); exclude_move(p2, EAST); save_crushed_ant(p2);

func (this *Command) Calculate() {
this.distanceToTrouble.Calculate()
this.army.Calculate()
this.predictions.Calculate()
//this.distanceToTrouble = DistanceToTrouble(this.terrain)
this.distanceToFood = DistanceToFood(this.terrain)
this.foragers = AssignForagers(this.terrain)

if this.turn == turn {
return
}
Expand All @@ -257,6 +300,10 @@ func (this *Command) Calculate() {
//this.DoomedAntsTakeHeart()
//timer.Stop()

this.distanceToFood.Calculate()
this.distanceToTrouble.Calculate()
this.distanceToDoom.Calculate()

timer.Start("PickBestMoves")
this.PickBestMoves()
timer.Stop()
Expand Down
14 changes: 10 additions & 4 deletions Command_test.go
Expand Up @@ -19,8 +19,11 @@ func TestFollowScentThroughMaze(t *testing.T) {
predictions := NewPredictions(terrain)
mystery := NewMystery(terrain)
potentialEnemy := NewPotentialEnemy(terrain)
distanceToTrouble := DistanceToTrouble(terrain, mystery, potentialEnemy)
command := NewCommand(terrain, army, predictions, distanceToTrouble)
scrum := NewScrum()
distanceToFood := DistanceToFood(terrain)
distanceToTrouble := DistanceToTrouble(terrain, mystery, potentialEnemy, scrum)
distanceToDoom := DistanceToTrouble(terrain, mystery, potentialEnemy, scrum)
command := NewCommand(terrain, army, predictions, scrum, distanceToFood, distanceToTrouble, distanceToDoom)

if command.At(Point{1, 1}) != SOUTH {
//t.Error(forageScent)
Expand Down Expand Up @@ -48,8 +51,11 @@ func TestMoves(t *testing.T) {
predictions := NewPredictions(terrain)
mystery := NewMystery(terrain)
potentialEnemy := NewPotentialEnemy(terrain)
distanceToTrouble := DistanceToTrouble(terrain, mystery, potentialEnemy)
command := NewCommand(terrain, army, predictions, distanceToTrouble)
scrum := NewScrum()
distanceToFood := DistanceToFood(terrain)
distanceToTrouble := DistanceToTrouble(terrain, mystery, potentialEnemy, scrum)
distanceToDoom := DistanceToTrouble(terrain, mystery, potentialEnemy, scrum)
command := NewCommand(terrain, army, predictions, scrum, distanceToFood, distanceToTrouble, distanceToDoom)

command.Reset()
before := command.At(Point{2, 0})
Expand Down
47 changes: 35 additions & 12 deletions Distance.go
Expand Up @@ -4,7 +4,7 @@ package main

type Distance uint16

const MAX_TRAVEL_DISTANCE = Distance(MAX_ROWS * MAX_COLS)
const MAX_TRAVEL_DISTANCE = MAX_ROWS * MAX_COLS

type TravelDistance struct {
time int64
Expand Down Expand Up @@ -46,24 +46,23 @@ func DistanceToFood(terrain *Terrain) *TravelDistance {
return distance
}

func DistanceToTrouble(terrain *Terrain, mystery *Mystery, potentialEnemy *PotentialEnemy) *TravelDistance {
mystery.Calculate()
potentialEnemy.Calculate()

distance := NewTravelDistance(func(p Point) (result Distance) {
square := terrain.At(p)
func DistanceToTrouble(terrain *Terrain, mystery *Mystery, potentialEnemy *PotentialEnemy, scrum *Scrum) *TravelDistance {
distance := NewTravelDistance(func(p Point) Distance {
switch {
case square.HasEnemyHill():
case terrain.At(p).HasEnemyHill():
return 0
case mystery.At(p) >= 100:
case mystery.At(p) >= 50:
return 10
case potentialEnemy.At(p):
return 15
case mystery.At(p) >= 50:
return 20
case mystery.At(p) >= 2:
return 30
case mystery.At(p) >= 1:
return 31
case scrum.At(p):
return 200
}
return MAX_TRAVEL_DISTANCE
//result = 5 + distanceToPotentialEnemy.At(p)
}, func(p Point) bool {
square := terrain.At(p)
return !square.HasWater() && !square.HasFriendlyAnt()
Expand All @@ -75,6 +74,30 @@ func DistanceToTrouble(terrain *Terrain, mystery *Mystery, potentialEnemy *Poten
return distance
}

func DistanceToDoom(terrain *Terrain, mystery *Mystery, potentialEnemy *PotentialEnemy, scrum *Scrum) *TravelDistance {
distance := NewTravelDistance(func(p Point) Distance {
switch {
case terrain.At(p).HasEnemyHill():
return 0
case mystery.At(p) >= 50:
return 10
case potentialEnemy.At(p):
return 15
case scrum.At(p):
return 200
}
return MAX_TRAVEL_DISTANCE
}, func(p Point) bool {
square := terrain.At(p)
return !square.HasWater()
}, func(p Point) bool {
square := terrain.At(p)
return !square.HasWater()
})

return distance
}

func AssignForagers(terrain *Terrain) *PointSet {
land := new(PointSet)
food := new(PointSet)
Expand Down

0 comments on commit f45c53d

Please sign in to comment.