Skip to content

Commit 4031c3a

Browse files
committed
Merge branch 'rewrite'
2 parents 85f67c5 + 49503ff commit 4031c3a

File tree

5 files changed

+520
-296
lines changed

5 files changed

+520
-296
lines changed

config.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,16 @@ func DefaultConfig() *Config {
2525
}
2626

2727
func ReadConfig(filepath string) (*Config, error) {
28+
config := DefaultConfig()
2829
f, err := os.Open(filepath)
2930
if err != nil {
30-
return nil, err
31+
return config, err
3132
}
3233
defer f.Close()
3334
d := json.NewDecoder(f)
34-
config := DefaultConfig()
3535
err = d.Decode(config)
3636
overrideByFlags(config)
37-
return config, nil
37+
return config, err
3838
}
3939

4040
var portFlag = flag.Int("port", 0, "the port number to listen on")

event_stream.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package main
2+
3+
import (
4+
"time"
5+
6+
"github.com/ughoavgfhw/libkq/io"
7+
)
8+
9+
type baseDataEventKey int
10+
11+
const (
12+
CabMessageKey baseDataEventKey = iota
13+
ControlCommandKey
14+
)
15+
16+
type EventType int
17+
18+
const (
19+
InvalidEventType EventType = iota
20+
CabMessageEvent
21+
ControlEvent
22+
)
23+
24+
type Event struct {
25+
When time.Time
26+
Type EventType
27+
Data map[interface{}]interface{}
28+
IsTick bool
29+
}
30+
31+
func EventWithMessage(msg *kqio.Message, tick bool) *Event {
32+
e := &Event{msg.Time, CabMessageEvent, make(map[interface{}]interface{}), tick}
33+
e.Data[CabMessageKey] = msg
34+
return e
35+
}
36+
37+
func NewControlEvent(commands []ControlCommand) *Event {
38+
e := &Event{time.Now(), ControlEvent, make(map[interface{}]interface{}), false}
39+
e.Data[ControlCommandKey] = commands
40+
return e
41+
}
42+
43+
type EventStream chan *Event
44+
45+
func NewEventStream() EventStream {
46+
return make(chan *Event, 8)
47+
}
48+
49+
func (strm EventStream) Close() error {
50+
close(strm)
51+
return nil
52+
}
53+
54+
// Adds an event to the stream. May block.
55+
func (strm EventStream) AddEvent(event *Event) {
56+
strm <- event
57+
}
58+
59+
// Reads an event from the stream. May block.
60+
func (strm EventStream) Next() *Event {
61+
return <-strm
62+
}

famine_tracking.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import (
77
"github.com/ughoavgfhw/libkq/maps"
88
)
99

