func benchmarkChunkMergerWithOutOfOrderChunks(b *testing.B, merger core.ChunkMerger) { b.StopTimer() chunks := make([]core.Chunk, b.N) for i := range chunks { chunks[i] = largePackets[i%len(largePackets)] chunks[i].Sequence = core.SequenceId(i) } c := cmwc.MakeGoodCmwc() c.Seed(123) rng := rand.New(c) // Shuffle blocks of 1000 at a time for i := 0; i < len(chunks); i += 1000 { max := len(chunks) if max > 1000 { max = 1000 } for j := 0; j < max; j++ { swap := rng.Intn(max-j) + j chunks[j], chunks[swap] = chunks[swap], chunks[j] } } b.StartTimer() for i := range chunks { merger.AddChunk(chunks[i]) } }
func makeFakeBlockingConn(dropFrac float64) *fakeBlockingConn { var fbc fakeBlockingConn fbc.in = make(chan []byte) fbc.out = make(chan []byte) fbc.dropFrac = dropFrac c := cmwc.MakeGoodCmwc() c.Seed(123) fbc.rng = rand.New(c) go fbc.run() return &fbc }
func TestZigAndZagWork(t *testing.T) { var diag core.Block64_32 // Set up a block so that lower values are in the upper-left and higher values are in the lower // right. A zig should sort this. for x := 0; x < 8; x++ { for y := 0; y < 8; y++ { diag[x+y*8] = int32(x + y) } } Convey("Slow versions are correct.", t, func() { var sorted core.Block64_32 copy(sorted[:], diag[:]) core.ZigSlow(&sorted) So(sorted, shouldBeSorted) core.ZagSlow(&sorted) So(sorted, ShouldResemble, diag) }) Convey("Fast versions match the slow versions.", t, func() { c := cmwc.MakeGoodCmwc() for i := 0; i < 100; i++ { c.Seed(int64(i)) rng := rand.New(c) var b0, b1, b2 core.Block64_32 for i := range b0 { b0[i] = rng.Int31() } copy(b1[:], b0[:]) copy(b2[:], b0[:]) So(b1, ShouldResemble, b0) So(b2, ShouldResemble, b0) core.ZigSlow(&b0) core.Zig(&b1) So(b1, ShouldResemble, b0) core.ZagSlow(&b0) core.Zag(&b1) So(b1, ShouldResemble, b0) So(b1, ShouldResemble, b2) } }) }
func (f *fireProcess) Think(g *game.Game) { player, ok := g.Ents[f.Gid].(*game.PlayerEnt) if !ok { return } f.Pos = player.Position f.Stored *= 0.97 if f.rng == nil { f.rng = cmwc.MakeGoodCmwc() f.rng.SeedWithDevRand() } max := int(f.Stored / 15) algorithm.Choose(&f.explosions, func(e fireExplosion) bool { return !e.Done() }) if len(f.explosions) < max { f.explosions = append(f.explosions, fireDoLine(f.rng, player.Position, player.Angle, f.Stored, 3, g.Levels[player.CurrentLevel])) } for i := range f.explosions { f.explosions[i].Think() } f.thinks++ }
func main() { fmt.Printf("%v\n", key_map) sys.Startup() err := gl.Init() if err != nil { panic(err) } render.Init() render.Queue(func() { sys.CreateWindow(10, 10, wdx, wdy) sys.EnableVSync(true) err := gl.Init() if err != nil { panic(err) } }) base.InitShaders() runtime.GOMAXPROCS(2) ui, err = gui.Make(gin.In(), gui.Dims{wdx, wdy}, filepath.Join(datadir, "fonts", "skia.ttf")) if err != nil { panic(err) } sys.Think() for false && len(sys.GetActiveDevices()[gin.DeviceTypeController]) < 2 { time.Sleep(time.Millisecond * 100) sys.Think() } var ids []int var engine *cgf.Engine var room game.Room err = base.LoadJson(filepath.Join(base.GetDataDir(), "rooms/basic.json"), &room) if err != nil { panic(err) } if IsHost() { sys.Think() var g game.Game g.Rng = cmwc.MakeGoodCmwc() g.Rng.SeedWithDevRand() g.Dx = 900 g.Dy = 600 g.Friction = 0.97 g.Friction_lava = 0.85 g.Room = room var p game.Player p.Color.R = 255 err := json.NewDecoder(bytes.NewBuffer([]byte(` { "Base": { "Max_turn": 0.07, "Max_acc": 0.2, "Mass": 750, "Max_rate": 10, "Influence": 75, "Health": 1000 }, "Dynamic": { "Health": 1000 } } `))).Decode(&p.Stats) if err != nil { panic(err) } Nx := 2 Ny := 1 p.X = float64(g.Dx-Nx)/2 - 200 p.Y = float64(g.Dy-Ny)/2 - 200 for x := 0; x < Nx; x++ { for y := 0; y < Ny; y++ { p.X += float64(x * 25) p.Y += float64(y * 25) p.Gid++ // p.Mass += float64(x+y) * 150 p.Processes = make(map[int]game.Process) temp := p ids = append(ids, g.AddEnt(&temp)) // p.Mass -= float64(x+y) * 150 p.X -= float64(x * 25) p.Y -= float64(y * 25) } } g.Ents[0].(*game.Player).X = 500 g.Ents[0].(*game.Player).Y = 300 g.Ents[1].(*game.Player).X = 550 g.Ents[1].(*game.Player).Y = 300 g.SetLocalData() d := sys.GetActiveDevices() base.Log().Printf("%v\n", d) n := 0 base.Log().Printf("%v\n", d[gin.DeviceTypeController]) for _, index := range d[gin.DeviceTypeController] { // panic("ASD") g.SetLocalPlayer(g.Ents[n].(*game.Player), index) n++ if n > 2 { break } } if len(d[gin.DeviceTypeController]) == 0 { g.SetLocalPlayer(g.Ents[0].(*game.Player), 0) } // g.Ents[0], g.Ents[(N*N)/2+(1-N%2)*N/2] = g.Ents[(N*N)/2+(1-N%2)*N/2], g.Ents[0] g.Init() // engine, err = cgf.NewLocalEngine(&g, 17, base.Log()) engine, err = cgf.NewHostEngine(&g, 17, "", 1231, base.Log()) if err != nil { panic(err.Error()) } g.SetEngine(engine) } else { engine, err = cgf.NewClientEngine(17, "", 1231, base.Log()) if err != nil { panic(err.Error()) } engine.CopyState().(*game.Game).SetEngine(engine) } anchor := gui.MakeAnchorBox(gui.Dims{wdx, wdy}) ui.AddChild(anchor) anchor.AddChild(&game.GameWindow{Engine: engine}, gui.Anchor{0.5, 0.5, 0.5, 0.5}) var v float64 var profile_output *os.File var num_mem_profiles int // ui.AddChild(base.MakeConsole()) base.LoadAllDictionaries() for gin.In().GetKey(gin.AnyEscape).FramePressCount() == 0 { sys.Think() render.Queue(func() { ui.Draw() }) render.Queue(func() { sys.SwapBuffers() }) render.Purge() game.LocalThink() if IsHost() { for i := 0; i <= 0; i++ { // down_axis := gin.In().GetKeyFlat(gin.ControllerAxis0Positive+1, gin.DeviceTypeController, gin.DeviceIndexAny) // up_axis := gin.In().GetKeyFlat(gin.ControllerAxis0Negative+1, gin.DeviceTypeController, gin.DeviceIndexAny) // right_axis := gin.In().GetKeyFlat(gin.ControllerAxis0Positive, gin.DeviceTypeController, gin.DeviceIndexAny) // left_axis := gin.In().GetKeyFlat(gin.ControllerAxis0Negative, gin.DeviceTypeController, gin.DeviceIndexAny) // up := key_map[fmt.Sprintf("%dup", i)].FramePressAvg() // down := key_map[fmt.Sprintf("%ddown", i)].FramePressAvg() // left := key_map[fmt.Sprintf("%dleft", i)].FramePressAvg() // right := key_map[fmt.Sprintf("%dright", i)].FramePressAvg() // up = axisControl(up_axis.FramePressAmt()) // down = axisControl(down_axis.FramePressAmt()) // left = axisControl(left_axis.FramePressAmt()) // right = axisControl(right_axis.FramePressAmt()) // if up-down != 0 { // engine.ApplyEvent(game.Accelerate{ids[i], 2 * (up - down)}) // } // if left-right != 0 { // engine.ApplyEvent(game.Turn{ids[i], (left - right)}) // } // if key_map[fmt.Sprintf("%d-1", i)].FramePressCount() > 0 { // engine.ApplyEvent(game.Pull{ids[i], 0, 20000}) // } // if key_map[fmt.Sprintf("%d-2", i)].FramePressCount() > 0 { // engine.ApplyEvent(game.MoonFire{ids[i], 1, 50, 50}) // } // if gin.In().GetKeyFlat(gin.ControllerButton0, gin.DeviceTypeController, gin.DeviceTypeAny).FramePressCount() > 0 { // if key_map[fmt.Sprintf("%d-3", i)].FramePressCount() > 0 { // engine.ApplyEvent(game.Burst{ids[i], 2, 3, 100000}) // } } } // TODO: Replace the 'P' key with an appropriate keybind if gin.In().GetKey(gin.AnyKeyP).FramePressCount() > 0 { if profile_output == nil { profile_output, err = os.Create(filepath.Join(datadir, "cpu.prof")) if err == nil { err = pprof.StartCPUProfile(profile_output) if err != nil { fmt.Printf("Unable to start CPU profile: %v\n", err) profile_output.Close() profile_output = nil } fmt.Printf("profout: %v\n", profile_output) } else { fmt.Printf("Unable to start CPU profile: %v\n", err) } } else { pprof.StopCPUProfile() profile_output.Close() profile_output = nil } } // TODO: Replace the 'M' key with an appropriate keybind if gin.In().GetKey(gin.AnyKeyM).FramePressCount() > 0 { f, err := os.Create(filepath.Join(datadir, fmt.Sprintf("mem.%d.prof", num_mem_profiles))) if err != nil { base.Error().Printf("Unable to write mem profile: %v", err) } pprof.WriteHeapProfile(f) f.Close() num_mem_profiles++ } v += 0.01 } }
func TestClientRecvChunks(t *testing.T) { Convey("ClientRecvChunksHandler", t, func() { config := &core.Config{ Node: 5, Logger: log.New(os.Stdout, "", log.Lshortfile|log.Ltime), GlobalConfig: core.GlobalConfig{ Streams: map[core.StreamId]core.StreamConfig{ 7: core.StreamConfig{ Name: "UU", Id: 7, Mode: core.ModeUnreliableUnordered, }, 8: core.StreamConfig{ Name: "UO", Id: 8, Mode: core.ModeUnreliableOrdered, }, 9: core.StreamConfig{ Name: "RU", Id: 9, Mode: core.ModeReliableUnordered, }, 10: core.StreamConfig{ Name: "RO", Id: 10, Mode: core.ModeReliableOrdered, }, }, MaxChunkDataSize: 50, MaxUnreliableAge: 25, Confirmation: 10 * time.Millisecond, Clock: &clock.RealClock{}, }, Starts: map[core.Streamlet]core.SequenceId{ core.Streamlet{9, 777}: 5, core.Streamlet{10, 777}: 5, core.Streamlet{9, 778}: 25, core.Streamlet{10, 778}: 25, }, } fromHost := make(chan core.Chunk) toCore := make(chan core.Packet) toHost := make(chan core.Chunk) reserved := make(chan core.Chunk) handlerIsDone := make(chan struct{}) defer func() { close(fromHost) for { select { case <-handlerIsDone: close(toHost) close(toCore) return case <-toHost: case <-toCore: } } }() go func() { core.ClientRecvChunksHandler(config, fromHost, toCore, toHost, reserved) close(handlerIsDone) }() Convey("Unreserved chunks from fromHost get assembled into packets and sent to toCore.", func() { go func() { // This is just to make sure the routine doesn't block trying to send to the host. for range toHost { } }() go func() { var chunks []core.Chunk // The first packet is before the start of the stream, it should not get reported. chunks = append(chunks, makeChunks(config, config.GetIdFromName("RO"), 777, 0, 5)...) chunks = append(chunks, makeChunks(config, config.GetIdFromName("RO"), 777, 5, 5)...) chunks = append(chunks, makeChunks(config, config.GetIdFromName("RO"), 778, 25, 5)...) chunks = append(chunks, makeChunks(config, config.GetIdFromName("RO"), 777, 10, 5)...) for _, chunk := range chunks { fromHost <- chunk } }() So(verifyPacket((<-toCore).Data, config.GetIdFromName("RO"), 777, 5, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, config.GetIdFromName("RO"), 778, 25, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, config.GetIdFromName("RO"), 777, 10, 5), ShouldBeTrue) }) Convey("Reserved chunks from fromHost get sent directly through the reserved channel.", func() { go func() { // This is just to make sure the routine doesn't block trying to send to the host. for range toHost { } }() go func() { fromHost <- makeSimpleChunk(core.StreamTruncate, 1, 10) fromHost <- makeSimpleChunk(core.StreamPing, 1, 11) fromHost <- makeSimpleChunk(core.StreamDing, 1, 100) fromHost <- makeSimpleChunk(core.StreamResend, 1, 20) }() for i := 0; i < 4; i++ { chunk := <-reserved So(verifySimpleChunk(&chunk), ShouldBeTrue) } select { case <-toCore: panic("Should not have gotten anything from <-toCore") default: } }) Convey("Unreliable and Unordered streams might drop packets, and might deliver them out of order.", func() { go func() { // This is just to make sure the routine doesn't block trying to send to the host. for range toHost { } }() var node core.NodeId = 777 stream := config.GetIdFromName("UU") go func() { var chunks []core.Chunk // Send all but the first chunk for each packet. Note that the last packet is more // than MaxAge in the future from the first packet. chunkSets := [][]core.Chunk{ // The first packet is before the start of the stream, it should not get reported. makeChunks(config, stream, node, 0, 5), makeChunks(config, stream, node, 5, 5), makeChunks(config, stream, node, 10, 5), makeChunks(config, stream, node, 15, 5), makeChunks(config, stream, node, 25, 5), makeChunks(config, stream, node, 35, 5), } for _, chunkSet := range chunkSets { chunks = append(chunks, chunkSet[0]) for j := 1; j < len(chunkSet); j++ { fromHost <- chunkSet[j] } } // Finish the packets in this order: 2,3,0,1,5,4. We should receive, in order, 2,3,5,4 for _, index := range []int{2, 3, 0, 1, 5, 4} { fromHost <- chunks[index] } }() So(verifyPacket((<-toCore).Data, stream, node, 10, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 15, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 35, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 25, 5), ShouldBeTrue) }) Convey("Unreliable and Ordered streams might drop packets, but all packets that are received are in order.", func() { go func() { // This is just to make sure the routine doesn't block trying to send to the host. for range toHost { } }() var node core.NodeId = 777 stream := config.GetIdFromName("UO") go func() { var chunks []core.Chunk // Send all but the first chunk for each packet chunkSets := [][]core.Chunk{ // The first packet is before the start of the stream, it should not get reported. makeChunks(config, stream, node, 0, 5), makeChunks(config, stream, node, 5, 5), makeChunks(config, stream, node, 10, 5), makeChunks(config, stream, node, 15, 5), makeChunks(config, stream, node, 20, 5), makeChunks(config, stream, node, 25, 5), } for _, chunkSet := range chunkSets { chunks = append(chunks, chunkSet[0]) for j := 1; j < len(chunkSet); j++ { fromHost <- chunkSet[j] } } // Finish the packets in this order: 2,3,0,1,5,4. We should receive, in order, 2,3,5,4 for _, index := range []int{2, 3, 0, 1, 5, 4} { fromHost <- chunks[index] } }() So(verifyPacket((<-toCore).Data, stream, node, 10, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 15, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 25, 5), ShouldBeTrue) }) Convey("Reliable and Unordered streams produce all packets, but can produce them out of order.", func() { go func() { // This is just to make sure the routine doesn't block trying to send to the host. for range toHost { } }() var node core.NodeId = 777 stream := config.GetIdFromName("RU") go func() { var chunks []core.Chunk // The first packet is before the start of the stream, it should not get reported. chunks = append(chunks, makeChunks(config, stream, node, 0, 5)...) chunks = append(chunks, makeChunks(config, stream, node, 5, 5)...) chunks = append(chunks, makeChunks(config, stream, node, 10, 5)...) chunks = append(chunks, makeChunks(config, stream, node, 15, 5)...) chunks = append(chunks, makeChunks(config, stream, node, 20, 5)...) chunks = append(chunks, makeChunks(config, stream, node, 25, 5)...) // Send them in reverse order for i := range chunks { fromHost <- chunks[len(chunks)-1-i] } }() So(verifyPacket((<-toCore).Data, stream, node, 25, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 20, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 15, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 10, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 5, 5), ShouldBeTrue) }) Convey("Reliable and Ordered streams produce all packets in order.", func() { go func() { // This is just to make sure the routine doesn't block trying to send to the host. for range toHost { } }() var node core.NodeId = 777 stream := config.GetIdFromName("RO") go func() { var chunks []core.Chunk chunks = append(chunks, makeChunks(config, stream, node, 5, 5)...) chunks = append(chunks, makeChunks(config, stream, node, 10, 5)...) chunks = append(chunks, makeChunks(config, stream, node, 15, 5)...) chunks = append(chunks, makeChunks(config, stream, node, 20, 5)...) chunks = append(chunks, makeChunks(config, stream, node, 25, 5)...) // Send them in reverse order for i := range chunks { fromHost <- chunks[len(chunks)-1-i] } }() So(verifyPacket((<-toCore).Data, stream, node, 5, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 10, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 15, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 20, 5), ShouldBeTrue) So(verifyPacket((<-toCore).Data, stream, node, 25, 5), ShouldBeTrue) }) Convey("Confirmation packets are sent at regular intervals.", func() { go func() { // This is just to make sure the routine doesn't block trying to send to the core. for range toCore { } }() config.MaxChunkDataSize = 100 var node core.NodeId = 777 stream := config.GetIdFromName("RO") var chunks []core.Chunk chunks = append(chunks, makeChunks(config, stream, node, 5, 95)...) chunks = append(chunks, makeChunks(config, stream, node, 100, 100)...) chunks = append(chunks, makeChunks(config, stream, node, 200, 100)...) c := cmwc.MakeGoodCmwc() c.Seed(123) rng := rand.New(c) // shuffle for i := range chunks { swap := rng.Intn(len(chunks)-i) + i chunks[i], chunks[swap] = chunks[swap], chunks[i] } // decoy is used to sync up our test with the some routines in sluice decoy := core.Chunk{Stream: config.GetIdFromName("UU")} goldenSt := core.MakeSequenceTracker(stream, node, 5) for len(chunks) > 0 { // Send 150 chunks for i := 0; i < 150 && len(chunks) > 0; i++ { select { case fromHost <- chunks[0]: goldenSt.AddSequenceId(chunks[0].Sequence) chunks = chunks[1:] case <-toHost: } } // The first bach of confirmation packets might not be up-to-date, so take those // packets until we're able to send the decoy, then take and store the next set of // confirmation packets. var confirmationChunks []core.Chunk decoyCount := 0 <-toHost for decoyCount < 2 { select { case confirm := <-toHost: if decoyCount > 0 { confirmationChunks = append(confirmationChunks, confirm) } case fromHost <- decoy: confirmationChunks = append(confirmationChunks, <-toHost) decoyCount++ } } // We want it to be greater than 1 because we want to test that independent chunks // can be combined to get all of the information we want. So(len(confirmationChunks), ShouldBeGreaterThan, 1) var sts []*core.SequenceTracker for _, chunk := range confirmationChunks { st, err := core.ParseSequenceTrackerChunkData(chunk.Data) So(err, ShouldBeNil) So(st, ShouldNotBeNil) if st.StreamId() == stream && st.NodeId() == node { sts = append(sts, st) } } So(len(sts), ShouldBeGreaterThanOrEqualTo, 1) coverage := make(map[core.SequenceId]bool) goldCoverage := make(map[core.SequenceId]bool) for _, st := range sts { // Don't need to check MaxContiguous, all we really care about is whether // Contains() is always correct. for sequence := core.SequenceId(0); sequence < 500; sequence++ { if st.Contains(sequence) { coverage[sequence] = true } if goldenSt.Contains(sequence) { goldCoverage[sequence] = true } } } So(coverage, ShouldResemble, goldCoverage) } }) }) }
func GenerateRoom(dx, dy, radius float64, grid int, seed int64) Room { var room Room room.Walls = make(map[string]linear.Poly) nextIdInt = 0 room.Dx = int(dx) room.Dy = int(dy) c := cmwc.MakeGoodCmwc() if seed == 0 { c.SeedWithDevRand() n := c.Int63() c = cmwc.MakeGoodCmwc() base.Log().Printf("SEED: %v", n) c.Seed(n) } else { c.Seed(seed) } sanity := int(math.Sqrt(dx * dy)) r := rand.New(c) var poss []linear.Vec2 for sanity > 0 { pos := linear.Vec2{r.Float64() * (dx - radius + 1), r.Float64() * (dy - radius + 1)} good := true for _, p := range poss { if p.Sub(pos).Mag() < 2*(2*radius) { good = false break } } if !good { sanity-- continue } poss = append(poss, pos) } // Find the pair of points that maximizes distance maxDist := 0.0 for i := range poss { for j := range poss { dist := poss[i].Sub(poss[j]).Mag() if dist > maxDist { maxDist = dist } } } var a, b int minDist := maxDist * 3 / 4 hits := 1.0 for i := range poss { for j := range poss { if i == j { continue } dist := poss[i].Sub(poss[j]).Mag() if dist > minDist && r.Float64() < 1.0/hits { a, b = i, j hits = hits + 1 } } } room.Starts = []linear.Vec2{poss[a], poss[b]} for _, start := range room.Starts { var data mobaRoomSideData data.Base = start room.Moba.SideData = append(room.Moba.SideData, data) } var data mobaRoomSideData for i, pos := range poss { if i == a || i == b { continue } data.Towers = append(data.Towers, pos) } room.Moba.SideData = append(room.Moba.SideData, data) sanity = int(math.Pow(dx*dy, 0.20)) var segs []linear.Seg2 for sanity > 0 { a := linear.Vec2{r.Float64() * (dx), r.Float64() * (dy)} length := gridify(r.Float64()*radius+(radius), grid) angle := float64(r.Intn(4)) * 3.1415926535 / 2 ray := (linear.Vec2{1, 0}).Rotate(angle) seg := linear.Seg2{a, a.Add(ray.Scale(length))} seg.P.X = gridify(seg.P.X, grid) seg.P.Y = gridify(seg.P.Y, grid) seg.Q.X = gridify(seg.Q.X, grid) seg.Q.Y = gridify(seg.Q.Y, grid) good := true if seg.P.X <= 0 || seg.P.X >= dx || seg.P.Y <= 0 || seg.P.Y >= dy { good = false } if seg.Q.X <= 0 || seg.Q.X >= dx || seg.Q.Y <= 0 || seg.Q.Y >= dy { good = false } if seg.P.X == seg.Q.X && seg.P.Y == seg.Q.Y { good = false } // Can't get too close to a circle for _, p := range poss { if distFromPointToSeg(p, seg) < radius/2 { good = false break } } // Check to make sure this segment isn't coincident with any othe segment. // To avoid annoying degeneracies we'll rotate the segment slightly. rot := linear.Seg2{seg.P, seg.Ray().Rotate(0.01).Add(seg.P)} for _, cur := range segs { if rot.DoesIsect(cur) { good = false break } } if !good { sanity-- continue } segs = append(segs, seg) } for _, s := range segs { right := s.Ray().Cross().Norm().Scale(-float64(grid)) s2 := linear.Seg2{s.Q.Add(right), s.P.Add(right)} room.Walls[nextId()] = linear.Poly{s.P, s.Q, s2.P, s2.Q} } room.Walls[nextId()] = linear.Poly{ linear.Vec2{0, 0}, linear.Vec2{dx, 0}, linear.Vec2{dx, dy}, linear.Vec2{0, dy}, } room.NextId = nextIdInt return room }
func RunGames(players []Player, seed int64, game string, num_games int, all_perms bool) (err error) { defer func() { if r := recover(); r != nil { err = runGamesErrors{fmt.Sprintf("%v", r)} } }() rng := cmwc.MakeGoodCmwc() if seed != 0 { rng.Seed(int64(seed)) } else { rng.SeedWithDevRand() } valid_game := false for _, valid_name := range AllBarbuGameNames() { if game == valid_name { valid_game = true } } if !valid_game { fmt.Printf("'%s' is not a valid game. Valid games are %v.\n", game, AllBarbuGameNames()) } var total [4]int N := num_games if !all_perms { perms = [][]int{{0, 1, 2, 3}} } total_games := N * len(perms) completed := 0 for i := 0; i < N; i++ { // Map from N to the scores for the Nth permutation perm_score_map := make(map[int][]int) deck := makeDeck(rng) for perm_num, perm := range perms { equivalent := false equivalent_perm_num := -1 for pi := 0; pi < perm_num; pi++ { if equivalentPermutation(players, pi, perm_num) { equivalent = true equivalent_perm_num = pi break } } scores := make([]int, 4) permed_players := make([]Player, 4) if equivalent { scores = perm_score_map[equivalent_perm_num] } else { for i := range permed_players { permed_players[i] = players[perm[i]] } // Tell the permed_players what position they are around the table, and what // their hand is. hands := deck.Copy().Deal() for i := range permed_players { permed_players[i].Stdin().Write([]byte(fmt.Sprintf("PLAYER %d\n", i))) for j := range hands[i] { var line string // Prevent having a trailing space if j == 0 { line = hands[i][j] } else { line = " " + hands[i][j] } permed_players[i].Stdin().Write([]byte(line)) } permed_players[i].Stdin().Write([]byte("\n")) } // TODO: This is where the dealer should choose the game. for i := range permed_players { permed_players[i].Stdin().Write([]byte(strings.ToUpper(game) + "\n")) } the_game := GetBarbuGame(game, permed_players, hands) doubles := the_game.Double() the_game.Run() raw_scores := the_game.Scores() for i := range scores { for j := range scores { if i >= j { continue } if doubles[i][j] == 0 || raw_scores[i]-raw_scores[j] == 0 { continue } diff := raw_scores[i] - raw_scores[j] if diff < 0 { diff = -diff } diff *= doubles[i][j] if raw_scores[i] > raw_scores[j] { scores[i] += diff scores[j] -= diff } else { scores[j] += diff scores[i] -= diff } } } for i := range scores { scores[i] += raw_scores[i] } } perm_score_map[perm_num] = scores for i := range scores { if !equivalent { line := fmt.Sprintf("END %d %d %d %d\n", scores[0], scores[1], scores[2], scores[3]) permed_players[i].Stdin().Write([]byte(line)) } total[perm[i]] += scores[i] } completed++ fmt.Printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b") fmt.Printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b") fmt.Printf("Finished %d/%d games.", completed, total_games) } } fmt.Printf("\nAverages:\n") for i := range total { fmt.Printf("Player %d: %.2f\n", i, float64(total[i])/float64(N*len(perms))) } return }
func (u SetupComplete) Apply(_g interface{}) { g := _g.(*Game) if g.Setup == nil { return } sideCount := make(map[int]int) // Must have at least two sides sideCount[0] = 0 sideCount[1] = 0 for _, spd := range g.Setup.Players { sideCount[spd.Side]++ } g.Engines = make(map[int64]*PlayerData) for id, player := range g.Setup.Players { var gid Gid if id < 0 { gid = Gid(fmt.Sprintf("Ai:%d", -id)) } else { gid = Gid(fmt.Sprintf("Engine:%d", id)) } g.Engines[id] = &PlayerData{ PlayerGid: Gid(gid), Side: player.Side, ChampIndex: player.ChampIndex, } } // Now that we have the information we can set up a lot of the local data for // this engine's player. if g.IsPlaying() { g.local.Side = g.Engines[g.local.Engine.Id()].Side g.local.Gid = g.Engines[g.local.Engine.Id()].PlayerGid g.local.Data = g.Engines[g.local.Engine.Id()] } var room Room err := base.LoadJson(filepath.Join(base.GetDataDir(), "rooms/basic.json"), &room) if err != nil { base.Error().Fatalf("%v", err) } errs := room.Validate() for _, err := range errs { base.Error().Printf("%v", err) } if len(errs) > 0 { base.Error().Fatalf("Errors with the level, bailing...") } g.Level = &Level{} g.Level.Room = room g.Rng = cmwc.MakeGoodCmwc() g.Rng.Seed(u.Seed) g.Ents = make(map[Gid]Ent) g.Friction = 0.97 g.losCache = makeLosCache(g.Level.Room.Dx, g.Level.Room.Dy) sides := make(map[int][]int64) var playerDatas []*PlayerData base.DoOrdered(g.Engines, func(a, b int64) bool { return a < b }, func(id int64, data *PlayerData) { sides[data.Side] = append(sides[data.Side], id) playerDatas = append(playerDatas, data) }) for id, ed := range g.Engines { base.Log().Printf("%v -> %v", id, *ed) } g.AddPlayers(playerDatas) g.MakeControlPoints() g.Init() base.Log().Printf("Nillifying g.Setup()") g.Setup = nil }
func (u SetupComplete) Apply(_g interface{}) { g := _g.(*Game) if g.Setup == nil { return } g.Engines = make(map[int64]*PlayerData) for _, id := range g.Setup.EngineIds { g.Engines[id] = &PlayerData{ PlayerGid: Gid(fmt.Sprintf("Engine:%d", id)), Side: g.Setup.Sides[id].Side, } } // Add a single Ai player to side 0 g.Engines[123123] = &PlayerData{ PlayerGid: Gid(fmt.Sprintf("Engine:%d", 123123)), Side: 0, Ai: &AiPlayerData{}, } g.Setup.Sides[123123] = &SetupSideData{ Champ: 0, Side: 0, } var room Room dx, dy := 1024, 1024 generated := generator.GenerateRoom(float64(dx), float64(dy), 100, 64, u.Seed) data, err := json.Marshal(generated) if err != nil { base.Error().Fatalf("%v", err) } err = json.Unmarshal(data, &room) // err = base.LoadJson(filepath.Join(base.GetDataDir(), "rooms/basic.json"), &room) if err != nil { base.Error().Fatalf("%v", err) } g.Levels = make(map[Gid]*Level) g.Levels[GidInvadersStart] = &Level{} g.Levels[GidInvadersStart].Room = room g.Rng = cmwc.MakeGoodCmwc() g.Rng.Seed(12313131) g.Ents = make(map[Gid]Ent) g.Friction = 0.97 // g.Standard = &GameModeStandard{} g.Moba = &GameModeMoba{ Sides: make(map[int]*GameModeMobaSideData), } sides := make(map[int][]int64) for id, data := range g.Engines { sides[data.Side] = append(sides[data.Side], id) } for _, players := range sides { var ids []int64 for _, id := range players { ids = append(ids, id) } side := g.Setup.Sides[ids[0]].Side gids := g.AddPlayers(ids, side) g.Moba.Sides[side] = &GameModeMobaSideData{} for i := range ids { player := g.Ents[gids[i]].(*PlayerEnt) player.Champ = g.Setup.Sides[ids[i]].Champ } } g.Moba.losCache = makeLosCache(dx, dy) g.MakeControlPoints() g.Init() base.Log().Printf("Nillifying g.Setup()") g.Setup = nil }
func (ms *ManaSource) Init(options *ManaSourceOptions, walls []linear.Poly, lava []linear.Poly) { ms.options = *options if options.NumNodeCols < 2 || options.NumNodeRows < 2 { panic(fmt.Sprintf("Invalid options: %v", options)) } c := cmwc.MakeGoodCmwc() c.SeedWithDevRand() r := rand.New(c) seeds := make([]nodeSeed, options.NumSeeds) for i := range seeds { seed := &seeds[i] seed.x = options.BoardLeft + r.Float64()*(options.BoardRight-options.BoardLeft) seed.y = options.BoardTop + r.Float64()*(options.BoardBottom-options.BoardTop) seed.color = r.Intn(3) } var allObstacles []linear.Poly for _, p := range walls { allObstacles = append(allObstacles, p) } for _, p := range lava { allObstacles = append(allObstacles, p) } ms.nodes = make([][]node, options.NumNodeCols) for col := 0; col < options.NumNodeCols; col++ { ms.nodes[col] = make([]node, options.NumNodeRows) for row := 0; row < options.NumNodeRows; row++ { x := options.BoardLeft + float64(col)/float64(options.NumNodeCols-1)*(options.BoardRight-options.BoardLeft) y := options.BoardTop + float64(row)/float64(options.NumNodeRows-1)*(options.BoardBottom-options.BoardTop) // all_obstacles[0] corresponds to the outer walls. We do not want to drop mana nodes for // being inside there. insideObstacle := false for i := 1; !insideObstacle && i < len(allObstacles); i++ { if vecInsideConvexPoly(linear.Vec2{x, y}, allObstacles[i]) { insideObstacle = true } } if insideObstacle { continue } maxWeightByColor := [3]float64{0.0, 0.0, 0.0} for _, seed := range seeds { c := seed.color dx := x - seed.x dy := y - seed.y distSquared := dx*dx + dy*dy weight := 1 / (distSquared + 1.0) if weight > maxWeightByColor[c] { maxWeightByColor[c] = weight } } normalizeWeights(options.NodeMagnitude, maxWeightByColor[:]) var weightsCopy [3]float64 copy(weightsCopy[:], maxWeightByColor[:]) ms.nodes[col][row] = node{ X: x, Y: y, RegenPerFrame: options.RegenPerFrame, Mana: maxWeightByColor, MaxMana: weightsCopy, } } } }