-
-
Save dzaima/ef83fff370bd93da3e24a6d752754f62 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const DEBUG = true; | |
const ADD = (a,b) => a + b; | |
var toReturn; | |
var me = view[4].ant; | |
me.me = true; // for basedOn to know | |
var food = me.food; | |
var type = me.type; | |
var isQueen = type == 5; | |
// raw directions | |
const UL = 0; const U = 1; const UR = 2; | |
const L = 3; const C = 4; const R = 5; | |
const DL = 6; const D = 7; const DR = 8; | |
// directions from the reference point | |
const ul = 16; const u = 17; const ur = 18; | |
const l = 19; const c = 20; const r = 21; | |
const dl = 22; const d = 23; const dr = 24; | |
const rp = 16; | |
function allRots (arr) { | |
return [arr, | |
[arr[2], arr[5], arr[8], | |
arr[1], arr[4], arr[7], | |
arr[0], arr[3], arr[6]], | |
[arr[8], arr[7], arr[6], | |
arr[5], arr[4], arr[3], | |
arr[2], arr[1], arr[0]], | |
[arr[6], arr[3], arr[0], | |
arr[7], arr[4], arr[1], | |
arr[8], arr[5], arr[2]]]; | |
} | |
function on (where, what) { | |
if (Array.isArray(where)) return where.some(c=>on(c, what)); | |
return basedOn(get(where), what); | |
} | |
function find (what) { | |
return view.findIndex(c=>basedOn(c, what)); | |
} | |
function findAll (what) { | |
return view.map((c,i)=>[c,i]).filter(c=>basedOn(c[0], what)).map(c=>c[1]); | |
} | |
function count (what) { | |
return findAll(what).length; | |
} | |
function findRel (what) { | |
return ref(find(what)); | |
} | |
function findAllRel (what) { | |
return findAll(what).map(c=>ref(c)); | |
} | |
function found (what) { | |
return find(what) != -1; | |
} | |
function get (dir) { | |
if (Array.isArray(dir)) return dir.map(c=>get(c)); | |
return view[raw(dir)]; | |
} | |
function deq (a, b) { | |
return a==b || raw(a)==raw(b); | |
} | |
// returns a random number from 0 to 4, based on the rotation. Will always have a possibility of being 0 | |
function random4 () { | |
var scores = allRots(view.map(c=>c.color)).map((c) => { | |
let cscore = 0; | |
c.forEach((c) => { | |
cscore*= 8; | |
cscore+= c-1; | |
}); | |
return cscore; | |
}); | |
var bestscore = -1, bestindex = 1; | |
scores.forEach((score, index) => { | |
if (score > bestscore) { | |
bestscore = score; | |
bestindex = index; | |
} | |
}) | |
return bestindex; | |
} | |
function rotate (what, times) { | |
for (var i = 0; i < times; i++) what = [2,5,8,1,4,7,0,3,6][what]; | |
return what; | |
} | |
function raw(dir) { | |
if (dir&rp) return rotate(dir&~rp, Pattern.rot); | |
return dir; | |
} | |
function ref(dir) { | |
if (dir == -1) return -1; | |
if (dir&rp) return dir; | |
return rotate(dir, 4-Pattern.rot)|rp; | |
} | |
function move(dir) { | |
if (Array.isArray(dir)) return dir.some(c=>move(c)); | |
dir = raw(dir); | |
return result({cell:dir}); | |
} | |
function color(dir, col) { | |
dir = raw(dir); | |
return result({cell:dir, color:Math.abs(col)}); | |
} | |
function rcolOf(what) { | |
return Number.isInteger(what)? what : what.color; | |
} | |
function colOf(what) { | |
return Math.abs(Number.isInteger(what)? what : what.color); | |
} | |
function sees(c1,c2) { | |
c1 = raw(c1); | |
c2 = raw(c2); | |
return Math.abs(c1%3-c2%3)<2 && Math.abs(Math.floor(c1/3)-Math.floor(c2/3))<2; | |
} | |
function spawn(dir, t) { | |
if (Array.isArray(t)) return t.some(c=>spawn(dir, c)); | |
if (Array.isArray(dir)) return dir.some(c=>spawn(c, t)); | |
dir = raw(dir); | |
return result({cell:dir, type:t}); | |
} | |
// repairs a single cell | |
function correct(dir) { | |
dir = raw(dir); | |
let col = colOf(Pattern.pt[dir]); | |
if (col && view[dir].color != col) { | |
color(dir, col); | |
return false; | |
} | |
return true; | |
} | |
// if pattern is repaired, returns true, otherwise fixes one cell | |
function repair(firstdirs) { | |
if (!Array.isArray(firstdirs)) firstdirs = []; | |
firstdirs = firstdirs.map(c=>raw(c)); | |
//console.log("FD",firstdirs); | |
var found = []; | |
view.forEach((v, i) => { | |
let col = colOf(Pattern.pt[i]); | |
if (col && v.color != col) { | |
found.push(i); | |
} | |
}); | |
if (found.length == 0) return true; | |
if (firstdirs.some(c=>found.includes(c))) { | |
let dir = firstdirs.find(c=>found.includes(c)); | |
let col = colOf(Pattern.pt[dir]); | |
color(dir, col); | |
return false; | |
} | |
let dir = found[0]; | |
let col = colOf(Pattern.pt[dir]); | |
color(dir, col); | |
return false; | |
} | |
function flatten (arr) { | |
return arr.reduce((a,b)=>a.concat(b)); | |
} | |
class Pattern { | |
constructor(pattern, inherit) { | |
this.pt = pattern; | |
if (inherit) { | |
this.vp = inherit.vp; | |
this.hp = inherit.hp; | |
this.rot = inherit.rot; | |
} else { | |
this.vp = 0; | |
this.hp = 0; | |
this.rot = 0; | |
} | |
} | |
rotateClockwise() { | |
var arr = []; | |
for (var i = 0; i < this.pt[0].length; i++) { | |
var sarr = []; | |
for (var j = this.pt.length-1; j >= 0; j--) { | |
sarr.push(this.pt[j][i]); | |
} | |
arr.push(sarr); | |
} | |
//console.log(arr); | |
var res = new Pattern(arr, this); | |
res.rot = (this.rot+1) % 4; | |
return res; | |
} | |
select(x, y, w, h) { | |
var res = new Pattern(this.pt.slice(y, y+h).map(c=>c.slice(x, x+w)), this); | |
res.hp+= x; | |
res.vp+= y; | |
return res; | |
} | |
rots(dir) { | |
var pts = []; | |
var pt = new Pattern(this.pt, this); | |
for (let i = 0; i < this.lengthIn(dir); i++) { | |
pts.push(pt); | |
pt = pt.rotate(dir); | |
} | |
return pts; | |
} | |
map(fn) { | |
return new Pattern(this.pt.map(ln=>ln.map(fn)), this); | |
} | |
lengthIn(dir) { | |
if (dir == U || dir == D) return this.pt.length; | |
else if (this.pt.length > 0) return this.pt[0].length; | |
else return 0; | |
} | |
rotate(dir) { // moves the center to that direction | |
if (dir == R) { | |
var res = new Pattern(this.pt.map(c=>((h,...t)=>t.concat(h))(...c)), this); | |
res.hp++; | |
return res; | |
} | |
if (dir == L) { | |
var res = new Pattern(this.pt.map(a=>(a=>a.slice(-1).concat(a.slice(0,-1)))(a)), this); | |
res.hp++; | |
return res; | |
} | |
if (dir == D) { | |
var res = new Pattern(((h,...t)=>t.concat([h]))(...this.pt), this); | |
res.vp++; | |
return res; | |
} | |
throw "rotate unimplemented dir!"; | |
} | |
setSize(xs, ys) { | |
var arr = []; | |
for (let y = 0; y < ys; y++) { | |
var ca = []; | |
for (let x = 0; x < xs; x++) { | |
ca.push(this.pt[y % this.pt.length][x % this.pt[0].length]); | |
} | |
arr.push(ca); | |
} | |
return new Pattern(arr, this); | |
} | |
static clear() { | |
Pattern.patterns = []; | |
} | |
static add(pattern, action, scorer, presetRot) { | |
if (Array.isArray(pattern)) pattern = new Pattern(pattern); | |
pattern = pattern.setSize(3,3); | |
if (scorer === undefined) { | |
scorer = (pt) => () => { | |
var free = 0; | |
var T; // temp | |
var corrects = flatten(pt.pt).map((guess, index) => rcolOf(guess)==0? (free++,null) : (T=basedOn(view[index], guess, true))===false? false : T*(rcolOf(guess)<0? (free++,0.1) : 1)); | |
var correctsHard = flatten(pt.pt).map((guess, index) => guess==0? 0 : basedOn(view[index], guess)); | |
var corrstr = correctsHard.map(c=>c?"#":" ").reduce((a,b)=>a+b); | |
var score = corrects.reduce(ADD)*9 / (9-free); | |
if (/(...)?######.*|.?##.##.##/.test(corrstr)) score+= 2; // 2x3 = good | |
if (!found({ant:"enemy"}) && !corrects[4] && corrects[4] !== null) score-= 3; // all hail the holy center cell | |
// console.log(pt.pt); | |
if (corrects.includes(0)) score = 0; // queen is in an unallowed place; abort all | |
if (DEBUG && score > 4) console.log("scored", score, "free", free, "corr", corrects.map(c=>+c), flatten(pt.pt).map(c=>c.ant? "A"+c.ant.type : c), pt.vp); | |
return score; | |
} | |
} | |
var cpt = pattern.setSize(3,3); | |
var orig = cpt.pt; | |
for (let i = 0; i < 4; i++) { | |
cpt = cpt.rotateClockwise(); | |
if (!presetRot || presetRot == cpt.rot) { | |
cpt.action = action; | |
cpt.scorer = scorer(cpt); | |
cpt.raw = orig; | |
cpt.view = allRots(view)[cpt.rot]; | |
Pattern.patterns.push(cpt); | |
} | |
} | |
} | |
static choose() { | |
var maxScore = -1e307; | |
var nextScore = -1e308; | |
var maxPt; | |
Pattern.patterns.forEach((c) => { | |
var score = c.scorer(); | |
if (score >= maxScore) { | |
nextScore = maxScore; | |
maxScore = score; | |
maxPt = c; | |
} | |
}); | |
var free = 0; | |
var corrects = flatten(maxPt.pt).map((guess, index) => guess==0? (free++,1) : basedOn(view[index], guess)); | |
Pattern.hardcorr = flatten(maxPt.pt).map((guess, index) => colOf(guess)<2? 0 : basedOn(view[index], guess)).reduce(ADD); | |
Pattern.corr = corrects.reduce(ADD); | |
Pattern.incorr = 9-Pattern.corr; | |
Pattern.confidence = maxScore-nextScore; | |
Pattern.rot = maxPt.rot; | |
Pattern.action = maxPt.action; | |
Pattern.pt = flatten(maxPt.pt); | |
Pattern.hp = maxPt.hp; | |
Pattern.raw = maxPt.raw; | |
Pattern.view = maxPt.view; | |
Pattern.vp = maxPt.vp; | |
Pattern.score = maxScore; | |
if (DEBUG) console.log("score", maxScore, "confidence", Pattern.confidence, "corr", Pattern.corr, "pt", maxPt.pt);//, "fn", maxPt.action+"" | |
} | |
static ref(...args) { | |
Pattern.clear(); | |
Pattern.add(...args); | |
Pattern.choose(); | |
} | |
} | |
Pattern.patterns = []; | |
/* | |
is the 2nd param a subset of the 1st param. | |
guess can be a number (color), or an object ({color:..,ant:..,..}) | |
guess.ant can be "worker", "queen", "enemy", "enemyworker", "enemyqueen" with obvious meanings. Note that "friend" ≠ me | |
guess.ant.type can be an array, ORing | |
true - correct! | |
false - not correct | |
0 - notqueen doesn't match (aka very bad) | |
*/ | |
function basedOn(real, guess, negativesEqual) { | |
if (Array.isArray(real)) return real.some(c=>basedOn(c, guess, negativesEqual)); | |
if (Number.isInteger(guess)) guess = {color:guess}; | |
if (guess.color && Math.abs(guess.color) != real.color && !(negativesEqual && guess.color<0)) return false; // 0 handles itself | |
if (guess.notqueen && real.ant && real.ant.friend && real.ant.type==5) return 0; | |
if (guess.obstacle !== undefined) { | |
if (guess.obstacle && !real.ant && !(food && real.food && !isQueen)) return false; | |
if (!guess.obstacle && (real.ant || (food && real.food && !isQueen))) return false; | |
} | |
if (guess.badobstacle !== undefined) { | |
if (guess.badobstacle && !(real.ant && !real.ant.friend) && !(food && real.food && !isQueen)) return false; | |
if (!guess.badobstacle && ((real.ant && !real.ant.friend) || (food && real.food && !isQueen))) return false; | |
} | |
if (guess.ant) { | |
if (!real.ant) return false; | |
if (guess.ant == "worker" &&!( real.ant.friend && real.ant.type!=5)) return false; | |
if (guess.ant == "queen" &&!( real.ant.friend && real.ant.type==5)) return false; | |
if (guess.ant == "enemyqueen" &&!(!real.ant.friend && real.ant.type==5)) return false; | |
if (guess.ant == "enemyworker" &&!(!real.ant.friend && real.ant.type!=5)) return false; | |
if (guess.ant == "friend" && (!real.ant.friend || real.ant.me)) return false; | |
if (guess.ant == "enemy" && real.ant.friend) return false; | |
if (Number.isInteger(guess.ant) && real.ant.type != guess.ant) return false; | |
if (guess.ant.friend !== undefined && guess.ant.friend !== real.ant.friend) return false; | |
if (guess.ant.type !== undefined && !(Array.isArray(guess.ant.type)? guess.ant.type.some(c=>c == real.ant.type) : guess.ant.type == real.ant.type)) return false; | |
if (guess.ant.food !== undefined && guess.ant.food !== real.ant.food) return false; | |
} | |
if (guess.food !== undefined && guess.food !== real.food) return false; | |
// console.log("matched"); | |
return true; | |
} | |
function result (action) { | |
if (toReturn !== undefined) return 0; | |
var color = action.color; | |
var type = action.type; | |
var cell = action.cell; | |
if (type < 1 || type > 4) return false; | |
if (!(cell >= 0 && cell <= 8)) return false; | |
if (color < 1 || color > 8) return false; | |
if (!color && ((view[cell].ant && cell != 4) || (isQueen? (view[cell].food && type) : (food && view[cell].food)))) return false; // can't walk onto ant, can't spawn on food, can't move to food with food | |
if (!isQueen && type) return false; | |
if (!isQueen && !color && food && view[cell].food) return false; | |
if (isQueen && !food && type) return false; | |
if (type && cell==C) return false; | |
if (color && type) return false; | |
toReturn = action; | |
return true; | |
} | |
const WH = 1; // white | |
const C1 = 6; // should stay green (or whatever is trail-eraser most ignorant of :p) | |
const C2 = 7; // blue | |
const C3 = 3; // purple | |
const C4 = 2; // yellow | |
const C5 = 8; // black | |
const C6 = 5; // red | |
const C7 = 4; // cyan | |
// C1=GR,C2=BL,C4=YL,C5=DK | |
//-----------------------------------------------------------------------------------------------------------------------------------------------------\\ | |
//----------------------------------------------------------------------- MAIN CODE ---------------------------------------------------------------------\\ | |
//---------------------------------------------------------------------------------------------------------------------------------------------------------\\ | |
if (DEBUG) { | |
console.log(); | |
console.log(type, view.map(c=>c.ant? "A"+c.ant.type : c.color)); | |
} | |
const Ut = 1; | |
const Dt = 2; | |
const Ht = 4; | |
const Uo = {ant:{type:Ut,friend:true}}; | |
const Do = {ant:{type:Dt,friend:true}}; | |
const Ho = {ant:{type:Ht,friend:true}}; | |
const Mo = {ant:{type:[Ut,Dt],friend:true}}; | |
const Fo = {food:1}; | |
const Qo = {ant:{type:5}}; | |
const FRIEND = {ant:"friend"}; | |
const ENEMY = {ant:"enemy"}; | |
const OBSTACLE = {obstacle:true}; | |
const FREE = {obstacle:false}; | |
const BADOBSTACLE = {badobstacle:true}; | |
const STARTINGFOOD = 7; | |
const ENDINGFOOD = 100; | |
const isMiner = type==Ut || type==Dt; | |
var friendCount = count(FRIEND); | |
const mydir = type==Ut? u : d; | |
const notmydir = type==Ut? d : u; | |
const foodExt = [C5, C7, C2]; | |
const rawRail = [ | |
[-1,-1,C7,-1], // 44 04 14 24 | |
[C6,-1,-1,-1], // 43 03 13 23 | |
[C5,C3,C4,C1], // 42 02 12 22 | |
[C4,C5,C2,C3], // 41 01 11 21 | |
[C3,C2,C1,C2], // 40 00 10 20 | |
[C1,C3,C3,C4], // 41 01 11 21 | |
[C5,C2,C4,C1], // 42 02 12 22 | |
[C6,-1,-1,-1], // 43 03 13 23 | |
[-1,-1,C7,-1] // 44 04 14 24 | |
].map((ln,row)=>(row<3||row>5)? ln.map(c=>({notqueen:true,color:c})) : ln); // queen can't be in the top & bottom 3 rows | |
const railPtt = new Pattern(rawRail); | |
railPtt.hp = 0; | |
railPtt.vp = -3; | |
function section(ln, action, scorer) { | |
if (ln > 0) section(-ln, action, scorer); | |
var sct = railPtt.select(0, ln+3, 4, 3); | |
var parts = Math.abs(ln)==3? [sct.setSize(3,3)] : sct.rots(R); | |
parts.map(c=>Pattern.add(c, action, scorer)); | |
} | |
section(0, () => { | |
if (isQueen) { // queen | |
var HM = Pattern.view.map(c=>+basedOn(c, Ho)); | |
var helperRows = [HM.slice(0,3),HM.slice(6,9)].map(c=>c.lastIndexOf(1)).map((c,i) => (c==0 && on(i==0? u : d, OBSTACLE)) ? -1 : c); | |
var minH = Math.min(helperRows[0],helperRows[1]); | |
var maxH = Math.max(helperRows[0],helperRows[1]); | |
if ((minH == -1 || maxH == 2) && on(r, ENEMY)) move(on(ur, ENEMY)? [d,u] : [u,d]); // initialize transporting around enemy | |
else if (on([u,d], ENEMY)) move(r); | |
else if (minH != -1 && friendCount < 3 && Pattern.corr != 9 && Pattern.hp != 1 && food < ENDINGFOOD) { // spawn miners | |
if (random4()%2 && helperRows[0] != 0) spawn([u,ul], Ut); | |
else if (helperRows[1] != 0) spawn([d,dl], Dt); | |
else spawn(l, [Ut,Dt]); | |
} else if (repair()) { | |
if (found(ENEMY)) move(r); // move away from the enemy | |
else if (minH == -1 && count(Ho) < 2) { // spawn helpers | |
if (helperRows[0] == -1) spawn([u,ur,ul],Ht); | |
else spawn([d,dr,dl],Ht); | |
} else if (minH != 0 && maxH == 2) { | |
move(r); | |
} else if (minH > 0 && Pattern.hp != 1) move(r); | |
} | |
} else if (isMiner) { // miners | |
if (repair()) { | |
if (on(l, Qo)) move([u,d]); | |
else if (on(mydir+1, OBSTACLE)) { | |
if (on(r, Qo)) move(mydir); | |
else if (on(r, OBSTACLE)) move([notmydir,notmydir+1]); | |
else move([r,mydir,notmydir,notmydir+1]); | |
} else move([mydir,r,notmydir]); | |
} | |
} else { // helper | |
if (repair()) { // TODO restore to queen | |
move(on([d,dr,dl], Ho)? [u,d] : [d,u]); | |
} | |
} | |
}); | |
section(1, () => { | |
var dir = Pattern.vp > 0? d : u; | |
var notdir = Pattern.vp > 0? u : d; | |
// console.log(dir,mydir,Pattern.hp,Pattern.vp); | |
if (isQueen) { | |
if (repair()) { | |
if (on(notdir, FREE) && on(notdir+1, FREE)) move(notdir); | |
else move(random4()? r : [r, notdir+1]); | |
} | |
} else if (type==Ht) { // helpers | |
var queenRel = (findRel(Qo)-rp)%3; | |
if (queenRel == 1 && Pattern.hp == 1 && on(dir-1, {ant:{}})) move(r); | |
else if (queenRel == 2 && on(r, FREE)) move(r); // queen's moving forward | |
else if (repair()) { | |
//console.log(on([r,l], Ho),queenRel); | |
if (on([r,l], Ho)) move(notdir); | |
else if (queenRel == 0 && on(l, Qo)) move(r); // queen's moving around enemy | |
else if (queenRel == 1 && on(notdir+1, ENEMY)) move(r); // queen needs space to move | |
} | |
} else { // miners | |
if (!food && dir == mydir && on(r, Ho) && on(notmydir+1, Qo)) { | |
if (Pattern.hp == 0) move(mydir); // move out! | |
} else if (repair()) { | |
var queenRel = (findRel(Qo)-rp)%3; | |
if (queenRel == 2 && !on(r,Ho)) move(C); // stay still, queen's moving forward | |
if (on(l, Ho) && on(notdir-1, Qo)) move(dir-1); // I'm in front of the queen :/ | |
else if (on(notdir, Qo)) move([l, dir, dir-1]); // don't move in front of the queen! | |
else if (dir != mydir) { | |
if (on(notdir+1, OBSTACLE)) move([...(random4()? [r] : []),notmydir, notdir+1, dir+1]); | |
else move(random4()? mydir : [mydir,r, notdir+1, dir+1]); // TODO | |
if (toReturn && toReturn.cell == (Pattern.hp == 4? dir+1 : Pattern.hp == 0? dir : -13.5) && random4()) toReturn = {cell:4}; | |
} else if (Pattern.hp == 4) move([r, notmydir, mydir, notmydir+1]); // no ur | |
else if (Pattern.hp == 0) move([r, notmydir, notmydir+1, mydir+1]); // no u | |
else move([r, notmydir, mydir, ...(food? [mydir+1] : []), notmydir+1]); | |
} | |
} | |
}); | |
if (isMiner) { | |
section(2, () => { | |
if (repair()) { | |
var hRel = (findRel(Ho)-rp)%3; | |
var dir = Pattern.vp > 0? d : u; | |
var notdir = Pattern.vp > 0? u : d; | |
if (hRel == 1) move([l, C]); // don't go past helper | |
else if (on(notdir+1, OBSTACLE) && !random4() && dir==mydir) move([r,notdir,notdir+1]); // if block downwards, continue moving here | |
else if (dir != mydir) { | |
move([mydir, mydir+1, mydir-1]); // TODO | |
} | |
else if (food) move([notmydir, r, notmydir+1]); | |
else if (Pattern.hp == 0) move(mydir); | |
else if (Pattern.hp == 4) move([notmydir,notmydir+1,notmydir-1]); | |
else move([notmydir,r,notmydir+1,notmydir-1]); | |
} | |
}); | |
section(3, () => { | |
if (repair()) move(food? [notmydir, notmydir+1, notmydir-1] : [mydir,notmydir+1]); | |
}, (pt) => () => { | |
var corrects = flatten(pt.raw).map((guess, index) => basedOn(pt.view[index], guess, true)); | |
var corrstr = corrects.map(c=>c?"#":" ").reduce((a,b)=>a+b); | |
var score = (pt.vp>0? /###....../ : /......###/).test(corrstr)? 20 : 0; | |
if (DEBUG && score > 0) console.log("scored", score, corrstr, flatten(pt.raw).map(c=>c.ant? "A"+c.ant.type : c), pt.vp); | |
return score; | |
}); | |
if (!found(Ho)) railPtt.select(0, 0, 3, 2).rots(D).map(c=>Pattern.add(c, () => { | |
var fol = on(l, Fo); // fool on left | |
if (!food && (fol || on(r, Fo))) { | |
Pattern.ref(Pattern.raw.map((ln, i) => [ln[0], foodExt[fol? i : 2-i], ln[2]]), () => { | |
if (repair()) move(fol? l : r); | |
}, undefined, Pattern.rot); | |
Pattern.action(); | |
} else if (repair()) { | |
if (food) move([notmydir, mydir]); | |
else move([mydir, notmydir]); | |
} | |
}, (pt) => () => { | |
var free = 0; | |
var T; // temp | |
var corrects = flatten(pt.raw).map((guess, index) => rcolOf(guess)==0? (free++,null) : (T=basedOn(pt.view[index], guess, true))===false? false : T*(rcolOf(guess)<0? (free++,0.1) : 1)); | |
var score = corrects.reduce(ADD)*9 / (9-free); | |
var corrstr = corrects.map(c=>c?"#":" ").reduce((a,b)=>a+b); | |
var DCorrect = /...######/.test(corrstr); | |
var UCorrect = /######.../.test(corrstr); | |
if ((mydir==u ^ food) && DCorrect) score = 15; | |
else if ((mydir==d ^ food) && UCorrect) score = 15; | |
else if (/#.##.##.#/.test(corrstr)) score=15; | |
else if (UCorrect || DCorrect) score = 6; | |
if (corrects.includes(0)) score = 0; // queen is in an unallowed place; abort all | |
if (DEBUG && score > 0) console.log("scored", score, "free", free, "corr", corrects.map(c=>+c), flatten(pt.pt).map(c=>c.ant? "A"+c.ant.type : c)); | |
return score; | |
})); | |
if (food) Pattern.add([foodExt, [0, 0, 0], [0, 0, 0]], ()=>move(u)); | |
} | |
Pattern.choose(); | |
var confident = (Pattern.confidence >= 1 && (Pattern.score > 4 || Pattern.corr >= 4)) || (Pattern.score >= 9 && Pattern.confidence > 0.05); | |
if (!confident) Pattern.action = () => { | |
if (!isQueen) { | |
if (!found(Qo) && found(Fo)) move(find(Fo)); | |
} | |
} | |
if (isMiner) { | |
if ((Pattern.corr > 3 || Pattern.score > 3) && confident) Pattern.action(); | |
} else if (isQueen) { | |
if ((Pattern.corr >= 6 || food > STARTINGFOOD+2 || friendCount>1) && confident) Pattern.action(); | |
else if (food >= STARTINGFOOD && friendCount == 1) { | |
Pattern.clear(); | |
Pattern.add([[1,{ant:Ho.ant,color:1},1], | |
[1,1,1], | |
[1,1,1]], ()=>spawn([ur,ul],Ht)); | |
Pattern.add([[1,1,{ant:Ho.ant,color:1}], | |
[1,1,1], | |
[1,1,1]], ()=>spawn([ur,u],Ht)); | |
Pattern.choose(); | |
if (repair()) Pattern.action(); | |
} else if (food == 0 && friendCount == 0) { // diagonal search | |
if (found(Fo)) { | |
move(find(Fo)); | |
} else { | |
Pattern.clear(); | |
Pattern.add([[WH,WH,WH], | |
[WH,C1,WH], | |
[C1,WH,WH]], ()=>move(ur)); | |
Pattern.add([[WH,WH,WH], | |
[WH,WH,WH], | |
[C1,WH,WH]], ()=>color(C, C1)); | |
Pattern.add([[WH,WH,WH],[WH,WH,WH],[WH,WH,WH]], ()=>color(DL, C1)); | |
Pattern.choose(); | |
if (Pattern.corr == 9) Pattern.action(); | |
else move(random4()? [DL,UL,DR,UL] : [D,L,U,R]); | |
} | |
} else if (food == 1 && friendCount == 0) spawn([U,L,D,R,UL,DL,UR,DR], Ht); | |
else if (friendCount == 1) lightSpeed(); | |
else { | |
Pattern.ref(railPtt.select(0,3,4,3).rotate(L).rotate(L)); | |
repair(); | |
} | |
} else if (type == Ht) { | |
if (Pattern.corr >= 5 || friendCount>1) Pattern.action(); | |
else if (found(Qo)) lightSpeed(); | |
else if (Pattern.corr >= 3 && confident) repair(); | |
} | |
function lightSpeed() { | |
var other = find(isQueen? Ho : Qo); | |
var orth = other%2; | |
if (isQueen || (view[other].ant.food < STARTINGFOOD && count(Ho) == 1)) { // LS | |
if (orth && found(Fo)) { // grab easy food | |
var fp = find(Fo); | |
if (sees(other, fp)) move(fp); | |
else { | |
Pattern.ref([[0,FRIEND,0], | |
[0,0,0], | |
[0,0,0]]); | |
move(l); | |
} | |
} | |
Pattern.clear(); | |
// Pattern.when(U,find(FRIEND), ()=>isQueen? move(ul) : move(ur)); when I'm not lazy imma make this a replacement of the below | |
Pattern.add([[0,FRIEND,0], | |
[0,0,0], | |
[0,0,0]], ()=>isQueen? move(ul) : move(ur)); | |
Pattern.add([[0,0,FRIEND], | |
[0,0,0], | |
[0,0,0]], ()=>move(u)); | |
Pattern.choose(); | |
Pattern.action(); | |
} | |
} | |
if (DEBUG) console.log(type, view.map(c=>c.ant? "A"+c.ant.type : c.color)); | |
if (toReturn) return toReturn; | |
else return {cell:4}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment