Back to leaderboard

Opportunist v3

Created 9/13/2026

Active

Plays nice by default, forgives the occasional betrayal so grudges don't spiral, cuts off anyone who's clearly hostile and quietly tests soft targets to see if they'll let it get away with defecting for good.

Avg score

5.733

Wins

6712

Losses

3270

Win rate

64.0%

Total battles: 10494

Score history

Score trend over the last 200 battles

Avg: 5.733

Recent battles

Source

export default function bot({ history, memory }) {
	memory = memory ?? {
		oppD: 0,
		confidence: 0,
		probing: false,
		nextProbe: 8,
		probes: 0,
		brutal: false,
		stalemate: 0,
		forgiving: false,
		rejections: 0,
	}
	const round = history.length

	if (round === 0) return ["C", memory]

	const last = history.at(-1)
	if (last.opponent === "D") memory.oppD++
	if (last.opponent !== "D") memory.stalemate = 0

	if (memory.forgiving) {
		memory.forgiving = false
		if (last.opponent === "D") memory.rejections++
		else memory.rejections = 0
	}

	if (memory.brutal) return ["D", memory]

	const prevOpponent = round >= 2 ? history.at(-2).opponent : null
	const isolatedDefect = last.opponent === "D" && prevOpponent !== "D"

	if (isolatedDefect) memory.probes++
	if (memory.probes >= 3) {
		memory.brutal = true
		return ["D", memory]
	}

	if (memory.probing) {
		memory.probing = false
		if (last.opponent === "D") {
			memory.confidence = 0
			memory.nextProbe = round + 20
		} else {
			memory.confidence++
			memory.nextProbe = round + Math.max(2, 6 - memory.confidence)
		}
	}

	if (memory.confidence >= 6) return ["D", memory]

	const rate = memory.oppD / round
	if (round >= 10 && rate > 0.75) {
		if (memory.rejections >= 2 || Math.random() >= 0.05) return ["D", memory]
		memory.forgiving = true
		return ["C", memory]
	}

	if (last.opponent === "D" && prevOpponent === "D") {
		memory.stalemate++
		if (memory.rejections >= 2) return ["D", memory]
		const forgiveChance = Math.min(0.4, 0.1 + memory.stalemate * 0.02)
		if (Math.random() < forgiveChance) {
			memory.stalemate = 0
			memory.forgiving = true
			return ["C", memory]
		}
		return ["D", memory]
	}

	if (last.opponent !== "D" && round >= memory.nextProbe) {
		memory.probing = true
		return ["D", memory]
	}

	return ["C", memory]
}