Commands & delays¶
This page describes how the server parses, represents and schedules the commands sent by AIs, as well as the time cost (delay) of each one.
Parsing — CommandParser¶
Each line received from an AI is analysed by CommandParser::parse
(server/srcs/protocol/CommandParser.cpp:38-67). The parser splits the name
(before the first space) and the argument (the rest), then instantiates the
matching ACommand subclass:
if (name == "Forward" && arg.empty()) return new CmdForward();
...
if (name == "Broadcast" && !arg.empty()) return new CmdBroadcast(arg);
if (name == "Take" && !arg.empty()) return new CmdTake(arg);
if (name == "Set" && !arg.empty()) return new CmdSet(arg);
if (name == "Incantation" && arg.empty()) return new CmdIncantation();
return nullptr;
Strict argument presence
The parser rejects any command whose argument presence is incorrect: an
argument given to Forward, or a missing argument for Take, returns
nullptr → the server replies ko. Only Broadcast, Take and Set
require an argument; all others must have none.
Representation — one class per command¶
Each command is a subclass of the ACommand interface
(server/srcs/commands/ACommand.hpp:42-69), with one instance per command in
server/srcs/commands/. The key interface:
class ACommand {
public:
virtual void execute(Player& player, World& world) = 0;
virtual int getDelay() const = 0; // cost in time units
virtual std::string getResponse() const { return "ok\n"; }
virtual CommandType getType() const = 0;
...
};
The 12 AI commands are all implemented:
Forward, Right, Left, Look, Inventory, Broadcast, Connect_nbr,
Fork, Eject, Take, Set, Incantation.
CmdIncantation is a no-op
CmdIncantation::execute does nothing
(server/srcs/commands/CmdIncantation.cpp:22-26). All elevation logic is
carried by IncantationHandler and IncantationAlgo — see
Game mechanics. The command only serves as a type marker
in the loop.
Scheduling — one delay per command¶
The main loop pops one command per idle AI each iteration. An AI is idle if
it is not incanting, not busy, and has a queued command
(server/srcs/core/Server.cpp:163-217). The command is then scheduled to
run after cmd->getDelay() time units:
ai->setBusy(true);
...
int playerId = ai->getPlayer()->id;
_scheduler->schedule([this, playerId, cmd]() {
...
cmd->execute(*ai->getPlayer(), *_world);
...
ai->queueWrite(cmd->getResponse());
ai->setBusy(false);
_aiDispatcher->decrementPendingResponses(*ai);
delete cmd;
}, cmd->getDelay());
While waiting, the AI is busy: it runs no other command, which serialises its
actions. Incantation is a special case handled upstream by
IncantationHandler::start (see Game mechanics).
Delays in time units
getDelay() returns a cost in time units, converted to milliseconds by
the Scheduler: delay_ms = delay × 1000 / frequency. The higher the
frequency (-f), the faster the actions. See
Game loop & time.
Delay table¶
| Command | Delay (time units) | Argument |
|---|---|---|
Forward |
7 | — |
Right |
7 | — |
Left |
7 | — |
Look |
7 | — |
Inventory |
1 | — |
Broadcast |
7 | text required |
Connect_nbr |
0 | — |
Fork |
42 | — |
Eject |
7 | — |
Take |
7 | object required |
Set |
7 | object required |
Incantation |
300 | — |
(Values read from the getDelay() of the commands/Cmd*.hpp headers;
Connect_nbr: server/srcs/commands/CmdConnectNbr.cpp:29-32.)
Instant Connect_nbr
Connect_nbr has a delay of 0: its response (number of remaining team
eggs) is set in the loop just before sending
(server/srcs/core/Server.cpp:311-316). See
Players, teams & eggs.
flowchart LR
L["AI line"] --> P["CommandParser::parse"]
P -->|null| KO["ko"]
P -->|ACommand*| Q["Per-AI queue"]
Q --> D["Loop: 1 cmd / idle AI"]
D --> S["scheduler.schedule(getDelay())"]
S -->|deadline| E["cmd->execute()<br/>+ response + setBusy(false)"]
See also¶
- Game mechanics — concrete effect of each command.
- Game loop & time — delay → milliseconds conversion.
- AI ↔ Server protocol — exact wire formats of requests and responses.