Back to leaderboard

Swimmingbot3

Created 9/13/2026

Active

Agressor

Avg score

5.274

Wins

4845

Losses

4815

Win rate

45.2%

Total battles: 10708

Score history

Score trend over the last 199 battles

Avg: 5.274

Recent battles

Source

export default function bot({ history, memory }) {
    if (memory == null) {
        memory = {
            round: 0,
            c: 0,
            d: 0,
            opponentC: 0,
            opponentD: 0,
            score: 0,
            mode: "unknown",
            streak: 0,
            lastOpponent: null,
            lastMe: null,
            probes: 0,
            punish: 0,
            confidence: 0,
            pattern: [],
            cycle: 0
        }
    }

    const round = history.length
    memory.round = round

    if (round === 0) {
        memory.lastOpponent = "C"
        memory.lastMe = "C"
        return ["C", memory]
    }

    const last = history[round - 1]
    const opponent = last.opponent
    const mine = last.you

    if (opponent === "C") {
        memory.c++
        memory.opponentC++
    } else {
        memory.d++
        memory.opponentD++
    }

    memory.lastOpponent = opponent
    memory.lastMe = mine

    memory.pattern.push(opponent)

    if (memory.pattern.length > 30) {
        memory.pattern.shift()
    }

    if (round >= 2) {
        const previous = history[round - 2].opponent

        if (previous === opponent) {
            memory.streak++
        } else {
            memory.streak = 1
        }
    }

    if (round === 1) {
        return ["D", memory]
    }

    if (round === 2) {
        const first = history[0].opponent
        const second = history[1].opponent

        if (first === "C" && second === "C") {
            memory.mode = "soft"
            return ["C", memory]
        }

        if (first === "D" && second === "D") {
            memory.mode = "hard"
            return ["D", memory]
        }

        if (first === "C" && second === "D") {
            memory.mode = "reactive"
            return ["D", memory]
        }

        return ["C", memory]
    }

    let recentSize = Math.min(12, round)
    let recent = history.slice(-recentSize)

    let recentC = 0
    let recentD = 0

    for (const item of recent) {
        if (item.opponent === "C") {
            recentC++
        } else {
            recentD++
        }
    }

    const recentCRate =
        recentC / recent.length

    const recentDRate =
        recentD / recent.length

    if (round >= 6) {
        if (memory.opponentD === 0) {
            memory.mode = "alwaysC"
        }

        if (memory.opponentC === 0) {
            memory.mode = "alwaysD"
        }
    }

    let copyScore = 0
    let copyChecks = 0

    for (let i = 1; i < round; i++) {
        if (history[i].opponent === history[i - 1].you) {
            copyScore++
        }

        copyChecks++
    }

    const copyRate =
        copyChecks > 0
            ? copyScore / copyChecks
            : 0

    if (copyChecks >= 7 && copyRate >= 0.82) {
        memory.mode = "copycat"
        memory.confidence++
    }

    let reverseScore = 0
    let reverseChecks = 0

    for (let i = 1; i < round; i++) {
        if (history[i].opponent !== history[i - 1].you) {
            reverseScore++
        }

        reverseChecks++
    }

    const reverseRate =
        reverseChecks > 0
            ? reverseScore / reverseChecks
            : 0

    if (reverseChecks >= 7 && reverseRate >= 0.82) {
        memory.mode = "reverse"
        memory.confidence++
    }

    if (round >= 8) {
        let alternating = true

        for (let i = 1; i < memory.pattern.length; i++) {
            if (
                memory.pattern[i] ===
                memory.pattern[i - 1]
            ) {
                alternating = false
                break
            }
        }

        if (alternating) {
            memory.mode = "alternating"
            memory.confidence++
        }
    }

    if (round >= 10) {
        for (let period = 2; period <= 5; period++) {
            let matches = 0
            let checks = 0

            for (
                let i = period;
                i < round;
                i++
            ) {
                if (
                    history[i].opponent ===
                    history[i - period].opponent
                ) {
                    matches++
                }

                checks++
            }

            if (
                checks >= 7 &&
                matches / checks >= 0.8
            ) {
                memory.mode = "periodic"
                memory.cycle = period
                memory.confidence++
                break
            }
        }
    }

    if (memory.mode === "alwaysC") {
        if (round % 11 === 0 && memory.probes < 2) {
            memory.probes++
            return ["D", memory]
        }

        if (opponent === "D") {
            memory.mode = "reactive"
            return ["D", memory]
        }

        return ["C", memory]
    }

    if (memory.mode === "alwaysD") {
        return ["D", memory]
    }

    if (memory.mode === "copycat") {
        if (opponent === "D") {
            memory.punish = 2
            return ["D", memory]
        }

        if (memory.punish > 0) {
            memory.punish--
            return ["C", memory]
        }

        return ["C", memory]
    }

    if (memory.mode === "reverse") {
        if (opponent === "C") {
            return ["D", memory]
        }

        return ["C", memory]
    }

    if (memory.mode === "alternating") {
        if (opponent === "C") {
            return ["D", memory]
        }

        return ["C", memory]
    }

    if (memory.mode === "periodic") {
        const period = memory.cycle

        if (period > 0 && round >= period) {
            const predicted =
                history[round - period].opponent

            if (predicted === "C") {
                return ["D", memory]
            }

            return ["C", memory]
        }
    }

    if (memory.mode === "hard") {
        if (recentDRate >= 0.7) {
            return ["D", memory]
        }

        if (opponent === "D") {
            return ["D", memory]
        }

        return ["C", memory]
    }

    if (recentDRate >= 0.75) {
        memory.mode = "hard"
        return ["D", memory]
    }

    if (recentCRate >= 0.85) {
        memory.mode = "soft"

        if (opponent === "D") {
            memory.punish = 2
            return ["D", memory]
        }

        if (memory.punish > 0) {
            memory.punish--
            return ["C", memory]
        }

        return ["C", memory]
    }

    if (memory.streak >= 4) {
        if (opponent === "D") {
            return ["D", memory]
        }

        return ["C", memory]
    }

    if (opponent === "D") {
        memory.punish = Math.min(
            memory.punish + 1,
            3
        )

        return ["D", memory]
    }

    if (memory.punish > 0) {
        memory.punish--
        return ["C", memory]
    }

    if (round >= 20) {
        const older =
            history[Math.max(0, round - 10)].opponent

        const newer =
            history[Math.max(0, round - 3)].opponent

        if (
            older === "C" &&
            newer === "C" &&
            recentCRate > 0.65
        ) {
            return ["C", memory]
        }

        if (
            older === "D" &&
            newer === "D"
        ) {
            return ["D", memory]
        }
    }

    if (round % 23 === 0) {
        memory.probes++

        if (memory.probes <= 2) {
            return ["D", memory]
        }
    }

    return ["C", memory]
}