10+
type famineUpdateEventKey int
11+
12+
var FamineUpdateKey famineUpdateEventKey
13+
1014
type FamineUpdate struct {
1115
BerriesLeft int
1216
FamineStart time.Time
@@ -15,21 +19,20 @@ type FamineUpdate struct {
1519

1620
type FamineTracker struct {
1721
berryCount int
18-
broadcast chan<- interface{}
1922
}
2023

21-
func NewFamineTracker(broadcast chan<- interface{}) *FamineTracker {
22-
return &FamineTracker{0, broadcast}
24+
func NewFamineTracker() *FamineTracker {
25+
return &FamineTracker{0}
2326
}
2427

25-
func (ft *FamineTracker) Update(when time.Time, state *kq.GameState, isTick bool) {
28+
func (ft *FamineTracker) Update(event *Event, state *kq.GameState) {
2629
mapData := maps.MetadataForMap(state.Map)
2730
if mapData == nil {
2831
return
2932
}
3033
berries := mapData.BerriesAvailable - state.BerriesUsed
31-
if berries != ft.berryCount || (state.InFamine() && isTick) {
34+
if berries != ft.berryCount || (state.InFamine() && event.IsTick) {
3235
ft.berryCount = berries
33-
ft.broadcast <- FamineUpdate{berries, state.FamineStart, when}
36+
event.Data[FamineUpdateKey] = FamineUpdate{berries, state.FamineStart, event.When}
3437
}
3538
}

main.go

+21-38
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"flag"
55
"fmt"
66
"io"
7-
"io/ioutil"
87
"os"
98
"strings"
109
"time"
@@ -17,8 +16,6 @@ import (
1716
)
1817

1918
var (
20-
msgDump = ioutil.Discard
21-
snailDebug = ioutil.Discard
2219
logOut = os.Stderr
2320
predictionOut = os.Stdout
2421
csvOut io.Writer // Opened in main
@@ -220,18 +217,12 @@ func updateState(msg kqio.Message, game *kq.GameState) bool {
220217
data := msg.Val.(parser.GetOnSnailMessage)
221218
game.Players[data.Rider.Index()].OnSnail = 1
222219
pos := data.Pos.X - game.Snails[0].MaxPos
223-
if pos != game.Snails[0].Pos {
224-
fmt.Fprintf(snailDebug, "%v: The snail moved from %v to %v without a rider\n",
225-
msg.Time, game.Snails[0].Pos, pos)
226-
}
227220
// running drone speed 250 px/s. may be 1925ish pixels to wrap
228221
// robot 200 px/s
229222
// eat takes 3.5s, arantius vid says 3.67
230223
if game.Players[data.Rider.Index()].HasSpeed {
231-
fmt.Fprintln(snailDebug, "rider has speed")
232224
snailSpeed = 28.209890875 // 27
233225
} else {
234-
fmt.Fprintln(snailDebug, "rider is slow")
235226
snailSpeed = 20.896215463 // 20
236227
}
237228
if data.Rider.Team() == BlueSide {
@@ -245,13 +236,6 @@ func updateState(msg kqio.Message, game *kq.GameState) bool {
245236
}
246237
data := msg.Val.(parser.GetOffSnailMessage)
247238
game.Players[data.Rider.Index()].OnSnail = 0
248-
fmt.Fprintf(snailDebug, "Off: The snail moved by %v pixels in %v, %v px/s\n",
249-
data.Pos.X-game.Snails[0].MaxPos-game.Snails[0].Pos,
250-
msg.Time.Sub(snailTime),
251-
float64(data.Pos.X-game.Snails[0].MaxPos-game.Snails[0].Pos)/
252-
float64(msg.Time.Sub(snailTime)/time.Millisecond)*1000)
253-
fmt.Fprintf(snailDebug, "Estimated snail position is %v, actual is %v, diff %v\n",
254-
snailEstimate(msg.Time, game), data.Pos.X-game.Snails[0].MaxPos, data.Pos.X-game.Snails[0].MaxPos-snailEstimate(msg.Time, game))
255239
game.Snails[0].Pos = data.Pos.X - game.Snails[0].MaxPos
256240
snailTime = msg.Time
257241
snailSpeed = 0
@@ -260,13 +244,6 @@ func updateState(msg kqio.Message, game *kq.GameState) bool {
260244
return false
261245
}
262246
data := msg.Val.(parser.SnailStartEatMessage)
263-
fmt.Fprintf(snailDebug, "Eat: The snail moved by %v pixels in %v, %v px/s\n",
264-
data.Pos.X-game.Snails[0].MaxPos-game.Snails[0].Pos,
265-
msg.Time.Sub(snailTime),
266-
float64(data.Pos.X-game.Snails[0].MaxPos-game.Snails[0].Pos)/
267-
float64(msg.Time.Sub(snailTime)/time.Millisecond)*1000)
268-
fmt.Fprintf(snailDebug, "Estimated snail position is %v, actual is %v, diff %v\n",
269-
snailEstimate(msg.Time, game), data.Pos.X-game.Snails[0].MaxPos, data.Pos.X-game.Snails[0].MaxPos-snailEstimate(msg.Time, game))
270247
game.Snails[0].Pos = data.Pos.X - game.Snails[0].MaxPos
271248
snailTime = msg.Time.Add(3500 * time.Millisecond)
272249
case "snailEscape":
@@ -281,14 +258,10 @@ func updateState(msg kqio.Message, game *kq.GameState) bool {
281258
} else {
282259
offset = 50
283260
}
261+
// In theory, the snail shouldn't move while someone is sacrificing.
262+
// In practice it can, either because it got pushed with a berry or
263+
// because the sacrifice carried momentum into the snail.
284264
pos := data.Pos.X - game.Snails[0].MaxPos + offset
285-
if pos != game.Snails[0].Pos {
286-
// In theory, the snail shouldn't move while someone is sacrificing.
287-
// In practice it can, either because it got pushed with a berry or
288-
// because the sacrifice carried momentum into the snail.
289-
fmt.Fprintf(snailDebug, "%v: The snail moved from %v to %v during a sacrifice\n",
290-
msg.Time, game.Snails[0].Pos, pos)
291-
}
292265
game.Snails[0].Pos = pos
293266
snailTime = msg.Time
294267
case "berryDeposit":
@@ -757,14 +730,22 @@ func updateStats(msg *kqio.Message, state *kq.GameState) {
757730

758731
var configPath = flag.String("config", "config.json", "the path to the config file; it is not an error if this file does not exist")
759732

733+
type mainEventKey int
734+
735+
const (
736+
GameStartTimeKey mainEventKey = iota
737+
StatsUpdateKey
738+
)
739+
760740
func main() {
761741
flag.Parse()
762742
config, e := ReadConfig(*configPath)
763743
if e != nil && !os.IsNotExist(e) {
764744
panic(fmt.Sprintf("Failed to load config %v", e))
765745
}
766-
broadcast := make(chan interface{})
767-
go startWebServer(fmt.Sprintf(":%d", config.ServerPort), broadcast)
746+
eventStream := NewEventStream()
747+
defer eventStream.Close()
748+
go startWebServer(fmt.Sprintf(":%d", config.ServerPort), eventStream)
768749
<-time.After(5 * time.Second)
769750
webStartTime, _ := time.Parse(time.RFC3339Nano, "2018-10-20T18:39:49.376-05:00")
770751

@@ -799,7 +780,7 @@ func main() {
799780
fmt.Fprintln(csvOut, CsvHeader)
800781
ticker := time.NewTicker(100 * time.Millisecond)
801782
defer ticker.Stop()
802-
famine := NewFamineTracker(broadcast)
783+
famine := NewFamineTracker()
803784
for {
804785
var isTick bool
805786
select {
@@ -811,18 +792,18 @@ func main() {
811792

812793
e = reader.ReadMessage(&msg)
813794
if e != nil {
814-
fmt.Fprintln(msgDump, "read error", e)
815795
if e == io.EOF {
816796
break
817797
}
818798
continue
819799
}
820-
fmt.Fprintln(msgDump, msg)
800+
801+
event := EventWithMessage(&msg, isTick)
821802
updateStats(&msg, state)
822803
if (updateState(msg, state) || isTick) && !state.Start.IsZero() && (state.InGame() || msg.Type == "victory") {
823804
fmt.Fprintln(csvOut, &CsvPrinter{state.Map, msg.Time.Sub(state.Start), msg.Time, *state})
824805
if msg.Type == "gamestart" {
825-
broadcast <- msg.Time
806+
event.Data[GameStartTimeKey] = msg.Time
826807
} else if !msg.Time.Before(webStartTime) {
827808
var dp dataPoint
828809
dp.when = msg.Time
@@ -844,7 +825,7 @@ func main() {
844825
dp.winner = msg.Val.(parser.GameResultMessage).Winner.String()
845826
dp.winType = msg.Val.(parser.GameResultMessage).EndCondition.String()
846827
}
847-
broadcast <- dp
828+
event.Data[StatsUpdateKey] = dp
848829
}
849830
if score != nil {
850831
s := score(state, msg.Time)
@@ -861,7 +842,9 @@ func main() {
861842
}
862843

863844
if state.InGame() {
864-
famine.Update(msg.Time, state, isTick)
845+
famine.Update(event, state)
865846
}
847+
848+
eventStream.AddEvent(event)
866849
}
867850
}

0 commit comments

Comments
 (0)