bool Board::move(Move move) { auto x = move.x; auto y = move.y; auto player = move.player; if (x < 0 || y < 0 || x > BOARD_WIDTH || y > BOARD_HEIGHT || (*this->getBoardState())[x][y] != Player::NoPlayer) { return false; } std::vector<std::pair<short, short>> searchDirections; for(auto itr = DIRECTIONS.begin(); itr != DIRECTIONS.end(); ++itr) { auto direction = *itr; short searchX = x + std::get<0>(direction); short searchY = y + std::get<1>(direction); if (searchX >=0 && searchX <= BOARD_WIDTH - 1 && searchY >=0 && searchY <= BOARD_HEIGHT - 1 && (*this->getBoardState())[searchX][searchY] == -player) { searchDirections.push_back(*itr); } } if(searchDirections.size() == 0) { return false; } std::shared_ptr<Matrix<short>> boardState = this->_boardStateStack.top()->clone(); std::vector<std::pair<unsigned short, unsigned short>> path; PlayerScoreInfo playerScore(this->getPlayerScoreInfo()); bool moveValid = false; for (auto itr = std::begin(searchDirections); itr != std::end(searchDirections); ++itr) { auto direction = *itr; short searchX = x + std::get<0>(direction); short searchY = y + std::get<1>(direction); while (searchX >=0 && searchX <= BOARD_WIDTH - 1 && searchY >=0 && searchY <= BOARD_HEIGHT - 1){ if ((*boardState)[searchX][searchY] == player) { playerScore[player] += path.size(); playerScore[PlayerUtil::swapPlayer(player)] -= path.size(); for (auto pathItr = std::begin(path); pathItr != std::end(path); ++pathItr) { (*boardState)[std::get<0>(*pathItr)][std::get<1>(*pathItr)] = player; } moveValid = true; break; } else { path.push_back({searchX, searchY}); } if ((*boardState)[searchX][searchY] == Player::NoPlayer) { break; } searchX += std::get<0>(direction); searchY += std::get<1>(direction); } path.clear(); } if (moveValid) { (*boardState)[x][y] = player; playerScore[player] ++; this->_boardStateStack.push(boardState); this->_playerScoreInfoStack.push(playerScore); this->_moveStack.push(move); this->_cachedAvailPosMap.clear(); } return moveValid; }
void runGame(PlayerSet& players, ControlData& control, const GameState& gameState, const Map& map, const SimulationParameters& params, GameStats& gameStats, zmq::socket_t& stateSocket, const json& settings, InfoLogger& logger) { uint targetFPS = settings["simulation"]["targetFPS"]; uint totalGameTimeSeconds = settings["gameTime"]; uint integrationSteps = uint(1. / float(targetFPS) / params.timeStep); // Make sure the per-game stats are cleared gameStats.playerRanks.clear(); gameStats.playerDists.clear(); uint nShips = players.fromId.size(); uint targetMicroseconds = 1000000 / targetFPS; StateMatrix state(nShips, STATE_LENGTH); initialiseState(state, map, params); ControlMatrix inputs = control.inputs; bool running = true; unsigned int fpscounter = 0; auto gameStart = hrclock::now(); logger("game", "status", {{"state","running"},{"map",map.name}, {"game",gameState.name}}); while (running && !interruptedBySignal) { auto frameStart = hrclock::now(); // Threadsafe copy of control inputs (unlock managed by scope) { std::lock_guard<std::mutex> lock(control.mutex); inputs = control.inputs; } for (uint i=0; i<integrationSteps;i++) rk4TimeStep(state, inputs, params, map); // Calculate game stats every second fpscounter++; if (fpscounter >= targetFPS) { fpscounter = 0; playerScore(state, control, map, params, gameStats); logger("game", "status", {{"state","running"},{"map",map.name}, {"game",gameState.name}, {"ranking", gameStats.playerRanks}}); } //check we don't need to end the game bool timeout = hasRoughIntervalPassed(gameStart, totalGameTimeSeconds, targetFPS); bool raceWon = winner(players, state,control, map, params) != ""; running = (!timeout) && (!raceWon); // get control inputs from control thread broadcastState(players, state, gameState, control, params, stateSocket); // make sure we target a particular frame rate waitPreciseInterval(frameStart, targetMicroseconds); } // Game over, so tell the clients playerScore(state, control, map, params, gameStats); // get final score updateRanks(players, control,map, gameStats); logger("game", "status", {{"state","finished"},{"map",map.name}, {"game",gameState.name}, {"ranking", gameStats.playerRanks}, {"totalScore", gameStats.totalPlayerScore}, {"teamScore", gameStats.totalTeamScore}}); send(stateSocket, {gameState.name,"{\"state\":\"finished\"}"}); }