[Feature] Squad Battles AI Opponent Generator #4

Open
opened 2026-06-26 05:05:29 +00:00 by funman300 · 0 comments
Owner

Overview

Generate random AI opponent squads for Squad Battles mode. Each opponent should have a unique formation, a randomised name pool, and difficulty-adjusted overall ratings. The weekly lineup must be stable (same seed for 7 days).

Implementation Steps

1. Add AI club templates to data/ai_clubs.json

[
  { "name": "FC Legends", "formation": "4-3-3", "difficulty": "world_class", "overall_range": [83, 88] },
  { "name": "Sunday Rangers", "formation": "4-4-2", "difficulty": "beginner", "overall_range": [55, 65] }
]

Create at least 10 templates across six difficulty tiers:
beginner (55–65), amateur (66–72), semi_pro (73–78), professional (79–82), world_class (83–88), legendary (89–99)

2. Add AI name pool to data/ai_names.json

{
  "first_names": ["Carlos", "Miguel", "Lucas", ...],
  "last_names": ["Silva", "Müller", "Rossi", ...]
}

At least 50 first names and 50 last names for variety.

3. Implement generate_ai_squad in src/services/squad_battles.rs

pub fn generate_ai_squad(difficulty: Difficulty, rng: &mut impl Rng) -> AiSquad
  • Pick a random template for the requested difficulty tier
  • Generate 11 players with random names from the pool
  • Assign overall ratings uniformly within the template's overall_range
  • Assign positions to match the formation (4-3-3 → GK, RB, CB, CB, LB, CM, CM, CM, RW, ST, LW)
  • Assign a random nationality and league to each player

4. Add GET /squad-battles/opponents endpoint

Returns a stable weekly lineup of 5 AI opponents. Seed the RNG with year * 100 + iso_week_number so the lineup is identical for the whole week but rotates every Monday:

{
  "week": "2026-W26",
  "opponents": [
    {
      "id": "opponent_1",
      "club_name": "FC Legends",
      "difficulty": "world_class",
      "squad": [ ...11 players... ]
    }
  ]
}

Use chrono::IsoWeek or chrono::Datelike::iso_week() for the seed.

5. Extend POST /matches/result for Squad Battles mode

When mode == "squad_battles", record the opponent's difficulty and award bonus coins:

  • beginner win: +200 coins
  • amateur win: +400 coins
  • semi_pro win: +700 coins
  • professional win: +1 000 coins
  • world_class win: +1 500 coins
  • legendary win: +2 000 coins

6. Wire coin reward into src/routes/matches.rs

Extend the match result handler to accept optional opponent_id and mode fields in the request body.

7. Write tests

  • generate_ai_squad(Difficulty::WorldClass, &mut rng) → all players overall 83–88
  • generate_ai_squad(Difficulty::Beginner, &mut rng) → all players overall 55–65
  • GET /squad-battles/opponents → returns exactly 5 opponents; calling twice in the same week returns identical results

Acceptance Criteria

  • GET /squad-battles/opponents returns 5 weekly AI opponents
  • Lineup is stable within a calendar week and rotates weekly
  • Match result awards correct coin bonus per difficulty
  • Tests for generation bounds and weekly stability pass
  • cargo clippy -- -D warnings passes
## Overview Generate random AI opponent squads for Squad Battles mode. Each opponent should have a unique formation, a randomised name pool, and difficulty-adjusted overall ratings. The weekly lineup must be stable (same seed for 7 days). ## Implementation Steps ### 1. Add AI club templates to `data/ai_clubs.json` ```json [ { "name": "FC Legends", "formation": "4-3-3", "difficulty": "world_class", "overall_range": [83, 88] }, { "name": "Sunday Rangers", "formation": "4-4-2", "difficulty": "beginner", "overall_range": [55, 65] } ] ``` Create at least 10 templates across six difficulty tiers: `beginner` (55–65), `amateur` (66–72), `semi_pro` (73–78), `professional` (79–82), `world_class` (83–88), `legendary` (89–99) ### 2. Add AI name pool to `data/ai_names.json` ```json { "first_names": ["Carlos", "Miguel", "Lucas", ...], "last_names": ["Silva", "Müller", "Rossi", ...] } ``` At least 50 first names and 50 last names for variety. ### 3. Implement `generate_ai_squad` in `src/services/squad_battles.rs` ```rust pub fn generate_ai_squad(difficulty: Difficulty, rng: &mut impl Rng) -> AiSquad ``` - Pick a random template for the requested difficulty tier - Generate 11 players with random names from the pool - Assign overall ratings uniformly within the template's `overall_range` - Assign positions to match the formation (4-3-3 → GK, RB, CB, CB, LB, CM, CM, CM, RW, ST, LW) - Assign a random nationality and league to each player ### 4. Add `GET /squad-battles/opponents` endpoint Returns a stable weekly lineup of 5 AI opponents. Seed the RNG with `year * 100 + iso_week_number` so the lineup is identical for the whole week but rotates every Monday: ```json { "week": "2026-W26", "opponents": [ { "id": "opponent_1", "club_name": "FC Legends", "difficulty": "world_class", "squad": [ ...11 players... ] } ] } ``` Use `chrono::IsoWeek` or `chrono::Datelike::iso_week()` for the seed. ### 5. Extend `POST /matches/result` for Squad Battles mode When `mode == "squad_battles"`, record the opponent's difficulty and award bonus coins: - beginner win: +200 coins - amateur win: +400 coins - semi_pro win: +700 coins - professional win: +1 000 coins - world_class win: +1 500 coins - legendary win: +2 000 coins ### 6. Wire coin reward into `src/routes/matches.rs` Extend the match result handler to accept optional `opponent_id` and `mode` fields in the request body. ### 7. Write tests - `generate_ai_squad(Difficulty::WorldClass, &mut rng)` → all players overall 83–88 - `generate_ai_squad(Difficulty::Beginner, &mut rng)` → all players overall 55–65 - `GET /squad-battles/opponents` → returns exactly 5 opponents; calling twice in the same week returns identical results ## Acceptance Criteria - [ ] `GET /squad-battles/opponents` returns 5 weekly AI opponents - [ ] Lineup is stable within a calendar week and rotates weekly - [ ] Match result awards correct coin bonus per difficulty - [ ] Tests for generation bounds and weekly stability pass - [ ] `cargo clippy -- -D warnings` passes
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: funman300/OpenFUT-Core#4