JustBeatIt V4
Created 9/9/2026
Active
HE HE!
Avg score
8.022
Wins
3643
Losses
5261
Win rate
23.8%
Total battles: 15333
Score history
Avg: 8.022
Recent battles
- JustBeatIt V4 5.67 vs 5.42 adaptative v2.1
- something 9.94 vs 9.94 JustBeatIt V4 Tie
- The Ultimate Bot v3 9.9 vs 9.9 JustBeatIt V4 Tie
- JustBeatIt V4 4.96 vs 5.03 Firstborn v2
- tit for tat 9.91 vs 9.91 JustBeatIt V4 Tie
- JustBeatIt V4 5.57 vs 5.48 Lagged Punisher
- JustBeatIt V4 5.82 vs 5.63 cop until 2 defect
- Slim Jeans 9.91 vs 9.91 JustBeatIt V4 Tie
- JBot 9.89 vs 9.89 JustBeatIt V4 Tie
- JustBeatIt V4 9.8 vs 9.8 Harvest V3 MAX Tie
- JustBeatIt V4 9.9 vs 9.9 better Tie
- Christopher 5.18 vs 5.06 JustBeatIt V4
- Wikipedia 9.82 vs 9.75 JustBeatIt V4
- tit for tat 9.9 vs 9.9 JustBeatIt V4 Tie
- JustBeatIt V4 5.66 vs 5.73 Test
- AaravC Bot 1 5.44 vs 5.34 JustBeatIt V4
- JustBeatIt V4 9.89 vs 9.89 apex predator v5 Tie
- JBot 9.9 vs 9.9 JustBeatIt V4 Tie
- JustBeatIt V4 9.91 vs 9.91 Forgiving Destroyer Tie
- JustBeatIt V4 5.65 vs 5.71 Grudger
- JustBeatIt V4 9.92 vs 9.92 IDK Bot Tie
- evil meow 9.92 vs 9.92 JustBeatIt V4 Tie
- glitch v2.2 for stag hunt 9.89 vs 9.89 JustBeatIt V4 Tie
- JustBeatIt V4 9.68 vs 9.79 Wikipedia
- Czechias imperium 5.71 vs 5.64 JustBeatIt V4
- JustBeatIt V4 9.9 vs 9.9 BestBot TFT Safe Tie
- JustBeatIt V4 6.17 vs 5.27 big GRIM guy
- JustBeatIt V4 9.91 vs 9.91 Redgux Tie
- JustBeatIt V4 6.48 vs 3.11 FlippityFloppity v3
- apex predator v5 9.9 vs 9.9 JustBeatIt V4 Tie
- big ULTIMATE guy 5.88 vs 6.02 JustBeatIt V4
- Destroyer 5.72 vs 5.65 JustBeatIt V4
- detective grudger v1 5.6 vs 8 JustBeatIt V4
- Test 5.77 vs 5.7 JustBeatIt V4
- JustBeatIt V4 9.89 vs 9.89 Zeus 2 Tie
- glitch v2.1 for stag hunt 9.89 vs 9.89 JustBeatIt V4 Tie
- JustBeatIt V4 5.45 vs 5.49 knight
- Reactant V3.2 9.38 vs 9.58 JustBeatIt V4
- Mabey 5.03 vs 4.96 JustBeatIt V4
- JustBeatIt V4 9.91 vs 9.91 Miyagi-do Tie
- tit for tat 9.9 vs 9.9 JustBeatIt V4 Tie
- JustBeatIt V4 9.9 vs 9.9 glitch v2.1 for stag hunt Tie
- JustBeatIt V4 9.85 vs 9.9 evil tic tacs
- OmegaTitForTat 9.89 vs 9.89 JustBeatIt V4 Tie
- Tieseeeeeker 9.9 vs 9.9 JustBeatIt V4 Tie
- eyk6 9.93 vs 9.93 JustBeatIt V4 Tie
- fightAggression 9.93 vs 9.93 JustBeatIt V4 Tie
- Bumwinnah4 5.27 vs 6.24 JustBeatIt V4
- JustBeatIt V4 4.92 vs 5.04 FirstBot
- JustBeatIt V4 9.89 vs 9.89 Poseidon vAlpha Tie
Source
const COOPERATION_THRESHOLD = 0.6
const EXPLOIT_THRESHOLD = 0.4
const MIN_DEFECT_RESPONSE_SAMPLES = 3
const OLIVE_BRANCH_SCHEDULE = [2, 5, 10, 20]
function freshMemory() {
return {
seen: 0,
opponentC: 0,
opponentD: 0,
mutualDStreak: 0,
olives: 0,
failedOlives: 0,
isSucker: false,
sparsePeace: false,
}
}
function rebuildMemory(history, previous) {
const memory = freshMemory()
memory.olives =
previous && Number.isFinite(previous.olives)
? Math.max(0, Math.floor(previous.olives))
: 0
memory.failedOlives =
previous && Number.isFinite(previous.failedOlives)
? Math.max(0, Math.floor(previous.failedOlives))
: 0
memory.isSucker = previous ? Boolean(previous.isSucker) : false
for (let i = 0; i < history.length; i++) {
const round = history[i]
if (round.opponent === "D") memory.opponentD++
else memory.opponentC++
if (round.you === "D" && round.opponent === "D")
memory.mutualDStreak++
else memory.mutualDStreak = 0
}
memory.seen = history.length
return memory
}
function updateMemory(history, memory) {
const n = history.length
if (
!memory ||
typeof memory !== "object" ||
memory.seen !== n - 1 ||
!Number.isFinite(memory.opponentC) ||
!Number.isFinite(memory.opponentD) ||
!Number.isFinite(memory.mutualDStreak) ||
!Number.isFinite(memory.olives) ||
!Number.isFinite(memory.failedOlives)
)
return rebuildMemory(history, memory)
const last = history[n - 1]
if (last.opponent === "D") memory.opponentD++
else memory.opponentC++
if (last.you === "D" && last.opponent === "D")
memory.mutualDStreak++
else memory.mutualDStreak = 0
if (typeof memory.sparsePeace !== "boolean") memory.sparsePeace = false
if (typeof memory.isSucker !== "boolean") memory.isSucker = false
memory.seen = n
return memory
}
function responseRates(history) {
let cooperateAfterC = 0
let samplesAfterC = 0
let cooperateAfterD = 0
let samplesAfterD = 0
// Dynamic window: scales with game length for better accuracy over long matches
const dynamicWindow = Math.max(10, Math.floor(history.length * 0.3))
const start = Math.max(1, history.length - dynamicWindow)
for (let i = start; i < history.length; i++) {
const ourPreviousMove = history[i - 1].you
const theirMove = history[i].opponent
if (ourPreviousMove === "C") {
samplesAfterC++
if (theirMove === "C") cooperateAfterC++
} else {
samplesAfterD++
if (theirMove === "C") cooperateAfterD++
}
}
return {
pC: (cooperateAfterC + 0.5) / (samplesAfterC + 1),
pD: (cooperateAfterD + 0.5) / (samplesAfterD + 1),
samplesAfterD,
}
}
function isUnconditionalPeriodic(history) {
const n = history.length
if (n < 15) return false
const start = Math.max(0, n - 30)
let sawC = false
let sawD = false
for (let i = start; i < n; i++) {
if (history[i].opponent === "C") sawC = true
else sawD = true
}
if (!sawC || !sawD) return false
// Expanded period loop up to 12 to catch longer repeating cycles
for (let period = 2; period <= 12; period++) {
let matches = true
let comparisons = 0
for (let i = start + period; i < n; i++) {
comparisons++
if (history[i].opponent !== history[i - period].opponent) {
matches = false
break
}
}
if (!matches || comparisons < 8) continue
let explainedByTitForTat = true
for (let i = Math.max(1, start); i < n; i++) {
if (history[i].opponent !== history[i - 1].you) {
explainedByTitForTat = false
break
}
}
if (!explainedByTitForTat) return true
}
return false
}
function isConfirmedGrimLock(history, minRoundsSinceTrigger) {
const n = history.length
let firstD = -1
for (let i = 0; i < n; i++) {
if (history[i].opponent === "D") { firstD = i; break }
}
if (firstD === -1) return false
if (n - firstD < minRoundsSinceTrigger) return false
for (let i = firstD; i < n; i++) {
if (history[i].opponent === "C") return false
}
return true
}
function decide(history, memory) {
const n = history.length
if (n === 0) return ["C", freshMemory()]
memory = updateMemory(history, memory)
const last = history[n - 1]
const previous = n >= 2 ? history[n - 2] : null
if (isConfirmedGrimLock(history, 4)) return ["D", memory]
// Never disturb pristine cooperation, but probe "suckers" on round 15
if (memory.opponentD === 0) {
if (n === 15) return ["D", memory]
if (n > 15 && previous && previous.you === "D" && last.opponent === "C") {
memory.isSucker = true
}
if (memory.isSucker) return ["D", memory]
return ["C", memory]
}
if (isUnconditionalPeriodic(history)) return ["D", memory]
const { pC, pD, samplesAfterD } = responseRates(history)
if (
samplesAfterD >= MIN_DEFECT_RESPONSE_SAMPLES &&
pD >= EXPLOIT_THRESHOLD
)
return ["D", memory]
if (pC >= COOPERATION_THRESHOLD) {
const theirDWasProvoked =
last.opponent === "D" &&
previous !== null &&
previous.you === "D"
if (last.opponent === "D" && !theirDWasProvoked)
return ["D", memory]
return ["C", memory]
}
// Track if our previous olive branch was exploited immediately
if (previous !== null && previous.you === "C" && previous.opponent === "D" && last.opponent === "D") {
memory.failedOlives++
}
// Only offer olive branches if they haven't abused our last attempts
if (
memory.failedOlives < 2 &&
memory.opponentC > 0 &&
memory.olives < OLIVE_BRANCH_SCHEDULE.length &&
memory.mutualDStreak >= OLIVE_BRANCH_SCHEDULE[memory.olives]
) {
memory.olives++
return ["C", memory]
}
return ["D", memory]
}
export default function bot(state) {
let memory =
state && state.memory && typeof state.memory === "object"
? state.memory
: null
try {
const history = state && Array.isArray(state.history) ? state.history : []
const [move, nextMemory] = decide(history, memory)
return [move === "C" ? "C" : "D", nextMemory]
} catch {
return ["D", memory || freshMemory()]
}
}