コード例 #1
0
ファイル: ai.go プロジェクト: robban/stockholm-ai
/*
HTTPHandlerFunc returns an http.HandlerFunc to use when hosting an AI.
*/
func HTTPHandlerFunc(lf common.LoggerFactory, ai AI) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logger := lf(r)
		defer func() {
			if e := recover(); e != nil {
				w.WriteHeader(500)
				logger.Printf("Error delivering orders: %v", e)
			}
		}()
		var req OrderRequest
		common.MustDecodeJSON(r.Body, &req)
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		common.MustEncodeJSON(w, ai.Orders(lf(r), req.Me, req.State))
	}
}
コード例 #2
0
ファイル: game.go プロジェクト: robban/stockholm-ai
func nextTurn(cont appengine.Context, id *datastore.Key, playerNames []string) {
	con := common.Context{Context: cont}
	self := getGameById(con, id)
	self.PlayerNames = playerNames
	if self.Length > maxGameDuration {
		self.State = StateFinished
		self.Save(con)
		con.Infof("Ended %v due to timeout", self.Id)
		return
	}
	errorSavers := []func(){}
	if err := common.Transaction(con, func(c common.Context) (err error) {
		lastTurn := GetLatestTurnByParent(c, self.Id)
		responses := make(chan orderResponse, len(self.Players))
		for _, playerId := range self.Players {
			orderResp := orderResponse{
				DatastorePlayerId: playerId,
				StatePlayerId:     state.PlayerId(playerId.Encode()),
			}
			if foundAi := GetAIById(c, playerId); foundAi != nil {
				go func() {
					// Always deliver the order response
					defer func() {
						responses <- orderResp
					}()

					// create a request
					orderRequest := ai.OrderRequest{
						Me:     orderResp.StatePlayerId,
						State:  lastTurn.State,
						GameId: state.GameId(self.Id.Encode()),
					}

					// encode it into a body, and remember its string representation
					sendBody := &bytes.Buffer{}
					aiCommon.MustEncodeJSON(sendBody, orderRequest)
					sendBodyString := sendBody.String()

					// get a client
					client := urlfetch.Client(c)

					// send the request to the ai
					req, err := http.NewRequest("POST", foundAi.URL, sendBody)
					var resp *http.Response
					if err == nil {
						req.Header.Set("Content-Type", "application/json; charset=UTF-8")
						resp, err = client.Do(req)
					}

					recvBody := &bytes.Buffer{}
					recvBodyString := ""
					if err == nil {
						// check what we received
						_, err = io.Copy(recvBody, resp.Body)
						recvBodyString = recvBody.String()
					}
					// if we have no other errors, but we got a non-200
					if err == nil && resp.StatusCode != 200 {
						err = orderError{
							Request:      req,
							RequestBody:  sendBodyString,
							Response:     resp,
							ResponseBody: recvBodyString,
						}
					}

					// lets try to unserialize
					if err == nil {
						err = json.Unmarshal(recvBody.Bytes(), &orderResp.Orders)
					}

					// store the error, if any
					if err != nil {
						orderResp.Error = err
					}
				}()
			} else {
				responses <- orderResp
			}
		}
		orderMap := map[state.PlayerId]state.Orders{}
		for _, _ = range self.Players {
			// wait for the responses
			orderResp := <-responses
			// store it
			orderMap[orderResp.StatePlayerId] = orderResp.Orders
			// if we got an error
			if orderResp.Error != nil {
				// make sure to save it later
				errorSavers = append(errorSavers, func() {
					if ai := GetAIById(con, orderResp.DatastorePlayerId); ai != nil {
						ai.AddError(con, lastTurn.Id, orderResp.Error)
					}
				})
			}
		}
		// execute the orders
		newTurn, winner := lastTurn.Next(c, orderMap)
		// save the new turn
		newTurn.Save(c, self.Id)
		// if we got a winner, end the game and store the winner
		if winner == nil {
			self.State = StatePlaying
		} else {
			self.Winner = common.MustDecodeKey(string(*winner))
			self.State = StateFinished
		}
		// increase our length with the new turn
		self.Length += 1
		// save us
		self.Save(c)
		// if we didn't end, queue the next turn
		if winner == nil {
			nextTurnFunc.Call(c, self.Id, playerNames)
		}
		return nil
	}); err != nil {
		panic(err)
	}
	// run any error savers we got
	for _, saver := range errorSavers {
		saver()
	}
	// store the new stats in the players if we ended
	if self.State == StateFinished {
		for _, playerId := range self.Players {
			common.Transaction(con, func(c common.Context) error {
				if ai := GetAIById(c, playerId); ai != nil {
					if playerId.Equal(self.Winner) {
						ai.Wins += 1
					} else {
						ai.Losses += 1
					}
					ai.Save(c)
				}
				return nil
			})
		}
	}
}
コード例 #3
0
ファイル: common.go プロジェクト: robban/stockholm-ai
func (self Context) RenderJSON(i interface{}) {
	self.SetContentType("application/json; charset=UTF-8", false)
	common.MustEncodeJSON(self.Resp, i)
}