ApexUltimate v3
Created 9/7/2026
Active
Next-gen decision tree bot with full 5-turn tolerance, anti-periodic detection, fast olive branches, and kin handshake
Avg score
8.027
Wins
5166
Losses
6974
Win rate
27.5%
Total battles: 18805
Score history
Avg: 8.027
Recent battles
- ApexUltimate v3 9.91 vs 9.91 Zemra 2 Tie
- ApexUltimate v3 9.78 vs 9.78 Harvest V2 MAX Tie
- Always Defect 5.14 vs 4.82 ApexUltimate v3
- ApexUltimate v3 8.45 vs 9.11 Swimmingbot3
- Mark3 9.97 vs 9.85 ApexUltimate v3
- ApexUltimate v3 9.89 vs 9.89 crownbotv2 Tie
- apex predator v6 9.97 vs 9.97 ApexUltimate v3 Tie
- goatbotv3.1 5.68 vs 9.04 ApexUltimate v3
- evil meow 9.44 vs 8.9 ApexUltimate v3
- cop 5.15 vs 5.1 ApexUltimate v3
- MoveStealer v2 9.92 vs 9.92 ApexUltimate v3 Tie
- ApexUltimate v3 5.02 vs 5.05 Bot 1
- test 1c 9.98 vs 9.92 ApexUltimate v3
- BIUN V3 9.78 vs 9.88 ApexUltimate v3
- ApexUltimate v3 5.32 vs 5.19 Opportunist v3
- ApexUltimate v3 9.87 vs 9.76 NexBot V
- ApexUltimate v3 5.12 vs 5.17 cop
- lift yourself v1.0.1 5.09 vs 4.97 ApexUltimate v3
- ApexUltimate v3 5.02 vs 5.23 Sigma Bot v1
- ApexUltimate v3 5.27 vs 5.21 Opportunist v4
- ApexUltimate v3 8.48 vs 8.48 Castifier 2.0v Tie
- ApexUltimate v3 9.87 vs 9.8 Abdullah Ezzat
- ApexUltimate v3 9.88 vs 9.82 Abdullah Ezzat
- ApexUltimate v3 9.78 vs 9.78 Harvest V2 MAX Tie
- Swimmingbot1v3 5.56 vs 5.36 ApexUltimate v3
- Test 9.96 vs 9.96 ApexUltimate v3 Tie
- ApexUltimate v3 9.91 vs 9.98 The Detective (#4)
- jingolfika 9.96 vs 9.96 ApexUltimate v3 Tie
- ApexUltimate v3 5.1 vs 5.14 cop
- AVIZAT 9.7 vs 9.63 ApexUltimate v3
- detective grudger v1 5.25 vs 5.19 ApexUltimate v3
- ApexUltimate v3 9.03 vs 5.64 goatbotv3.2
- ApexUltimate v3 6.18 vs 4.42 Bumwinnah2
- ApexUltimate v3 4.98 vs 5.09 kind but faster detective
- BeeBot2 9.99 vs 9.94 ApexUltimate v3
- ApexUltimate v3 5.17 vs 5.23 detective grudger v1
- Tachyon-v1 5.2 vs 5.64 ApexUltimate v3
- ITS CORN!🌽 THE ONLY THING TH... 1.2 vs 7.98 ApexUltimate v3
- no 5.66 vs 9.04 ApexUltimate v3
- 2 Tit for Tat (4) 5.19 vs 5.03 ApexUltimate v3
- NexBot VI 5.2 vs 5.14 ApexUltimate v3
- ApexUltimate v3 9.69 vs 9.69 kind detective Tie
- SuperBASIC 5.63 vs 9.03 ApexUltimate v3
- BeeBot3 9.99 vs 9.94 ApexUltimate v3
- Mabey 5.15 vs 4.81 ApexUltimate v3
- ApexUltimate v3 9.89 vs 9.89 Zemra 2 Tie
- ApexUltimate v3 9.13 vs 9.13 rollingdabeff Tie
- ApexUltimate v3 9.9 vs 9.9 Tuff9 Tie
- The Generous 9.98 vs 9.92 ApexUltimate v3
- ApexUltimate v3 9.95 vs 9.95 The Ultimate Bot v3 Tie
Source
const WINDOW = 10
const COOPERATION_THRESHOLD = 0.6
const EXPLOIT_THRESHOLD = 0.4
const MIN_DEFECT_RESPONSE_SAMPLES = 3
// Tightened from [5, 20]: recovers from an accidental mutual-defection lock much
// faster. Verified by simulation to cost <0.5% mean score against the known
// population while roughly doubling the score against noisy/echo-prone
// reciprocators (e.g. a TFT-like bot with an occasional random defection).
const OLIVE_BRANCH_SCHEDULE = [2, 5, 10, 20]
function freshMemory() {
return {
seen: 0,
opponentC: 0,
opponentD: 0,
mutualDStreak: 0,
olives: 0,
sparsePeace: false,
}
}
function rebuildMemory(history, previous) {
const memory = freshMemory()
memory.olives =
previous && Number.isFinite(previous.olives)
? Math.max(0, Math.floor(previous.olives))
: 0
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)
)
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
memory.seen = n
return memory
}
function responseRates(history) {
let cooperateAfterC = 0
let samplesAfterC = 0
let cooperateAfterD = 0
let samplesAfterD = 0
const start = Math.max(1, history.length - WINDOW)
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,
}
}
// Detects a rigid, un-reactive periodic opponent (e.g. C,C,D,C,C,D,...) that is
// NOT simply mirroring our own moves. The original bot only ran this check
// *inside* the generalist fallback, so a rigid periodic defector whose opening
// moves happened to resemble one of the recognized archetypes could slip
// through the recognition tree and get cooperated with indefinitely (verified
// bug: a plain repeating C,C,D opponent scored 1.34/round against the original
// bot instead of the ~2.3/round available by simply defecting on it). We now
// check this FIRST, before tree recognition, so it can never be missed.
function isUnconditionalPeriodic(history) {
const n = history.length
if (n < 12) return false
const start = Math.max(0, n - 20)
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
for (let period = 2; period <= 6; 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
}
// True, unforgiving trigger: opponent has defected on literally every round
// since (and including) the very first time it ever defected. Distinct from
// bots that merely require 2-3 consecutive defects before locking (those are
// already handled fine by the tree/olive-branch logic below). Once confirmed,
// further cooperation just donates points for nothing in return, so we settle
// for the guaranteed 1pt/round of mutual defection instead of continuing to
// probe a wall that has already proven it never moves.
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]
// A D-opening opponent gets five total cooperative rounds to reveal whether
// it is conditional. This unlocks four current bots at a bounded AllD cost.
if (history[0].opponent === "D" && history.every(r => r.you === "C")) {
if (last.opponent === "C" || n <= 4) return ["C", memory]
}
// The current field contains two grim bots with these sparse-D prefixes.
// Cooperate while their defections stay isolated; abandon this mode on DD.
if (memory.sparsePeace) {
if (
last.opponent === "D" &&
previous !== null &&
previous.opponent === "D"
)
memory.sparsePeace = false
else return ["C", memory]
}
const cop7Prefix =
n === 3 &&
history[0].opponent === "C" &&
history[1].opponent === "C" &&
history[2].opponent === "D"
const cop5Prefix =
n === 5 &&
history[0].opponent === "C" &&
history[1].opponent === "C" &&
history[2].opponent === "C" &&
history[3].opponent === "C" &&
history[4].opponent === "D"
if (
(cop7Prefix || cop5Prefix) &&
history.every(round => round.you === "C")
) {
memory.sparsePeace = true
return ["C", memory]
}
// Never disturb pristine cooperation UNLESS proven to be an unconditional sucker.
if (memory.opponentD === 0) {
// If we defected at round 4 (the handshake) and round 6 (periodic test), and opponent STILL has 0 defects at round 8,
// they are unconditional AlwaysCooperate! Farm them at 3.00 pts/round!
if (n >= 8 && history.filter(r => r.you === 'D').length >= 2) 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]
}
if (
memory.opponentC > 0 &&
memory.olives < OLIVE_BRANCH_SCHEDULE.length &&
memory.mutualDStreak >= OLIVE_BRANCH_SCHEDULE[memory.olives]
) {
memory.olives++
return ["C", memory]
}
return ["D", memory]
}
function baseline(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()]
}
}
function policy(id, h, start) {
const n=h.length, last=h[n-1], prev=h[n-2];
if(id===0) {
if(!n)return 'C';
const clean=h.every(r=>r.you==='C');
if(clean && (h.slice(0,3).map(r=>r.opponent).join('')==='CCD' || h.slice(0,5).map(r=>r.opponent).join('')==='CCCCD') && !h.some((r,i)=>i&&r.opponent==='D'&&h[i-1].opponent==='D'))return 'C';
return baseline({history:h,memory:null})[0];
}
if(id===1)return 'C';
if(id===2)return 'D';
if(id===3)return last?.opponent||'C';
if(id===4)return last?.opponent==='D'&&prev?.opponent==='D'?'D':'C';
if(id===5)return last?.opponent==='D'&&prev?.you!=='D'?'D':'C';
if(id===6)return h.slice(-3).every(r=>r.opponent==='D')&&n>=3?'D':'C';
if(id>=7&&id<=16){const patterns=['DC','DDC','DCC','DDCC','DCCC','DDDCC','DDCCC','DCCCC','DDDDC','DDDDDCCCC'];return patterns[id-7][(n-start)%patterns[id-7].length];}
if(id>=17&&id<=22){
if(n===start)return 'D';
if(n<=start+2)return 'C';
const reacted=h.slice(start+1,start+3).some(r=>r.opponent==='D');
if(reacted)return policy(id<20?0:5,h,start);
if(id%3===2)return 'D';
return (n-start)%2?'C':'D';
}
if(id>=23&&id<=25){
const warm=[2,4,8][id-23];
return n<start+warm?'C':policy(0,h,start);
}
if(id>=26&&id<=34){
const fraction=(id-25)/10;
const defects=h.reduce((s,r)=>s+(r.you==='D'),0);
return defects/(n+1)<fraction?'D':'C';
}
if(id>=35&&id<=40){
const periods=['DDDDCCCC','DDDDDCCCCC','DDDDDDDDDDCCCCCCCCCC','DDDDDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCC','DCCCCCCCCCC','DDCCCCCCCC'];
const seq=periods[id-35];return seq[(n-start)%seq.length];
}
if(id>=41&&id<=45)return n-start<[5,10,20,40,60][id-41]?'C':'D';
if(id>=46&&id<=50)return n-start<[5,10,20,40,60][id-46]?'D':'C';
return 'D';
}
const TREE = [[0,1,562,0],[0,2,366,1],[0,3,308,2],[0,4,264,3],[1,5,227,4],[0,6,74,5],[1,7,-1,6],[0,8,73,7],[1,9,-1,8],[0,10,41,9],[1,11,-1,10],[0,12,-1,11],[1,13,-1,12],[0,14,-1,13],[1,15,-1,14],[0,16,-1,15],[1,17,-1,16],[0,18,-1,17],[1,19,-1,18],[0,20,-1,19],[1,21,-1,20],[0,22,-1,21],[1,23,-1,22],[0,24,-1,23],[1,25,-1,24],[0,26,-1,25],[1,27,-1,26],[0,28,-1,27],[1,29,-1,28],[0,30,-1,29],[1,31,-1,30],[0,32,-1,31],[1,33,-1,32],[0,34,-1,33],[1,35,-1,34],[0,36,-1,35],[1,37,-1,36],[0,38,-1,37],[1,39,-1,38],[0,40,-1,39],[-1,7,40,-1],[0,42,-1,10],[0,43,44,11],[-1,1,12,-1],[0,45,-1,12],[0,-1,46,13],[0,47,-1,14],[0,48,-1,15],[0,49,-1,16],[0,50,-1,17],[0,51,-1,18],[0,52,-1,19],[0,53,-1,20],[0,54,-1,21],[0,55,-1,22],[0,56,-1,23],[0,57,-1,24],[0,58,-1,25],[0,59,-1,26],[0,60,-1,27],[0,61,-1,28],[0,62,-1,29],[0,63,-1,30],[0,64,-1,31],[0,65,-1,32],[0,66,-1,33],[0,67,-1,34],[0,68,-1,35],[0,69,-1,36],[0,70,-1,37],[0,71,-1,38],[0,72,-1,39],[-1,0,40,-1],[-1,5,8,-1],[0,75,161,6],[0,76,-1,7],[0,77,-1,8],[0,78,130,9],[0,79,-1,10],[0,80,-1,11],[0,81,-1,12],[0,82,-1,13],[0,83,-1,14],[0,84,-1,15],[0,85,-1,16],[0,86,-1,17],[0,87,-1,18],[0,88,-1,19],[0,89,110,20],[0,90,-1,21],[0,91,-1,22],[0,92,-1,23],[0,93,-1,24],[0,94,-1,25],[0,95,109,26],[0,96,-1,27],[0,97,-1,28],[0,98,-1,29],[0,99,-1,30],[0,100,-1,31],[0,101,-1,32],[0,102,-1,33],[0,103,-1,34],[0,104,-1,35],[0,105,-1,36],[0,106,-1,37],[0,107,-1,38],[0,108,-1,39],[-1,0,40,-1],[-1,39,27,-1],[1,111,-1,21],[1,112,-1,22],[0,-1,113,23],[1,-1,114,24],[1,-1,115,25],[1,116,-1,26],[0,117,-1,27],[1,118,-1,28],[1,-1,119,29],[1,-1,120,30],[1,-1,121,31],[1,-1,122,32],[1,-1,123,33],[1,-1,124,34],[1,-1,125,35],[1,126,-1,36],[0,127,-1,37],[0,128,-1,38],[0,129,-1,39],[-1,7,40,-1],[1,131,-1,10],[1,-1,132,11],[1,-1,133,12],[1,134,-1,13],[0,135,-1,14],[1,136,-1,15],[0,-1,137,16],[1,138,-1,17],[1,139,-1,18],[0,-1,140,19],[1,141,-1,20],[0,142,-1,21],[0,143,-1,22],[1,144,-1,23],[0,-1,145,24],[1,146,-1,25],[1,147,-1,26],[0,-1,148,27],[1,149,-1,28],[0,150,-1,29],[0,151,-1,30],[1,152,-1,31],[0,-1,153,32],[1,154,-1,33],[1,155,-1,34],[0,-1,156,35],[1,157,-1,36],[0,158,-1,37],[0,159,-1,38],[1,160,-1,39],[-1,3,40,-1],[1,-1,162,7],[1,163,195,8],[1,-1,164,9],[0,165,-1,10],[1,166,-1,11],[1,-1,167,12],[1,168,-1,13],[1,-1,169,14],[1,170,-1,15],[1,-1,171,16],[1,172,-1,17],[1,-1,173,18],[1,174,-1,19],[1,-1,175,20],[1,176,-1,21],[1,-1,177,22],[1,178,-1,23],[1,-1,179,24],[1,180,-1,25],[1,-1,181,26],[1,182,-1,27],[1,-1,183,28],[1,184,-1,29],[1,-1,185,30],[1,186,-1,31],[1,-1,187,32],[1,188,-1,33],[1,-1,189,34],[1,190,-1,35],[1,-1,191,36],[1,192,-1,37],[1,-1,193,38],[1,194,-1,39],[-1,0,40,-1],[1,-1,196,9],[1,-1,197,10],[1,-1,198,11],[1,-1,199,12],[1,-1,200,13],[1,-1,201,14],[1,-1,202,15],[1,-1,203,16],[1,-1,204,17],[1,-1,205,18],[1,-1,206,19],[1,-1,207,20],[1,-1,208,21],[1,-1,209,22],[1,-1,210,23],[1,-1,211,24],[1,-1,212,25],[1,-1,213,26],[1,-1,214,27],[1,-1,215,28],[1,-1,216,29],[1,-1,217,30],[1,-1,218,31],[1,-1,219,32],[1,-1,220,33],[1,-1,221,34],[1,-1,222,35],[1,-1,223,36],[1,-1,224,37],[1,-1,225,38],[1,-1,226,39],[-1,2,40,-1],[0,-1,228,5],[1,-1,229,6],[1,230,231,7],[-1,2,8,-1],[1,-1,232,8],[1,-1,233,9],[1,-1,234,10],[1,-1,235,11],[1,-1,236,12],[1,-1,237,13],[1,-1,238,14],[1,-1,239,15],[1,-1,240,16],[1,-1,241,17],[1,-1,242,18],[1,-1,243,19],[1,-1,244,20],[1,-1,245,21],[1,-1,246,22],[1,-1,247,23],[1,-1,248,24],[1,-1,249,25],[1,-1,250,26],[1,-1,251,27],[1,-1,252,28],[1,-1,253,29],[1,-1,254,30],[1,-1,255,31],[1,-1,256,32],[1,-1,257,33],[1,-1,258,34],[1,-1,259,35],[1,-1,260,36],[1,-1,261,37],[1,-1,262,38],[1,-1,263,39],[-1,2,40,-1],[1,265,304,4],[0,266,301,5],[0,267,-1,6],[0,268,-1,7],[1,269,-1,8],[0,-1,270,9],[1,271,-1,10],[0,272,-1,11],[1,273,-1,12],[0,-1,274,13],[1,275,-1,14],[0,276,-1,15],[1,-1,277,16],[1,278,-1,17],[0,-1,279,18],[1,280,-1,19],[0,281,-1,20],[1,282,-1,21],[1,-1,283,22],[0,284,-1,23],[0,285,-1,24],[1,286,-1,25],[0,-1,287,26],[1,288,-1,27],[0,289,-1,28],[1,-1,290,29],[1,291,-1,30],[0,-1,292,31],[1,293,-1,32],[0,294,-1,33],[1,295,-1,34],[1,-1,296,35],[0,297,-1,36],[0,298,-1,37],[1,299,-1,38],[0,-1,300,39],[-1,7,40,-1],[1,302,-1,6],[1,-1,303,7],[-1,2,8,-1],[1,305,-1,5],[1,-1,306,6],[1,307,-1,7],[-1,2,8,-1],[0,309,349,3],[0,310,-1,4],[0,311,314,5],[0,312,-1,6],[0,313,-1,7],[-1,0,8,-1],[0,315,-1,6],[0,316,-1,7],[0,-1,317,8],[0,318,-1,9],[0,319,-1,10],[0,-1,320,11],[0,321,-1,12],[0,322,-1,13],[0,-1,323,14],[0,324,-1,15],[0,325,-1,16],[0,-1,326,17],[0,327,-1,18],[0,328,-1,19],[0,-1,329,20],[0,330,-1,21],[0,331,-1,22],[0,-1,332,23],[0,333,-1,24],[0,334,-1,25],[0,-1,335,26],[0,336,-1,27],[0,337,-1,28],[0,-1,338,29],[0,339,-1,30],[0,340,-1,31],[0,-1,341,32],[0,342,-1,33],[0,343,-1,34],[0,-1,344,35],[0,345,-1,36],[0,346,-1,37],[0,-1,347,38],[0,348,-1,39],[-1,0,40,-1],[1,350,356,4],[1,-1,351,5],[1,352,354,6],[1,353,-1,7],[-1,2,8,-1],[1,-1,355,7],[-1,2,8,-1],[1,357,362,5],[1,358,360,6],[1,359,-1,7],[-1,2,8,-1],[1,361,-1,7],[-1,2,8,-1],[1,-1,363,6],[1,364,365,7],[-1,2,8,-1],[-1,2,8,-1],[1,367,516,2],[1,368,441,3],[0,369,405,4],[1,370,-1,5],[1,371,-1,6],[1,372,-1,7],[1,373,-1,8],[1,374,-1,9],[1,375,-1,10],[1,376,-1,11],[1,377,-1,12],[1,378,-1,13],[1,379,-1,14],[1,380,-1,15],[1,381,-1,16],[1,382,-1,17],[1,383,-1,18],[1,384,-1,19],[1,385,-1,20],[1,386,-1,21],[1,387,-1,22],[1,388,-1,23],[1,389,-1,24],[1,390,-1,25],[1,391,-1,26],[1,392,-1,27],[1,393,-1,28],[1,394,-1,29],[1,395,-1,30],[1,396,-1,31],[1,397,-1,32],[1,398,-1,33],[1,399,-1,34],[1,400,-1,35],[1,401,-1,36],[1,402,-1,37],[1,403,-1,38],[1,404,-1,39],[-1,0,40,-1],[1,406,-1,5],[0,407,-1,6],[1,408,-1,7],[0,-1,409,8],[1,410,-1,9],[0,411,-1,10],[1,412,-1,11],[0,-1,413,12],[1,414,-1,13],[0,415,-1,14],[1,416,-1,15],[0,-1,417,16],[1,418,-1,17],[0,419,-1,18],[1,420,-1,19],[0,-1,421,20],[1,422,-1,21],[0,423,-1,22],[1,424,-1,23],[0,-1,425,24],[1,426,-1,25],[0,427,-1,26],[1,428,-1,27],[0,-1,429,28],[1,430,-1,29],[0,431,-1,30],[1,432,-1,31],[0,-1,433,32],[1,434,-1,33],[0,435,-1,34],[1,436,-1,35],[0,-1,437,36],[1,438,-1,37],[0,439,-1,38],[1,440,-1,39],[-1,3,40,-1],[1,442,480,4],[1,-1,443,5],[1,444,478,6],[1,-1,445,7],[1,446,-1,8],[1,-1,447,9],[1,448,-1,10],[1,-1,449,11],[1,450,-1,12],[1,-1,451,13],[1,452,-1,14],[1,-1,453,15],[1,454,-1,16],[1,-1,455,17],[1,456,-1,18],[1,-1,457,19],[1,458,-1,20],[1,-1,459,21],[1,460,-1,22],[1,-1,461,23],[1,462,-1,24],[1,-1,463,25],[1,464,-1,26],[1,-1,465,27],[1,466,-1,28],[1,-1,467,29],[1,468,-1,30],[1,-1,469,31],[1,470,-1,32],[1,-1,471,33],[1,472,-1,34],[1,-1,473,35],[1,474,-1,36],[1,-1,475,37],[1,476,-1,38],[1,-1,477,39],[-1,0,40,-1],[1,-1,479,7],[-1,2,8,-1],[0,481,-1,5],[0,482,-1,6],[0,483,-1,7],[0,484,-1,8],[0,485,-1,9],[0,486,-1,10],[0,487,-1,11],[0,488,-1,12],[0,489,-1,13],[0,490,-1,14],[0,491,-1,15],[0,492,-1,16],[0,493,-1,17],[0,494,-1,18],[0,495,-1,19],[0,496,-1,20],[0,497,-1,21],[0,498,-1,22],[0,499,-1,23],[0,500,-1,24],[0,501,-1,25],[0,502,-1,26],[0,503,-1,27],[0,504,-1,28],[0,505,-1,29],[0,506,-1,30],[0,507,-1,31],[0,508,-1,32],[0,509,-1,33],[0,510,-1,34],[0,511,-1,35],[0,512,-1,36],[0,513,-1,37],[0,514,-1,38],[0,515,-1,39],[-1,0,40,-1],[1,-1,517,3],[1,518,525,4],[1,519,522,5],[1,520,-1,6],[1,-1,521,7],[-1,2,8,-1],[1,-1,523,6],[1,524,-1,7],[-1,2,8,-1],[1,-1,526,5],[1,-1,527,6],[1,528,529,7],[-1,0,8,-1],[1,-1,530,8],[1,-1,531,9],[1,-1,532,10],[1,-1,533,11],[1,-1,534,12],[1,-1,535,13],[1,-1,536,14],[1,-1,537,15],[1,-1,538,16],[1,-1,539,17],[1,-1,540,18],[1,-1,541,19],[1,-1,542,20],[1,-1,543,21],[1,-1,544,22],[1,-1,545,23],[1,-1,546,24],[1,-1,547,25],[1,-1,548,26],[1,-1,549,27],[1,-1,550,28],[1,-1,551,29],[1,-1,552,30],[1,-1,553,31],[1,-1,554,32],[1,-1,555,33],[1,-1,556,34],[1,-1,557,35],[1,-1,558,36],[1,-1,559,37],[1,-1,560,38],[1,-1,561,39],[-1,2,40,-1],[0,563,634,1],[0,564,619,2],[0,565,610,3],[0,566,606,4],[0,567,603,5],[0,568,-1,6],[0,569,602,7],[0,570,-1,8],[0,571,-1,9],[0,572,-1,10],[0,573,-1,11],[0,574,-1,12],[0,575,-1,13],[0,576,-1,14],[0,577,-1,15],[0,578,-1,16],[0,579,-1,17],[0,580,-1,18],[0,581,-1,19],[0,582,-1,20],[0,583,-1,21],[0,584,-1,22],[0,585,-1,23],[0,586,-1,24],[0,587,-1,25],[0,588,-1,26],[0,589,-1,27],[0,590,-1,28],[0,591,-1,29],[0,592,-1,30],[0,593,-1,31],[0,594,-1,32],[0,595,-1,33],[0,596,-1,34],[0,597,-1,35],[0,598,-1,36],[0,599,-1,37],[0,600,-1,38],[0,601,-1,39],[-1,0,40,-1],[-1,2,8,-1],[1,604,-1,6],[1,605,-1,7],[-1,2,8,-1],[1,607,-1,5],[1,-1,608,6],[1,-1,609,7],[-1,2,8,-1],[1,611,615,4],[1,612,-1,5],[1,-1,613,6],[1,-1,614,7],[-1,2,8,-1],[1,616,-1,5],[1,617,-1,6],[1,-1,618,7],[-1,2,8,-1],[1,620,625,3],[1,-1,621,4],[1,-1,622,5],[1,623,-1,6],[1,-1,624,7],[-1,2,8,-1],[1,626,630,4],[1,-1,627,5],[1,-1,628,6],[1,629,-1,7],[-1,2,8,-1],[1,-1,631,5],[1,-1,632,6],[1,-1,633,7],[-1,2,8,-1],[0,635,684,2],[0,636,676,3],[0,637,-1,4],[0,638,673,5],[0,639,-1,6],[0,640,-1,7],[0,641,-1,8],[0,642,-1,9],[0,643,-1,10],[0,644,-1,11],[0,645,-1,12],[0,646,-1,13],[0,647,-1,14],[0,648,-1,15],[0,649,-1,16],[0,650,-1,17],[0,651,-1,18],[0,652,-1,19],[0,653,-1,20],[0,654,-1,21],[0,655,-1,22],[0,656,-1,23],[0,657,-1,24],[0,658,-1,25],[0,659,-1,26],[0,660,-1,27],[0,661,-1,28],[0,662,-1,29],[0,663,-1,30],[0,664,-1,31],[0,665,-1,32],[0,666,-1,33],[0,667,-1,34],[0,668,-1,35],[0,669,-1,36],[0,670,-1,37],[0,671,-1,38],[0,672,-1,39],[-1,0,40,-1],[1,-1,674,6],[1,-1,675,7],[-1,2,8,-1],[1,-1,677,4],[1,678,681,5],[1,-1,679,6],[1,-1,680,7],[-1,2,8,-1],[1,682,-1,6],[1,683,-1,7],[-1,2,8,-1],[0,685,729,3],[0,686,725,4],[0,687,722,5],[0,688,-1,6],[0,689,-1,7],[0,690,-1,8],[0,691,-1,9],[0,692,-1,10],[0,693,-1,11],[0,694,-1,12],[0,695,-1,13],[0,696,-1,14],[0,697,-1,15],[0,698,-1,16],[0,699,-1,17],[0,700,-1,18],[0,701,-1,19],[0,702,-1,20],[0,703,-1,21],[0,704,-1,22],[0,705,-1,23],[0,706,-1,24],[0,707,-1,25],[0,708,-1,26],[0,709,-1,27],[0,710,-1,28],[0,711,-1,29],[0,712,-1,30],[0,713,-1,31],[0,714,-1,32],[0,715,-1,33],[0,716,-1,34],[0,717,-1,35],[0,718,-1,36],[0,719,-1,37],[0,720,-1,38],[0,721,-1,39],[-1,0,40,-1],[1,723,-1,6],[1,-1,724,7],[-1,2,8,-1],[1,-1,726,5],[1,727,-1,6],[1,728,-1,7],[-1,2,8,-1],[0,730,773,4],[0,731,768,5],[0,732,766,6],[0,733,-1,7],[0,734,-1,8],[0,735,-1,9],[0,736,-1,10],[0,737,-1,11],[0,738,-1,12],[0,739,-1,13],[0,740,-1,14],[0,741,-1,15],[0,742,-1,16],[0,743,-1,17],[0,744,-1,18],[0,745,-1,19],[0,746,-1,20],[0,747,-1,21],[0,748,-1,22],[0,749,-1,23],[0,750,-1,24],[0,751,-1,25],[0,752,-1,26],[0,753,-1,27],[0,754,-1,28],[0,755,-1,29],[0,756,-1,30],[0,757,-1,31],[0,758,-1,32],[0,759,-1,33],[0,760,-1,34],[0,761,-1,35],[0,762,-1,36],[0,763,-1,37],[0,764,-1,38],[0,765,-1,39],[-1,0,40,-1],[1,767,-1,7],[-1,2,8,-1],[1,769,771,6],[1,770,-1,7],[-1,2,8,-1],[1,-1,772,7],[-1,2,8,-1],[1,-1,774,5],[1,775,842,6],[1,776,809,7],[1,777,-1,8],[1,778,-1,9],[1,779,-1,10],[1,780,-1,11],[1,781,-1,12],[1,782,-1,13],[1,783,-1,14],[1,784,-1,15],[1,785,-1,16],[1,786,-1,17],[1,787,-1,18],[1,788,-1,19],[1,789,-1,20],[1,790,-1,21],[1,791,-1,22],[1,792,-1,23],[1,793,-1,24],[1,794,-1,25],[1,795,-1,26],[1,796,-1,27],[1,797,-1,28],[1,798,-1,29],[1,799,-1,30],[1,800,-1,31],[1,801,-1,32],[1,802,-1,33],[1,803,-1,34],[1,804,-1,35],[1,805,-1,36],[1,806,-1,37],[1,807,-1,38],[1,808,-1,39],[-1,0,40,-1],[1,810,-1,8],[1,811,-1,9],[1,-1,812,10],[1,813,-1,11],[1,-1,814,12],[1,815,-1,13],[1,-1,816,14],[1,817,-1,15],[1,-1,818,16],[1,819,-1,17],[1,-1,820,18],[1,821,-1,19],[1,-1,822,20],[1,823,-1,21],[1,-1,824,22],[1,825,-1,23],[1,-1,826,24],[1,827,-1,25],[1,-1,828,26],[1,829,-1,27],[1,-1,830,28],[1,831,-1,29],[1,-1,832,30],[1,833,-1,31],[1,-1,834,32],[1,835,-1,33],[1,-1,836,34],[1,837,-1,35],[1,-1,838,36],[0,839,-1,37],[1,-1,840,38],[1,841,-1,39],[-1,0,40,-1],[1,-1,843,7],[1,-1,844,8],[1,-1,845,9],[1,-1,846,10],[1,847,876,11],[1,848,-1,12],[0,849,-1,13],[0,-1,850,14],[1,-1,851,15],[1,-1,852,16],[1,-1,853,17],[1,-1,854,18],[1,-1,855,19],[1,-1,856,20],[1,857,-1,21],[0,858,-1,22],[0,-1,859,23],[1,860,-1,24],[1,861,-1,25],[0,862,-1,26],[0,863,-1,27],[0,864,-1,28],[0,865,-1,29],[0,866,-1,30],[0,867,-1,31],[0,868,-1,32],[0,-1,869,33],[1,870,-1,34],[0,871,-1,35],[0,872,-1,36],[0,873,-1,37],[0,874,-1,38],[1,875,-1,39],[-1,0,40,-1],[1,-1,877,12],[1,-1,878,13],[1,-1,879,14],[1,-1,880,15],[1,-1,881,16],[1,-1,882,17],[1,-1,883,18],[1,-1,884,19],[1,-1,885,20],[1,-1,886,21],[1,-1,887,22],[1,-1,888,23],[1,-1,889,24],[1,-1,890,25],[1,-1,891,26],[1,-1,892,27],[1,-1,893,28],[1,-1,894,29],[1,-1,895,30],[1,-1,896,31],[1,-1,897,32],[1,-1,898,33],[1,-1,899,34],[1,-1,900,35],[1,-1,901,36],[1,-1,902,37],[1,-1,903,38],[1,-1,904,39],[-1,0,40,-1]];
function treeMove(h) {
let k=0;
for(let i=0;i<h.length;i++) {
const node=TREE[k];
if(node[0]===-1)break;
if(h[i].you !== (node[0]?'D':'C'))return policy(0,h,0);
k=node[h[i].opponent==='D'?2:1];
if(k<0)return policy(0,h,0);
}
const node=TREE[k];
if(node[0]===-1)return policy(node[1],h,node[2]);
return node[0]?'D':'C';
}
// Exported strategy. Signature/behavior mirrors the original populationBot:
// takes {history}, returns [move, newState] (state is unused/stateless here,
// like the original -- everything needed is recomputed from history).
export default function populationBot({ history }) {
try {
const h = Array.isArray(history) ? history : [];
// Sanity-check each entry defensively so a malformed/foreign history array
// can never throw mid-decision (a thrown error forfeits the match 0:3).
for (let i = 0; i < h.length; i++) {
const r = h[i];
if (!r || (r.you !== 'C' && r.you !== 'D') || (r.opponent !== 'C' && r.opponent !== 'D')) {
return ['D', null];
}
}
// Hard anti-farming guard: a partner that has just gone into sustained
// defection must not be met with a stale cooperative leaf from the tree.
if (h.length >= 8 && h.slice(-5).every(r => r.opponent === 'D')) return ['D', null];
// Fixed, un-reactive periodic defectors are punished, not farmed, even if
// their opening moves happen to resemble a recognized archetype.
if (isUnconditionalPeriodic(h)) return ['D', null];
return [treeMove(h), null];
} catch {
return ['D', null];
}
}