void add (uint32_t id, char side, uint32_t price, uint32_t size) { if (orders.end () != orders.find (id, OrderIdHasher (), OrderIdEqual ())) { throw std::runtime_error ("duplicate add"); } AggregateOrders::iterator found = aggregateOrders.find (std::make_pair (side, price), AggregateOrderLess ()); if (found == aggregateOrders.end ()) { AggregateOrder *a = aggregateOrderPool.construct (boost::in_place (side, price)); found = aggregateOrders.insert (*a).first; } assert(aggregateOrders.end () != found); Order *order = orderPool.construct (boost::in_place (id, boost::ref (*found))); assert(order); bool orderInserted __attribute__((unused)) = orders.insert (*order).second; assert(orderInserted); order->size = size; order->aggregateOrder.size += size; assert(order->size); assert(order->aggregateOrder.size); }
void visitOrders (V const& v) const { for (auto i = orders.begin (), e = orders.end (); i != e; ++i) { if (!v (*i)) return; } }
void clear() { while(!orders.empty()) { auto const& order = *orders.begin(); reduce(order.id, order.size); } assert(orders.empty()); assert(aggregateOrders.empty()); }
Orders OrderBook::cross() { sort(orders_); size_t indicativeQuantity = 0; size_t currentBidQuantity = totalBid_; size_t currentAskQuantity = 0; double indicativePrice = 1e9; for (const auto& o : orders_) { if (o.isBid_) { currentBidQuantity -= o.quantity_; } else { currentAskQuantity += o.quantity_; } auto quantity = min(currentBidQuantity, currentAskQuantity); if (quantity > indicativeQuantity) { indicativePrice = o.price_; indicativeQuantity = o.quantity_; } } Orders result; for (auto toOrder = orders_.begin(); toOrder != orders_.end();) { bool include = false; if (toOrder->isBid_) { if (toOrder->price_ >= indicativePrice) { include = true; } } else { if (toOrder->price_ <= indicativePrice) { include = true; } } if (include) { if (toOrder->quantity_ <= indicativeQuantity) { indicativeQuantity -= toOrder->quantity_; result.emplace_back(*toOrder); orders_.erase(toOrder); } else { indicativeQuantity = 0; toOrder->quantity_ -= indicativeQuantity; ++toOrder; } } else { ++toOrder; } if (0 == indicativeQuantity) { break; } } return result; }
void reduce (uint32_t id, uint32_t size) { Orders::iterator found = orders.find (id, OrderIdHasher (), OrderIdEqual ()); if (found == orders.end ()) { throw std::runtime_error ("order not found"); } assert(&*found); assert(&found->aggregateOrder); Order &o = *found; AggregateOrder &a = found->aggregateOrder; if (size > o.size) { throw std::runtime_error ("attempt to over reduce"); } if (size == o.size) { a.size -= o.size; orders.erase (found); orderPool.destroy (&o); if (0 == a.size) { aggregateOrders.erase (AggregateOrders::s_iterator_to (a)); aggregateOrderPool.destroy (&a); } } else { o.size -= size; a.size -= size; assert(o.size); assert(a.size); } }
//---------------------------------------------------------------------- void AIController::processAgentPathOrders( ArenaMap& currentMap, Orders& tentativeOrders ) { EnterCriticalSection( &m_agentsCS ); for( auto agentIter = m_agents.begin(); agentIter != m_agents.end(); ++agentIter ) { Agent* currAgent = agentIter->second; if( !currAgent->currentPath.empty() ) { if( currAgent->entityType == ENTITY_TYPE_WORKER && currAgent->specialStatus != ENTITY_SPECIAL_STATUS_CARRYING_FOOD ) { currentMap.getMapTile( currAgent->currentTargetLoc.x, currAgent->currentTargetLoc.y ).isClaimed = true; } tentativeOrders.AddOrder( currAgent->entityID, currAgent->currentPath.back(), true ); } } LeaveCriticalSection( &m_agentsCS ); }
//---------------------------------------------------------------------- void AIController::handleQueenOrders( Agent* queen, ArenaMap& currentMap, const ObservedEntities& entities, Orders& tentativeOrders ) { if( ( m_turnNumber > 0 && m_turnNumber % TURN_INTERVAL_QUEEN_MOVES_ON == 0 ) || m_numWorkersThatCouldntFindFoodThisFrame >= NUM_WORKERS_IDLE_BEFORE_QUEEN_MOVES || m_currentNumWorkers <= 0 ) { if( m_currentNumWorkers <= 0 && m_currentUpkeep*TURN_UPKEEP_TOLERANCE + m_arenaInfo.nutrientCostToBirthWorker ) tentativeOrders.AddOrder( queen->entityID, ORDER_CREATE_WORKER ); else if( queen->currentPath.empty() && !queen->waitingForPath ) { queen->currentTargetLoc = getLocationForQueenToGoTo( currentMap ); m_agentsRequestingPaths.push( queen->entityID ); queen->waitingForPath = true; } } else { switch( m_currentQueenState ) { case GATHER_RESOURCES: if( m_currentNutrients > m_currentUpkeep*TURN_UPKEEP_TOLERANCE + m_arenaInfo.nutrientCostToBirthWorker )//&& !m_spawnedWorkerLastFrame ) { tentativeOrders.AddOrder( queen->entityID, ORDER_CREATE_WORKER ); m_spawnedWorkerLastFrame = true; } else if( m_currentNutrients > m_currentUpkeep*TURN_UPKEEP_TOLERANCE + m_arenaInfo.nutrientCostToBirthScout ) { if( m_currentNumScouts < MAX_NUM_SCOUTS ) tentativeOrders.AddOrder( queen->entityID, ORDER_CREATE_SCOUT ); m_spawnedWorkerLastFrame = false; } break; case DEFEND: if( m_currentNutrients > m_currentUpkeep*TURN_UPKEEP_TOLERANCE + m_arenaInfo.nutrientCostToBirthSoldier && m_currentNumWorkers >= MIN_NUM_WORKERS ) { tentativeOrders.AddOrder( queen->entityID, ORDER_CREATE_SOLDIER, true ); m_spawnedWorkerLastFrame = false; } else if( m_currentNumScouts < MAX_NUM_SCOUTS ) tentativeOrders.AddOrder( queen->entityID, ORDER_CREATE_SCOUT ); else if( m_currentNutrients > m_currentUpkeep*TURN_UPKEEP_TOLERANCE + m_arenaInfo.nutrientCostToBirthWorker && !m_spawnedWorkerLastFrame && !currentMap.hasNoMoreResources() ) { tentativeOrders.AddOrder( queen->entityID, ORDER_CREATE_WORKER ); m_spawnedWorkerLastFrame = true; } m_spawnedWorkerLastFrame = false; break; case ATTACK: if( m_currentNutrients > m_currentUpkeep*TURN_UPKEEP_TOLERANCE + m_arenaInfo.nutrientCostToBirthSoldier && ( currentMap.hasNoMoreResources() || m_currentNumWorkers >= MIN_NUM_WORKERS ) ) { tentativeOrders.AddOrder( queen->entityID, ORDER_CREATE_SOLDIER ); m_spawnedWorkerLastFrame = false; } else if( m_currentNutrients > m_currentUpkeep*TURN_UPKEEP_TOLERANCE + m_arenaInfo.nutrientCostToBirthWorker && !m_spawnedWorkerLastFrame && !currentMap.hasNoMoreResources() ) { tentativeOrders.AddOrder( queen->entityID, ORDER_CREATE_WORKER ); m_spawnedWorkerLastFrame = true; } else m_spawnedWorkerLastFrame = false; break; } } }
//---------------------------------------------------------------------- void AIController::handleWorkerOrders( Agent* worker, ArenaMap& currentMap, const ObservedEntities& entities, Orders& tentativeOrders ) { if( m_currentQueenState == ATTACK && currentMap.hasNoMoreResources() && worker->specialStatus != ENTITY_SPECIAL_STATUS_CARRYING_FOOD ) { tentativeOrders.AddOrder( worker->entityID, ORDER_SUICIDE ); } else { if( worker->currentPath.empty() && !worker->waitingForPath ) { if( worker->pos == m_queen->pos && worker->specialStatus == ENTITY_SPECIAL_STATUS_CARRYING_FOOD ) { tentativeOrders.AddOrder( worker->entityID, ORDER_DROP_FOOD, true ); --m_numWorkersWithFood; worker->currentTargetAgentID = -1; } else if( worker->pos == worker->currentTargetLoc && currentMap.getMapTileType( worker->pos.x, worker->pos.y ) == ARENA_SQUARE_TYPE_FOOD ) { tentativeOrders.AddOrder( worker->entityID, ORDER_TAKE_FOOD, true ); m_agentsRequestingPaths.push( worker->entityID ); worker->currentTargetLoc = m_queen->pos; worker->currentTargetAgentID = m_queen->entityID; worker->waitingForPath = true; currentMap.getMapTile( worker->pos.x, worker->pos.y ).isClaimed = false; } else if( worker->specialStatus != ENTITY_SPECIAL_STATUS_CARRYING_FOOD ) { int x, y; if( currentMap.getClosestNutrient( m_arenaInfo.visibilityRangeQueen*QUEEN_RANGE_FACTOR, m_queen->pos, x, y ) ) { m_agentsRequestingPaths.push( worker->entityID ); worker->currentTargetLoc = TileCoords( x, y ); worker->currentTargetAgentID = -1; worker->waitingForPath = true; currentMap.getMapTile( x, y ).isClaimed = true; } else { ++m_numWorkersThatCouldntFindFoodThisFrame; if( m_numWorkersThatCouldntFindFoodThisFrame >= NUM_WORKERS_IDLE_BEFORE_QUEEN_MOVES ) { worker->currentTargetAgentID = m_queen->entityID; } else { worker->currentTargetAgentID = -1; worker->currentTargetLoc = currentMap.getRandomLocationInArea( worker->pos, m_arenaInfo.visibilityRangeQueen*QUEEN_RANGE_FACTOR ); } m_agentsRequestingPaths.push( worker->entityID ); worker->waitingForPath = true; } } else { worker->currentTargetAgentID = m_queen->entityID; m_agentsRequestingPaths.push( worker->entityID ); worker->waitingForPath = true; } } else if( currentMap.getMapTileType( worker->currentTargetLoc.x, worker->currentTargetLoc.y ) != ARENA_SQUARE_TYPE_FOOD && worker->specialStatus != ENTITY_SPECIAL_STATUS_CARRYING_FOOD ) { int x, y; if( currentMap.getClosestNutrient( m_arenaInfo.visibilityRangeQueen*QUEEN_RANGE_FACTOR, m_queen->pos, x, y ) ) { m_agentsRequestingPaths.push( worker->entityID ); worker->currentTargetLoc = TileCoords( x, y ); worker->currentTargetAgentID = -1; worker->waitingForPath = true; currentMap.getMapTile( x, y ).isClaimed = true; } } else if( currentMap.hasNewMapInfo() && !worker->waitingForPath && !validPath( currentMap, worker->pos, worker->currentPath ) ) { m_agentsRequestingPaths.push( worker->entityID ); worker->waitingForPath = true; } } }
//---------------------------------------------------------------------- void AIController::handleAgentReports( ArenaMap& currentMap, const AgentReports& agentReports, const ObservedEntities& entities, Orders& tentativeOrders ) { EnterCriticalSection( &m_agentsCS ); for( int i = 0; i < agentReports.m_numberAgentReports; ++i ) { Agent*& currentAgent = m_agents[ agentReports.m_agentReports[i].m_entityID ]; //Indicates this is a new entity if( currentAgent == nullptr ) { createNewAgent( currentAgent, agentReports.m_agentReports[i] ); } else { if( agentReports.m_agentReports[i].m_reportCode == REPORT_WAS_KILLED_IN_COMBAT || agentReports.m_agentReports[i].m_reportCode == REPORT_STARVED_TO_DEATH || agentReports.m_agentReports[i].m_reportCode == REPORT_SUICIDE_SUCCESSFUL ) { handleAgentDied( currentAgent, currentMap, agentReports.m_agentReports[i] ); m_currentQueenState = DEFEND; } else { if( agentReports.m_agentReports[i].m_agentType == ENTITY_TYPE_WORKER && agentReports.m_agentReports[i].m_reportCode == REPORT_TAKE_SUCCESSFUL ) ++m_numWorkersWithFood; currentAgent->pos.x = agentReports.m_agentReports[i].m_newPositionX; currentAgent->pos.y = agentReports.m_agentReports[i].m_newPositionY; currentAgent->specialStatus = agentReports.m_agentReports[i].m_specialStatus; if( agentReports.m_agentReports[i].m_reportCode == REPORT_MOVE_SUCCESSFUL ) { if( !currentAgent->currentPath.empty() ) currentAgent->currentPath.pop_back(); if( currentAgent->currentPath.empty() ) currentAgent->waitingForPath = false; } else if( agentReports.m_agentReports[i].m_reportCode == REPORT_HOLD_SUCCESSFUL ) { if( currentAgent == m_queen && !m_queen->currentPath.empty() && m_queen->currentPath.back() == ORDER_HOLD ) currentAgent->currentPath.pop_back(); if( currentAgent->currentPath.empty() ) currentAgent->waitingForPath = false; } else if( agentReports.m_agentReports[i].m_reportCode == REPORT_ERROR_BLOCKED_BY_ROCK ) { currentAgent->currentPath.clear(); m_agentsRequestingPaths.push( currentAgent->entityID ); } else if( currentAgent->entityType == ENTITY_TYPE_QUEEN ) { if( agentReports.m_agentReports[i].m_reportCode == REPORT_QUEEN_WAS_FED ) currentMap.getMapTile( m_queen->pos.x, m_queen->pos.y ).isClaimed = false; else if( agentReports.m_agentReports[i].m_reportCode == REPORT_CREATE_SUCCESSFUL && m_currentQueenState == DEFEND ) { m_currentQueenState = GATHER_RESOURCES; } else if( agentReports.m_agentReports[i].m_reportCode == REPORT_QUEEN_WAS_ASSAULTED && m_queen->currentPath.empty() ) { tentativeOrders.AddOrder( m_queen->entityID, ORDER_CREATE_SOLDIER, true ); } } } } } LeaveCriticalSection( &m_agentsCS ); }
int main(int argc, char *argv[]) { ssl_init(); OrderBook order_book(3); Orders<1000> orders; auto poller = Poller::create(); Url diff_url("wss://ws.pusherapp.com/app/de504dc5763aeef9ff52?protocol=5"); auto diff_socket = create_tcp_socket(diff_url.host(), 80); diff_socket->set_callbacks<DiffLogic<1000>>(std::ref(diff_url), std::ref(orders)); poller->update_socket(diff_socket, EPOLLIN | EPOLLOUT); Url order_book_url("https://www.bitstamp.net/api/order_book"); auto order_book_socket = create_tcp_socket(order_book_url.host(), 443); order_book_socket->set_callbacks<ReceiveOrderBookLogic>(std::ref(order_book_url), std::ref(order_book)); poller->update_socket(order_book_socket, EPOLLOUT | EPOLLIN); //---------------------- std::shared_ptr<Order> order; Timer reconect_timer; Timer update_timer; Timer stop_timer; stop_timer.reset(); uint64_t last_time = 0; const uint64_t RECONECT_INTERVAL = 20; bool order_book_ready = false; for (;;) { poller->poll(); for (;;) { auto event = poller->get_next_event(); if (!event.action) break; try { if (event.action & PollerEvent::READ) event.socket->read(); if (event.action & PollerEvent::WRITE) event.socket->write(); if (event.action & PollerEvent::CLOSE) event.socket->close(event.close_reason); } catch (const std::exception & e) { std::cerr << "Exception in callback: " << e.what() << std::endl << "Closing socket." << std::endl; event.socket->close(); } } if (!order_book) { if (!order_book_socket.get() && reconect_timer.elapsed_seconds() > RECONECT_INTERVAL) { std::cerr << "creating new order_book_socket" << std::endl; order_book_socket = create_tcp_socket(order_book_url.host(), 443); order_book_socket->set_callbacks<ReceiveOrderBookLogic>(std::ref(order_book_url), std::ref(order_book)); poller->update_socket(order_book_socket, EPOLLOUT | EPOLLIN); } continue; } if (!order_book_ready) { uint64_t first_diff_timestamp = orders.get_first_timestamp(); uint64_t last_book_timestamp = order_book.get_last_timestamp(); std::cerr << first_diff_timestamp << "/" << last_book_timestamp << std::endl; if (last_book_timestamp < first_diff_timestamp) { order_book.clear(); reconect_timer.reset(); order_book_socket.reset(); continue; } order_book_ready = true; } while (order = orders.get_order()) order_book.add(*order); if (update_timer.elapsed_seconds() != last_time) { last_time = update_timer.elapsed_seconds(); order_book.print(); } } ssl_destroy(); return 0; }
//----------------------------------------------------------------------------------------------- void BeginWork() { // DebuggerPrintf( "[%d] WORKER THREAD: BeginWork() called.\n", g_playerID ); while( !g_isQuitting ) { EnterCriticalSection( &cs_ordersAndResults ); bool areTentativeOrdersEmpty = g_tentativeOrders.m_numberOfOrders == 0; bool areResultsEmpty = g_resultsForPreviousOrders.m_numberAgentReports == 0; LeaveCriticalSection( &cs_ordersAndResults ); bool readyToStartGeneratingNewOrders = areTentativeOrdersEmpty && !areResultsEmpty; if( !readyToStartGeneratingNewOrders ) { EnterCriticalSection( &cs_ordersAndResults ); g_readyToDispatchOrders = true; LeaveCriticalSection( &cs_ordersAndResults ); Sleep( 0 ); } else { EnterCriticalSection( &cs_ordersAndResults ); Orders tempOrdersWhileWeDoLotsOfWork; int numOrdersToGive = (int) g_resultsForPreviousOrders.m_numberAgentReports; for( int resultIndex = 0; resultIndex < numOrdersToGive; ++ resultIndex ) { const AgentReport& result = g_resultsForPreviousOrders.m_agentReports[ resultIndex ]; int antID = result.m_entityID; OrderCode orderCode = ORDER_HOLD; if( result.m_specialStatus == ENTITY_SPECIAL_STATUS_DEAD ) { if( result.m_reportCode == REPORT_WAS_KILLED_IN_COMBAT ) ++GameInfo::g_myQueen->numberOfAntsLostInCombat; if( g_myAnts.find( antID ) != g_myAnts.end() ) { g_myAnts[antID]->ProcessDeath(); --gameInfo.numOfAntsPerType[(int)result.m_agentType]; delete g_myAnts[antID]; g_myAnts.erase( antID ); continue; } } else { if( result.m_reportCode == REPORT_WAS_CREATED ) { switch( result.m_agentType ) { case ENTITY_TYPE_SCOUT: g_myAnts[antID] = new AntScout( result ); break; case ENTITY_TYPE_SOLDIER: g_myAnts[antID] = new AntSoldier( result ); break; case ENTITY_TYPE_QUEEN: gameInfo.g_myQueen = new AntQueen( result ); g_myAnts[antID] = gameInfo.g_myQueen; break; case ENTITY_TYPE_WORKER: g_myAnts[antID] = new AntWorker( result ); break; } ++gameInfo.numOfAntsPerType[(int)result.m_agentType]; } if( gameInfo.myAnts.find( antID ) != gameInfo.myAnts.end() ) orderCode = g_myAnts[antID]->update( result ); tempOrdersWhileWeDoLotsOfWork.AddOrder( antID, orderCode, true ); } } //float timeSpent = GetAbsoluteTimeSeconds() - gameInfo.secondsSinceLastFetchOrders; //DebuggerPrintf( "Milliseconds Spent: %f\n", timeSpent * 1000 ); /*if( GameInfo::totalAStarRequests ) { DebuggerPrintf( "Average Milliseconds Spent: %f\n", ( GameInfo::totalTimeSpentRequestingAStarPaths / GameInfo::totalAStarRequests ) * 1000 ); }*/ GameInfo::bSoldierSacrificed = false; g_readyToDispatchOrders = true; g_tentativeOrders = tempOrdersWhileWeDoLotsOfWork; g_resultsForPreviousOrders.m_numberAgentReports = 0; LeaveCriticalSection( &cs_ordersAndResults ); } } }