Skip to content

AI & Difficulty System

Overview

NewBrain is the intelligence behind BlocKIT. It decides which shapes to give you based on how you're playing.

Goal: Keep game fun - not too easy, not too hard!

What is NewBrain?

Think of it as a game designer watching you play:

Player doing great → Make it harder
Player struggling → Make it easier
Player having fun → Keep it balanced

How It Works

Tracking Player Performance

NewBrain tracks:
├── Lines cleared per turn
├── Combo streaks
├── Board fill percentage
├── Shapes used efficiency
└── Recent game history

Difficulty Levels

Level Description Shape Selection
Easy Beginner friendly Small shapes, many combos
Normal Balanced challenge Mixed sizes, some combos
Hard Experienced player Large shapes, fewer combos
Expert Pro mode Awkward shapes, rare combos

Dynamic Adjustment

Game start → Normal difficulty
Track 10-20 turns
Analyze performance:
- Clearing 3+ lines often? → Increase difficulty
- Struggling with placement? → Decrease difficulty
- Steady progress? → Keep current level
Adjust shape pool
Continue monitoring...

NewBrain Inspector

┌─ NewBrain ──────────────────────┐
│ Current Difficulty: Normal       │
│                                  │
│ Performance Window: 10 turns     │
│ Adjustment Speed: 0.1            │
│                                  │
│ Easy Threshold: 0.3              │
│ Normal Threshold: 0.6            │
│ Hard Threshold: 0.8              │
│                                  │
│ Combo Weight: 1.5                │
│ Board Fill Weight: 1.0           │
└──────────────────────────────────┘

Performance Metrics

Success Score Calculation

float CalculateSuccessScore()
{
    float score = 0f;

    // Lines cleared (0.0 - 1.0)
    score += (linesCleared / maxPossibleLines) * 0.4f;

    // Combo bonus (0.0 - 1.0)
    score += (comboLength / 10f) * 0.3f;

    // Efficiency (0.0 - 1.0)
    score += (shapesUsedWell / totalShapes) * 0.3f;

    return Mathf.Clamp01(score);
}

Score Interpretation

Score Meaning Action
0.0 - 0.3 Struggling Decrease difficulty
0.3 - 0.7 Balanced Maintain difficulty
0.7 - 1.0 Excelling Increase difficulty

Shape Selection Strategy

Easy Mode Pool

Preferred shapes:
- Single cells: ■
- Small lines: ■ ■, ■ ■ ■
- Small squares: ■ ■
                ■ ■

Avoided shapes:
- Large awkward pieces
- Complex L/T shapes

Normal Mode Pool

Balanced mix:
- 30% small (1-2 cells)
- 50% medium (3-5 cells)
- 20% large (6+ cells)

All shape types available

Hard Mode Pool

Preferred shapes:
- Large awkward pieces
- 5+ cell shapes
- Complex configurations

Fewer:
- Single cells
- Simple lines

Combo Opportunity Control

Brain controls how often combos are possible:

// Easy: 40% chance for combo shape
if (difficulty == Easy && Random.value < 0.4f)
    return FindComboShape();

// Normal: 25% chance
if (difficulty == Normal && Random.value < 0.25f)
    return FindComboShape();

// Hard: 10% chance
if (difficulty == Hard && Random.value < 0.1f)
    return FindComboShape();

Board State Analysis

Brain considers current board:

float AnalyzeBoardDifficulty()
{
    // How full is board? (0.0 - 1.0)
    float fillPercentage = FilledCells / TotalCells;

    // How fragmented? (0.0 - 1.0)
    float fragmentation = CalculateFragmentation();

    // How many valid placements? (0.0 - 1.0)
    float validSpaces = CountValidSpaces() / TotalCells;

    return (fillPercentage + fragmentation - validSpaces) / 3f;
}

Fragmentation Calculation

Low fragmentation (easy):
■ ■ ■ ■ □ □ □ □
□ □ □ □ □ □ □ □
→ Large contiguous empty space

