-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaliens.go
145 lines (124 loc) · 3.79 KB
/
aliens.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package main
import (
"fmt"
"math/rand"
"strings"
)
// Choosing to attach the aliens to the city instead of attaching the city to the aliens because it's simpler to find alien collisions
type AlienName *string
type CityAliens []AlienName
func (rm RoadMap) moveAliens() {
// We can't just loop through every city and move the aliens around; we
// would end up moving some aliens multiple times. Instead, we do one
// sweep where we determine where to move to, and a second sweep to
// actually move them.
alienMoves := make(map[*City]CityAliens)
for _, city := range rm {
// Put neighbor cities in a slice so we can easily pick on at random
var neighborCities [](*City)
if city.roads.north != nil {
neighborCities = append(neighborCities, city.roads.north)
}
if city.roads.east != nil {
neighborCities = append(neighborCities, city.roads.east)
}
if city.roads.south != nil {
neighborCities = append(neighborCities, city.roads.south)
}
if city.roads.west != nil {
neighborCities = append(neighborCities, city.roads.west)
}
// If there are no roads out of this city, all aliens in this
// city are trapped. Indicate that the list of aliens does not
// change.
if len(neighborCities) == 0 {
alienMoves[city] = city.aliens
continue
}
// If there are roads, pick a neighbor city at random for each
// alien and indicate that they will move there.
for _, alien := range city.aliens {
nextCity := neighborCities[rand.Intn(len(neighborCities))]
alienMoves[nextCity] = append(alienMoves[nextCity], alien)
}
}
// Actually move the aliens to their new destinations
for _, city := range rm {
// If city is not in alienMoves, alienMoves[city].aliens will
// be empty, which is what we want here anyway.
city.aliens = alienMoves[city]
}
}
func (rm RoadMap) fightAliens() {
for cityName, city := range rm {
// If 2 or more aliens can land on the same city, they destroy the city (and
// each other).
if len(city.aliens) > 1 {
rm.destroyCity(cityName)
}
}
}
func (rm RoadMap) setInitialAliens(numAliens int) {
// Since we're picking at random we'll want cities integer-indexed
var cities [](*City)
for _, city := range rm {
cities = append(cities, city)
}
for x := 0; x < numAliens; x++ {
index := rand.Intn(len(rm))
// pass a unique x in for each alien so it generates a unique name
cities[index].aliens = append(cities[index].aliens, generateAlienName(x))
}
}
// list of all aliens in this city formatted in English
// ex: "a, b and c"
func (ca CityAliens) englishList() string {
// Special cases that don't fit the below formula
if len(ca) == 0 {
return ""
}
if len(ca) == 1 {
return *ca[0]
}
// To []string so that we can use Join on them
var alienNameStrings []string
for _, alienName := range ca {
alienNameStrings = append(alienNameStrings, *alienName)
}
// Comma separate all but the last alien
alienList := strings.Join(alienNameStrings[:len(alienNameStrings)-1], ", ")
// ...and [last alien]
alienList += " and " + alienNameStrings[len(alienNameStrings)-1]
return alienList
}
func generateAlienName(seed int) AlienName {
// Pick 4 different name segments. With order mattering, that's 3000+ alien names.
// If we need more, we start appending numbers.
segments := []string{
"goom",
"kor",
"mon",
"zor",
"xan",
"blax",
"thu",
"blar",
"yaf",
}
name := ""
for x := 0; x < 4; x++ {
index := seed % len(segments)
seed /= len(segments)
name += segments[index]
segments = append(segments[0:index], segments[index+1:]...)
}
// If we really need so many names, start appending numbers
// Start with 2 (un-numbered would imply 1)
if seed > 0 {
name += fmt.Sprintf(" %d", seed+1)
}
// Capitalize the first letter
firstLetter := name[0] + 'A' - 'a'
name = string(firstLetter) + name[1:]
return AlienName(&name)
}