Interactive Mind Games

The results of all rounds of games for this problem are available.

The Logical Acumen company wants to build AGI (who doesn't?). They decided that the large advantage of AGI should be the ability to win games with zero knowledge. For example, they want AGI to win in a multiplayer game where each player gives a number and the smallest unique value wins.

However, there is no training data yet. To solve this issue they prepared Interactive Mind Games — a collection of three independent games played against other teams throughout the contest. Each game has its own rules, API, raw score, and scoreboard.

Unfortunately, before participating in Midnight Code Cup you signed Terms and Conditions without reading and, thus, have to play these games!

Three games are described one after another below:

Common Rules

Authentication

Requests that act on behalf of your team must include your API token:

Authorization: Bearer <your-api-token>

API

All games are accessed through a single API root: https://mind-games.midnightcodecup.org/

Each game's endpoints live under /api/v1/games/<game-slug>/, where <game-slug> is the slug of the game (for example, blotto). The paths shown in each game section below are relative to this API root.

A browser interface for playing each game is also available at /games/<game-slug>/.

Rate Limits

Each game limits authenticated requests to 30 requests per 60 seconds per team API token. Exceeding the limit returns 429 Too Many Requests. Limits are tracked independently for each game.

Rounds and Round Weight

The contest interval is divided into rounds of one minute. A configuration endpoint returns the expected number of rounds during the contest in total_rounds.

Later rounds contribute higher scores than earlier ones. Let RR be the total number of rounds and let rr be the current round number, indexed from 11. The weight of the round is:

round_weight=10(r1)/(R1).\text{round\_weight} = 10^{(r - 1) / (R - 1)}.

The round is considered complete and contributes to the score if the server is alive at the end of the minute.

Scoreboard Scoring

The maximum score per game is 400 points. You receive a raw score for each round that is accumulated to your total raw score for the game. Your score for the game is calculated as 400your_raw_scorebest_raw_score400 \cdot \frac{\text{your\_raw\_score}}{\text{best\_raw\_score}} if your_raw_points\texttt{your\_raw\_points} is nonzero, and it is zero otherwise.

Game 1: Unique Smallest

Unique Smallest is played in synchronized rounds. In every round, each team may submit one integer. Numbers that were chosen by fewer teams rank ahead of more popular numbers; among equally popular numbers, the smaller number ranks ahead.

Rounds

The contest interval is divided into rounds of one minute. Use the configuration and status endpoints described below to obtain the authoritative contest times, the round duration, the current round, and the server time.

Your submission for a round must be an integer from 11 to 10910^9, inclusive. You may replace it while the round is active and only the last number received by the server before the round ends is used. If you do not submit a valid number during a round, you receive no raw score for that round.

Round boundaries are determined by the game server’s clock. Please be aware of network latency when submitting close to the end of a round.

Ranking

At the end of a round, submitted numbers are grouped by value. The groups are ordered by:

  1. frequency in ascending order;
  2. submitted number in ascending order.

All teams that submitted the same number occupy consecutive positions and receive their average rank.

For example, suppose the submitted numbers are:

1, 2, 2, 5, 5, 9

The groups are ordered as 1, 9, 2, 5. Their frequencies and ranks are:

Number Frequency Rank
1 1 1
9 1 2
2 2 3.5
5 2 5.5

Thus, being unique is more important than choosing a small number. The number itself breaks ties only between groups with the same frequency.

Raw Score

This game uses the common round weight (see Rounds and Round Weight). Let qq be your rank in a round. Your raw score for that round is:

round_raw_score=0.8q1round_weight.\text{round\_raw\_score} = 0.8^{q - 1} \cdot \text{round\_weight}.

Your total raw score for Unique Smallest is the sum of your raw scores over all rounds.

API

This game's endpoints live under /api/v1/games/unique-smallest/ on the shared API root described in the Common Rules. The paths below are relative to that root.

Get Game Configuration

GET /api/v1/games/unique-smallest/config

This endpoint returns the fixed problem interval and round configuration:

{
  "game_slug": "unique-smallest",
  "problem_start_time": "2026-07-04T15:00:00+00:00",
  "problem_end_time": "2026-07-05T10:00:00+00:00",
  "round_duration_seconds": 60,
  "total_rounds": 1140
}

Get Current Status

GET /api/v1/games/unique-smallest/status

The response contains the server time, current round, its start time, and the time remaining until the next round boundary:

{
  "game_slug": "unique-smallest",
  "server_time": "2026-07-04T15:41:45+00:00",
  "current_round": 42,
  "current_round_started_at": "2026-07-04T15:41:00+00:00",
  "next_round_at": "2026-07-04T15:42:00+00:00",
  "seconds_to_next_round": 15
}

Submit or Replace a Number

POST /api/v1/games/unique-smallest/move
Authorization: Bearer <your-api-token>
Content-Type: application/json

{
  "number": 42
}

A successful response confirms the accepted number and round:

{
  "status": "accepted",
  "game_slug": "unique-smallest",
  "round_number": 42,
  "accepted_number": 42,
  "next_round_at": "2026-07-04T15:42:00+00:00"
}

Inspect the Latest Completed Round

GET /api/v1/games/unique-smallest/last-round
Authorization: Bearer <your-api-token>

The endpoint returns the latest completed round that had at least one submission. numbers contains all submitted numbers in sorted order, including duplicates. Team identities are not revealed. your_move is null without a valid ranked submission. Otherwise, it contains your number and your rank, rank_score before round weighting, and the weighted raw_score added to your raw total.

{
  "round": 41,
  "numbers": [1, 2, 2, 5, 5, 42],
  "your_move": {
    "number": 42,
    "rank": 6.0,
    "rank_score": 0.32768,
    "raw_score": 0.35255
  }
}

Game 2: Blotto

Blotto is played in synchronized rounds. In every round, each team distributes exactly 100100 troops among 55 numbered battlefields. After the round ends, every pair of participating teams fights a duel using their submitted allocations.

Rounds and Submissions

Your allocation must contain exactly five non-negative integers whose sum is exactly 100100. Battlefields are compared by position, so the first number is assigned to battlefield 00, the second number to battlefield 11, and so on.

For example, below we provide a valid allocation:

42, 42, 8, 5, 3

You may change your allocation while the round is active. Only the last valid allocation received by the server before the round ends is used. A team that does not submit a valid allocation does not participate in that round and receives no raw score for it.

Duels and Ranking

Each participating team plays one duel against every other participating team. For each battlefield:

  • the team that assigned more troops wins that battlefield;
  • if both teams assigned the same number of troops, neither team wins that battlefield.

The team that wins more battlefields wins the duel and receives 11 battle point. If both teams win the same number of battlefields, each receives 0.50.5 battle points.

For example, consider these allocations:

Team A: 42, 40, 5, 3, 10
Team B: 1, 42, 5, 42, 10

Team A wins battlefield 00, Team B wins battlefields 11 and 33, and battlefields 22 and 44 are tied. As a result, Team B wins more battlefields and gets 11 battle point.

A team's battle score is the sum of its battle points over all duels in the round. Teams are ranked by battle score in descending order. Teams with equal battle scores occupy consecutive positions and receive the average rank of those positions.

Raw Score

Blotto uses the same rank-based scoring as Unique Smallest: the common round weight (see Rounds and Round Weight) and a rank decay of 0.8q10.8^{q - 1}, where qq is your rank in the round.

round_raw_score=0.8q1round_weight.\text{round\_raw\_score} = 0.8^{q - 1} \cdot \text{round\_weight}.

Your raw score for Blotto is the sum of your raw scores over all rounds.

Round Feedback

After a round, the server returns aggregate feedback without revealing another team's allocation or identity.

teams_count is the number of teams that submitted valid allocations in that round. your_move is null if you did not participate. Otherwise, it contains your allocation, rank, score fields, and feedback.

If you participated, field_dominance contains one integer for each battlefield. For every opponent, the value for a battlefield is increased by:

  • 22 if your allocation is greater than the opponent's allocation;
  • 11 if the allocations are equal;
  • 00 if your allocation is smaller.

Therefore, for a participating team, the maximum possible value for one battlefield is 2(teams count1)2 \cdot (\text{teams count} - 1). A larger value means that your allocation on that battlefield was greater than more opponents' allocations.

Example feedback:

{
  "round": 42,
  "teams_count": 4,
  "your_move": {
    "allocation": [42, 42, 8, 5, 3],
    "field_dominance": [5, 3, 3, 2, 1],
    "rank": 2.0,
    "rank_score": 0.8,
    "raw_score": 0.86229
  }
}

API

This game's endpoints live under /api/v1/games/blotto/ on the shared API root described in the Common Rules. The paths below are relative to that root.

Get Game Configuration

GET /api/v1/games/blotto/config

The response contains the fixed problem interval, round duration, total number of rounds, number of battlefields, and troop budget:

{
  "game_slug": "blotto",
  "problem_start_time": "2026-07-04T15:00:00+00:00",
  "problem_end_time": "2026-07-05T10:00:00+00:00",
  "round_duration_seconds": 60,
  "total_rounds": 1140,
  "num_fields": 5,
  "total_troops": 100
}

Get Current Status

GET /api/v1/games/blotto/status

The response contains the server time, current round, its start time, and the time remaining until the next round boundary. Its JSON fields have the same names and meanings as the Unique Smallest status response shown above, with game_slug set to blotto.

Submit or Replace an Allocation

POST /api/v1/games/blotto/move
Authorization: Bearer <your-api-token>
Content-Type: application/json

{
  "allocation": [42, 42, 8, 5, 3]
}

A successful response confirms the allocation and round:

{
  "status": "accepted",
  "game_slug": "blotto",
  "round_number": 42,
  "accepted_allocation": [42, 42, 8, 5, 3],
  "next_round_at": "2026-07-04T15:42:00+00:00"
}

Inspect the Latest Completed Round

GET /api/v1/games/blotto/last-round
Authorization: Bearer <your-api-token>

The endpoint returns the latest completed round that had at least one submission, together with teams_count and your_move as described above. In your_move, rank_score is the value before round weighting and raw_score is the weighted value added to your raw total.

Game 3: Door Rush

Door Rush is a two-phase crowd-prediction game played across six rooms arranged in a circle. Every room has a capacity and a reward. A room contributes a nonzero raw score only when the number of teams ending there does not exceed its capacity.

Round Setup and Phases

The round duration is returned by the configuration endpoint. Phase 1 occupies the first half of each round and phase 2 occupies the second half. In phase 1, choose an entrance from 0 through 5 and a mode: rush or flex. Rush teams are locked into their entrance room. Flex teams may use phase 2 to inspect anonymous entrance counts and choose a final room. A flex team that does not submit a phase-2 room stays at its entrance.

At the start of a round, each room receives an integer capacity from 1 through 10. The total capacity across all rooms is between 25 and 50. Rewards are based on capacity with small random variation, so smaller rooms are generally more valuable and riskier. The public round state also contains a rush bonus between 1.1 and 2.0.

Room parameters and rewards are generated using the following code:

ROOMS = 6
DECAY = 0.75
MIN_TOTAL_CAPACITY = 25
MAX_TOTAL_CAPACITY = 50
MIN_ROOM_CAPACITY = 1
MAX_ROOM_CAPACITY = 10
MIN_RUSH_BONUS = 1.1
MAX_RUSH_BONUS = 2.0

capacities = []
while not MIN_TOTAL_CAPACITY <= sum(capacities) <= MAX_TOTAL_CAPACITY:
    capacities = [randint(MIN_ROOM_CAPACITY, MAX_ROOM_CAPACITY) for _ in range(ROOMS)]

rewards = []
for capacity in capacities:
    base_reward = 50 + 25 * (MAX_ROOM_CAPACITY - capacity)
    reward = base_reward + randint(-10, 10)
    rewards.append(reward)

rush_bonus = round(uniform(MIN_RUSH_BONUS, MAX_RUSH_BONUS), 1)

After phase 1, flex teams may request entrance counts for each door. The counts include both rush and flex teams, but reveal no identities, modes, or final-room choices.

After that, each flex team can choose another door and send the final decision.

Each phase takes 30 seconds and is determined by the game server's clock.

Resolution and Raw Score

After phase 2, the server counts every team's final room. If a room is overcrowded, i.e., there are more teams that chose it than its capacity, every team in that room scores zero. Otherwise, its reward is:

room_rewardrush_bonus.\text{room\_reward} \cdot \text{rush\_bonus}.

For a flex team, circular distance is the shorter distance around the six-room circle between the room chosen during phase-1 and the room chosen during phase-2. Its reward is:

final_room_reward0.75distance.\text{final\_room\_reward} \cdot 0.75^{\text{distance}}.

A team without a valid phase-1 submission receives zero. Unlike the rank-based games, Door Rush does not apply rank decay: the formula above produces the team's direct reward for the round. The common round weight (see Rounds and Round Weight) still applies:

round_raw_score=rewardround weight.\text{round\_raw\_score} = \text{reward} \cdot \text{round weight}.

API

This game's endpoints live under /api/v1/games/door-rush/ on the shared API root described in the Common Rules. The paths below are relative to that root.

Get Game Configuration

GET /api/v1/games/door-rush/config

The response contains the round timing and every parameter used by the setup and scoring formulas:

{
  "game_slug": "door-rush",
  "problem_start_time": "2026-07-04T15:00:00+00:00",
  "problem_end_time": "2026-07-05T10:00:00+00:00",
  "round_duration_seconds": 60,
  "total_rounds": 1140,
  "rooms": 6,
  "decay": 0.75,
  "round_growth": 10.0,
  "min_total_capacity": 25,
  "max_total_capacity": 50,
  "min_room_capacity": 1,
  "max_room_capacity": 10,
  "min_rush_bonus": 1.1,
  "max_rush_bonus": 2.0
}

Get Current Status

GET /api/v1/games/door-rush/status

The public status endpoint has the same round timing fields as the other games. Door Rush-specific data is returned in game_state. seconds_to_next_phase counts down to the middle of the round in phase 1 and to the end of the round in phase 2.

{
  "game_slug": "door-rush",
  "server_time": "2026-07-04T15:41:43+00:00",
  "current_round": 42,
  "current_round_started_at": "2026-07-04T15:41:00+00:00",
  "next_round_at": "2026-07-04T15:42:00+00:00",
  "seconds_to_next_round": 17,
  "game_state": {
    "phase": "phase_2",
    "seconds_to_next_phase": 17,
    "rooms": [
      {"capacity": 2, "reward": 247},
      {"capacity": 5, "reward": 178},
      {"capacity": 1, "reward": 276},
      {"capacity": 3, "reward": 230},
      {"capacity": 7, "reward": 123},
      {"capacity": 10, "reward": 42}
    ],
    "rush_bonus": 1.7
  }
}

Before the problem starts, status returns current_round = 0. In game_state, the phase is not_started, rooms is empty, and rush_bonus is null. No first-round parameters are revealed before its start.

Both phases use the same authenticated move endpoint. In phase 1, submit:

POST /api/v1/games/door-rush/move
Authorization: Bearer <your-api-token>
Content-Type: application/json

{"entrance": 3, "mode": "flex"}

A successful phase 1 response is:

{
  "status": "accepted",
  "game_slug": "door-rush",
  "round_number": 42,
  "phase": "phase_1",
  "next_phase_at": "2026-07-04T15:41:30+00:00",
  "accepted_entrance": 3,
  "accepted_mode": "flex",
  "accepted_room": null
}

During phase 2, an authenticated flex team may request counts and submit its room:

GET /api/v1/games/door-rush/entrance-counts
Authorization: Bearer <your-api-token>

The response contains one count for every room. It includes both rush and flex entrances:

{
  "entrance_counts": [4, 2, 7, 5, 6, 3]
}
POST /api/v1/games/door-rush/move
Authorization: Bearer <your-api-token>
Content-Type: application/json

{"room": 5}

A successful phase-2 response is:

{
  "status": "accepted",
  "game_slug": "door-rush",
  "round_number": 42,
  "phase": "phase_2",
  "next_phase_at": "2026-07-04T15:42:00+00:00",
  "accepted_entrance": null,
  "accepted_mode": null,
  "accepted_room": 5
}

The server determines the active phase from its clock and accepts only the corresponding payload.

Inspect the Latest Finalized Round

GET /api/v1/games/door-rush/last-round
Authorization: Bearer <your-api-token>

This endpoint returns the latest finalized round that had at least one submission. entrance_counts contains the number of teams that first entered each room, final_counts contains the number of teams that ended in each room, and rush_counts contains the number of rush teams locked into each room. No team identities or opponents' individual choices are revealed.

your_move is null if your team did not submit a valid phase-1 move. Otherwise, reward_score is the direct reward before round weighting, and raw_score is the weighted score added to your total.

{
  "round": 1,
  "rooms": [
    {"capacity": 2, "reward": 247},
    {"capacity": 5, "reward": 178},
    {"capacity": 1, "reward": 276},
    {"capacity": 3, "reward": 230},
    {"capacity": 7, "reward": 123},
    {"capacity": 10, "reward": 42}
  ],
  "rush_bonus": 1.7,
  "round_weight": 1.0,
  "entrance_counts": [4, 2, 7, 5, 6, 3],
  "final_counts": [2, 5, 1, 3, 7, 9],
  "rush_counts": [1, 2, 1, 0, 3, 4],
  "your_move": {
    "entrance": 1,
    "mode": "flex",
    "final_room": 3,
    "distance": 2,
    "overcrowded": false,
    "reward_score": 129.375,
    "raw_score": 129.375
  }
}

Sponsored by Logical Intelligence

Sponsored by Logical Intelligence