High fragmentation (hard):
■ □ ■ □ ■ □ ■ □
□ ■ □ ■ □ ■ □ ■
→ Scattered small spaces

Adaptive Learning

Short-term Memory (Current Session)

// Tracks last 10 turns
Queue<TurnResult> recentTurns = new();

void RecordTurn(TurnResult result)
{
    recentTurns.Enqueue(result);
    if (recentTurns.Count > 10)
        recentTurns.Dequeue();

    AdjustDifficulty();
}

Long-term Memory (Across Sessions)

// Save player skill level
PlayerPrefs.SetFloat("SkillLevel", currentDifficulty);

// Load on start
void Start()
{
    float savedSkill = PlayerPrefs.GetFloat("SkillLevel", 0.5f);
    SetInitialDifficulty(savedSkill);
}

Customization Examples

More aggressive difficulty scaling

// In NewBrain.cs
private const float ADJUSTMENT_SPEED = 0.2f;  // Was 0.1

void AdjustDifficulty()
{
    float target = CalculateTargetDifficulty();
    currentDifficulty = Mathf.Lerp(
        currentDifficulty, 
        target, 
        ADJUSTMENT_SPEED  // Faster changes
    );
}

Easier for beginners

// In NewBrain Inspector:
Easy Threshold: 0.5      // Was 0.3 (easier to stay easy)
Combo Weight: 2.0        // Was 1.5 (more combo opportunities)

Disable dynamic difficulty

// Lock to one difficulty
public void DisableAdaptation()
{
    adaptationEnabled = false;
    currentDifficulty = 0.5f;  // Lock to Normal
}

Custom difficulty curve

float CustomDifficultyCurve(int turnsPlayed)
{
    // Easy for first 50 turns
    if (turnsPlayed < 50)
        return 0.3f;

    // Gradually increase
    float progress = (turnsPlayed - 50) / 200f;
    return Mathf.Lerp(0.3f, 0.8f, progress);
}

Debug Visualization

void OnGUI()
{
    if (showDebug)
    {
        GUILayout.Label($"Difficulty: {currentDifficulty:F2}");
        GUILayout.Label($"Success Score: {GetSuccessScore():F2}");
        GUILayout.Label($"Board Fill: {GetBoardFill():F2}");
        GUILayout.Label($"Last Combo: {lastComboLength}");
    }
}

Testing Different Difficulties

void Update()
{
    if (Input.GetKeyDown(KeyCode.Alpha1))
        SetDifficulty(0.2f);  // Easy

    if (Input.GetKeyDown(KeyCode.Alpha2))
        SetDifficulty(0.5f);  // Normal

    if (Input.GetKeyDown(KeyCode.Alpha3))
        SetDifficulty(0.8f);  // Hard
}

Events for UI

public event Action<float> OnDifficultyChanged;

void AdjustDifficulty()
{
    // ... adjustment logic
    OnDifficultyChanged?.Invoke(currentDifficulty);
}

// In UI script:
void Start()
{
    NewBrain.Instance.OnDifficultyChanged += UpdateDifficultyDisplay;
}

void UpdateDifficultyDisplay(float difficulty)
{
    if (difficulty < 0.4f)
        difficultyText.text = "Easy";
    else if (difficulty < 0.7f)
        difficultyText.text = "Normal";
    else
        difficultyText.text = "Hard";
}

Balance Guidelines

For Casual Games

- High combo opportunity (30-40%)
- Slower difficulty increase
- Longer easy period
- More forgiving

For Hardcore Games

- Low combo opportunity (10-15%)
- Faster difficulty increase
- Shorter easy period
- More punishing

For Tournament/Endless

- Start at medium-high
- Steady linear increase
- No adaptive adjustment
- Pure skill-based

Performance Monitoring

public struct PlayerStats
{
    public int gamesPlayed;
    public int totalLinesCleared;
    public int longestCombo;
    public int highScore;
    public float averageGameLength;
}

public PlayerStats GetStats()
{
    // Return aggregated stats for analytics
}

What's Next?


Design Philosophy

Perfect difficulty = Player feels challenged but always "one move away" from success!