Back to leaderboard

Bumwinnah2

Created 9/11/2026

Active

Nah i'd win

Avg score

6.761

Wins

3564

Losses

7669

Win rate

28.1%

Total battles: 12702

Score history

Score trend over the last 199 battles

Avg: 6.761

Recent battles

Source

export default function bot({ history, memory }) {
  memory = memory ?? {
    pattern: null,        // detected opponent archetype
    myMoves: [],
    oppMoves: [],
    streakC: 0,
    streakD: 0,
    alternateCheck: true,
  };

  const n = history.length;

  if (n === 0) {
    return ["C", memory];
  }

  const lastOpp = history.at(-1).opponent;
  memory.oppMoves.push(lastOpp);

  if (lastOpp === "C") { memory.streakC++; memory.streakD = 0; }
  else { memory.streakD++; memory.streakC = 0; }

  // ---- Phase 1 (rounds 1-10): identify opponent archetype ----
  if (n <= 10) {
    memory.pattern = detectPattern(memory.oppMoves);
    const move = "C"; // stay cooperative while gathering data
    memory.myMoves.push(move);
    return [move, memory];
  }

  // Re-check pattern periodically in case opponent shifts strategy
  if (n % 15 === 0) {
    memory.pattern = detectPattern(memory.oppMoves.slice(-15));
  }

  let move;

  switch (memory.pattern) {
    case "alwaysCooperate":
      // Pure exploitation — they never punish.
      move = "D";
      break;

    case "alwaysDefect":
      // No point cooperating, just match them (avoid the 0-point sucker payoff).
      move = "D";
      break;

    case "titForTat":
      // Mirror-matching TFT just locks in mutual cooperation forever —
      // that's actually great (2 pts/round), so cooperate.
      move = "C";
      break;

    case "random":
      // Against unpredictable opponents, defect slightly more than cooperate
      // since expected value favors D when opponent is 50/50.
      move = Math.random() < 0.55 ? "D" : "C";
      break;

    case "grudger":
      // Never defect against a grudger — one slip locks in 1pt/round forever.
      move = "C";
      break;

    default:
      // Unknown/mixed pattern: fall back to reciprocal play with slight
      // optimism (cooperate on ties).
      move = lastOpp === "D" ? "D" : "C";
  }

  memory.myMoves.push(move);
  return [move, memory];
}

// Heuristic pattern detector based on recent opponent move history
function detectPattern(moves) {
  if (moves.length < 5) return "unknown";

  const total = moves.length;
  const defects = moves.filter(m => m === "D").length;
  const defectRate = defects / total;

  if (defectRate === 0) return "alwaysCooperate";
  if (defectRate === 1) return "alwaysDefect";

  // Grudger signature: mostly C, then switches to all D and stays D
  const lastThird = moves.slice(Math.floor(total * 2 / 3));
  const firstTwoThirds = moves.slice(0, Math.floor(total * 2 / 3));
  const earlyDefectRate = firstTwoThirds.filter(m => m === "D").length / (firstTwoThirds.length || 1);
  const lateDefectRate = lastThird.filter(m => m === "D").length / (lastThird.length || 1);
  if (earlyDefectRate < 0.15 && lateDefectRate > 0.85) return "grudger";

  // Random signature: defect rate close to 50%, no obvious runs
  if (defectRate > 0.35 && defectRate < 0.65) return "random";

  // Otherwise assume some form of reciprocal/tit-for-tat-like play
  return "titForTat";
}