示例#1
0
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])
	}
}
示例#2
0
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
}
示例#3
0
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)
		}
	})
}
示例#4
0
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++
}
示例#5
0
文件: main.go 项目: dgthunder/magnus
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)
			}
		})

	})
}
示例#7
0
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
}
示例#8
0
文件: main.go 项目: runningwild/barbu
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
}
示例#9
0
文件: game.go 项目: runningwild/jota
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
}
示例#10
0
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
}
示例#11
0
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,
			}
		}
	}
}