Esempio n. 1
0
func fightN(f1, f2 Factory, n int) []MatchResult {
	aiA := &aiAdapter{factory: f1, games: make(map[string]gameState)}
	aiB := &aiAdapter{factory: f2, games: make(map[string]gameState)}

	a1, a2 := net.Pipe()
	b1, b2 := net.Pipe()

	ca1, ca2 := rpc.StreamTransport(a1), rpc.StreamTransport(a2)
	cb1, cb2 := rpc.StreamTransport(b1), rpc.StreamTransport(b2)

	// Server-side
	srvA := botapi.Ai_ServerToClient(aiA)
	srvB := botapi.Ai_ServerToClient(aiB)
	serverConnA := rpc.NewConn(ca1, rpc.MainInterface(srvA.Client))
	serverConnB := rpc.NewConn(cb1, rpc.MainInterface(srvB.Client))
	defer serverConnA.Wait()
	defer serverConnB.Wait()

	// Client-side
	ctx := context.Background()

	clientConnA := rpc.NewConn(ca2)
	clientConnB := rpc.NewConn(cb2)
	defer clientConnA.Close()
	defer clientConnB.Close()

	clientA := localAI{botapi.Ai{Client: clientConnA.Bootstrap(ctx)}}
	clientB := localAI{botapi.Ai{Client: clientConnB.Bootstrap(ctx)}}

	matchRes := make([]MatchResult, n)
	// Run the game
	for i := 0; i < n; i++ {
		b := engine.EmptyBoard(engine.DefaultConfig)
		b.InitBoard(engine.DefaultConfig)

		for !b.IsFinished() {
			turnCtx, _ := context.WithTimeout(ctx, 30*time.Second)
			resA, _ := clientA.takeTurn(turnCtx, strconv.Itoa(i), b, engine.P1Faction)
			resB, _ := clientB.takeTurn(turnCtx, strconv.Itoa(i), b, engine.P2Faction)
			b.Update(resA, resB)
		}
		matchRes[i] = MatchResult{
			P1Score: b.BotCount(1),
			P2Score: b.BotCount(2),
		}
	}
	return matchRes
}
Esempio n. 2
0
func runMatch(gidCh chan<- gameID, ctx gocontext.Context, ds datastore, aiA, aiB *onlineAI, bc engine.BoardConfig) error {
	sTime := time.Now()
	// Create new board and store it.
	b := engine.EmptyBoard(bc)
	b.InitBoard(bc)
	_, seg, _ := capnp.NewMessage(capnp.SingleSegment(nil))
	wb, _ := botapi.NewRootInitialBoard(seg)
	b.ToWireWithInitial(wb, engine.P1Faction)
	gid, err := ds.startGame(aiA.Info.ID, aiB.Info.ID, wb)
	if err != nil {
		return err
	}
	gidCh <- gid

	// Run the game
	for !b.IsFinished() {
		turnCtx, _ := gocontext.WithTimeout(ctx, 30*time.Second)
		chA, chB := make(chan turnResult), make(chan turnResult)
		go aiA.takeTurn(turnCtx, gid, b, engine.P1Faction, chA)
		go aiB.takeTurn(turnCtx, gid, b, engine.P2Faction, chB)
		ra, rb := <-chA, <-chB
		if ra.err.HasError() {
			log.Printf("Errors from AI ID %s: %v", aiA.Info.ID, ra.err)
		}
		if rb.err.HasError() {
			log.Printf("Errors from AI ID %s: %v", aiB.Info.ID, rb.err)
		}
		b.Update(ra.results, rb.results)
		_, s, err := capnp.NewMessage(capnp.SingleSegment(nil))
		if err != nil {
			return err
		}
		r, err := botapi.NewRootReplay_Round(s)
		if err != nil {
			return err
		}

		wireBoard, err := r.NewEndBoard()
		if err != nil {
			return err
		}
		b.ToWire(wireBoard, engine.P1Faction)

		ral, rbl := ra.results.Len(), rb.results.Len()
		turns, err := botapi.NewTurn_List(r.Segment(), int32(ral+rbl))
		if err != nil {
			return err
		}
		for i := 0; i < ral; i++ {
			t := ra.results.At(i)
			if err := turns.Set(i, t); err != nil {
				return err
			}
		}
		for i := 0; i < rbl; i++ {
			t := rb.results.At(i)
			if err := turns.Set(i+ral, t); err != nil {
				return err
			}
		}
		r.SetMoves(turns)
		db.addRound(gid, r)
	}

	gInfo := &gameInfo{
		ID:        gid,
		AI1:       &aiA.Info,
		AI2:       &aiB.Info,
		AI1Score:  b.BotCount(1),
		AI2Score:  b.BotCount(2),
		StartTime: sTime,
		EndTime:   time.Now(),
	}
	return db.finishGame(gid, &aiA.Info, &aiB.Info, gInfo)
}