// TODO: half-being in rail while shafting = shafting | |
const DEBUG = 0; | |
//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; | |
const NOP = {cell:C}; | |
var toReturn = undefined; | |
var foods; | |
var ref; | |
const me = view[C].ant; | |
const type = me.type; | |
const food = me.food; | |
const isQueen = type == 5; | |
const allvs = allRots(view); | |
const ixs = [0,1,2,3,4,5,6,7,8]; | |
const cols = ixs.map(a=>view[a].color); | |
const allcs = allRots(cols); | |
// color 0 is ignore | |
// negative colors are always matched as correct but need to be repaired | |
const COLORS = [1, 6, 2, 3, 4, 5, 8, 7]; | |
const WH = COLORS[0]; // 1 | |
const C1 = COLORS[1]; // 6/should stay green (or whatever is trail-eraser most ignorant of :p) | |
const C2 = COLORS[2]; // 2/yellow | |
const C3 = COLORS[3]; // 3/purple | |
const C4 = COLORS[4]; // 4/cyan | |
const C5 = COLORS[5]; // 5/red | |
const C6 = COLORS[6]; // 8/black | |
const C7 = COLORS[7]; // 7/blue | |
const TRAIL = C1; | |
const PatternKeep = ["vp", "hp", "p"]; | |
// spam `for (let cv of PatternKeep) pattern[cv] = opattern[cv];` everywhere | |
const QUEEN = {ant:{friend:true,type:5}}; | |
const MU = 1; | |
const MD = 2; | |
//const P = 3; | |
const mydir = type==MU? u : d; | |
const notmydir = type==MU? d : u; | |
var refScorer; | |
{ | |
let scoreTotal = 0; | |
let totalBiggestScore = 0; | |
let ptt; | |
let correct = 0; | |
let incorrect = 0; | |
let corrstr = ""; | |
let corr = []; | |
refScorer = { | |
new: () => {scoreTotal = 0; correct = 0; corrstr = ""; corr = []; incorrect = 0}, | |
add: (real, wanted, where, pattern) => { | |
ptt = pattern; | |
let eqt = cellsEq(real, wanted); | |
if (eqt && eqt!==2) correct++; | |
if (!eqt) incorrect++; | |
corrstr+= eqt?"#":" "; | |
corr.push(eqt); | |
}, | |
finish: (currBest) => { | |
if (incorrect == 0) scoreTotal+= 1e4; | |
if (ptt.p == 0 && ptt.vp ==-2) { if (/......###/.test(corrstr)) scoreTotal+= 10; else scoreTotal-= 1e300; } | |
if (ptt.p == 0 && ptt.vp == 2) { if (/###....../.test(corrstr)) scoreTotal+= 10; else scoreTotal-= 1e300; } | |
if (correct > 5) correct+= 3; | |
if (ptt.p==0&&ptt.vp!=0 && isQueen&&correct<5)scoreTotal=-1.5e308; | |
if (ptt.p==1) { | |
var upCorrect, downCorrect; | |
if (mydir==u || food) downCorrect = /...######/.test(corrstr); | |
if (mydir==d || food) upCorrect = /######.../.test(corrstr); | |
if ((mydir==u? upCorrect : downCorrect) && food) scoreTotal+= 1; | |
if (upCorrect || downCorrect) correct*=1.5; | |
else if (!view.some(c=>cellsEq(c,{ant:"enemy"}))) scoreTotal-= 20; | |
} | |
if (corr[4]) [[0,1,3],[1,2,5],[3,6,7],[5,7,8]].forEach(c=> { | |
if (c.every(i=>corr[i])) scoreTotal+= 3;// correct++; | |
}); | |
var fc = (what) => (["u","c","d"][(what-17)/3]) | |
log(`P[${ptt.p}@${ptt.hp} ${ptt.vp}] score = ${correct+scoreTotal/10}/${totalBiggestScore} [${corrstr}]`, ptt); | |
if (totalBiggestScore < correct+scoreTotal/10) totalBiggestScore = correct+scoreTotal/10; | |
return correct+scoreTotal/10; | |
} | |
}; | |
} | |
const rail = [[-1,-1,C5,-1], | |
[C4,-1,-1,-1], | |
[C1,C1,C3,C6], | |
[C4,C6,C1,C7], | |
[C2,C5,C2,C1], | |
[C4,-1,-1,-1], | |
[-1,-1,C5,-1]]; | |
rail.vp = -2; | |
rail.hp = 0; | |
rail.p = 0; | |
const shaft = [[WH,-1,C5], | |
[C4,-1,WH]]; | |
const foodExt = [C7,C3,C6]; | |
shaft.p = 1; | |
shaft.vp = 0; | |
shaft.hp = 0; | |
const pattern = {or:[]}; | |
const shifts = translates(rail, R); | |
function addPart(part) { | |
pattern.or.push(setSize(part, 3, 3)); | |
} | |
function section(line, forMe) { | |
if (!forMe) return []; | |
(Math.abs(line) == 2? [rail] : shifts).forEach(c=>{ | |
let res = c.slice(line+2); | |
for (let cv of PatternKeep) res[cv] = c[cv]; | |
res.vp = line; | |
addPart(res); | |
}); | |
} | |
section(-2, !isQueen); | |
section(-1, true); | |
section( 0, true); | |
section( 1, true); | |
section( 2, !isQueen); | |
if (!isQueen) { | |
var shafts = translates(shaft,U).map(c => setSize(c, 3, 3)); | |
var backFromFood = [foodExt,[0,0,0],[0,0,0]]; | |
backFromFood.p = 2; | |
if (food) addPart(backFromFood); | |
// if (mydir==u || food) shafts.forEach(c=>addPart(mapP(c,(ln,i)=>i==0? ln.map(col=>-Math.abs(col)) : ln))); | |
// if (mydir==d || food) shafts.forEach(c=>addPart(mapP(c,(ln,i)=>i==2? ln.map(col=>-Math.abs(col)) : ln))); | |
shafts.forEach(c=>addPart(c)); | |
} | |
log("new ant"); | |
log(view); | |
reference(pattern, undefined, refScorer); | |
const vp = ref.pt.vp; | |
const hp = ref.pt.hp; | |
const p = ref.pt.p; | |
//log("ant",type,"on rail at ", ref); | |
//log("vp", vp, "hp", hp); | |
//-----------------------------------------------------QUEEN------------------------------------------------------- | |
if (isQueen) { | |
if (food < 2 && ref.dist > 5) { | |
//initial food scramble | |
generateFoods(); | |
var sidevar = -1; | |
if ([0,2,6,8].some((i) => { | |
if (cols[i] === TRAIL) { | |
if (sidevar === -1) | |
sidevar = i; | |
else return true; | |
} | |
})) move(0); | |
else if (foods.includes(1)) { | |
move(foods.indexOf(1)); | |
} else if (cols[C] == TRAIL) { | |
if (sidevar == -1) { | |
move(0); | |
} else { | |
move(8-sidevar); | |
} | |
} else { | |
color(C, TRAIL); | |
} | |
//end food scramble | |
} else { | |
//on the rail | |
if (ref.dist == 1 && food < 100) spawnMiners(); | |
//if ((ref.dist == 1 && food < 100) || hp==1) spawnMiners(); | |
if ( | |
noop() | |
&& ( // otherwise | |
(ref.dist < 3 && get([l,ul,dl]).every(c=>c.ant && c.ant.friend) && !random4() && get([u,d,r,ur,dr]).every(c=>!c.ant)) // peer pressure | |
|| repair(random4()<2? [u,ur,ul,d,dr,dl] : [d,dr,dl,u,ur,ul]) // or everythings fine | |
)) { | |
if (vp !== 0) { if (vp > 0) move([u,ul,ur]); else move([d,dl,dr]); } | |
if (hp != 3 || get(ur).ant || get(dr).ant) { // move right if not on the place for staying still or ant(s) are prepared for mining | |
move(r); | |
} /*else if (food < 50) { | |
if (hp == 1 && !random4()) spawnMiners(); | |
}*/ | |
} | |
} | |
} else { | |
const movedir = food? notmydir : mydir; | |
const unmovedir = food? mydir : notmydir; | |
const REPAIRORDER = [c, r, mydir-1, l, notmydir-1, mydir, notmydir, mydir+1, notmydir+1]; | |
if (p == 0) { | |
const onmyside = vp == (mydir==u?-1:1); | |
const railside = vp<0?u:d; | |
const notrailside = vp<0?d:u; // move(notrailside) to move to center | |
if ((hp==0 && (vp == (mydir==u?-1:1)) && find(QUEEN) == notmydir) || repair(REPAIRORDER)) { | |
var fQ = find(QUEEN); | |
var queenvp = fQ? (((fQ-1)%3) + hp + 16)%4: -1; | |
if (food && vp == 0) move([r,mydir+1,notmydir+1]); | |
else if (hp==0 && onmyside && fQ == notmydir) {if (ref.dist == 0) move(mydir)} // go out to shaft! | |
else if (/*find({ant:"enemy"}) && */vp !== 0 && get([notrailside,notrailside-1,l]).every(c=>c.ant) && !obstacle(r) && !random4()) move(r); // peer pressure | |
//else if (!food && vp == 2 && mydir==u) move([ur,r]); | |
//else if (!food && vp ==-1 && mydir==u && cellsEq(get(dr),{ant:"queen"})) move(r); | |
//else if (!food && vp == 1 && mydir==d && cellsEq(get(ur),{ant:"queen"})) move(r); | |
//else if (!food && vp ==-2 && mydir==d) move([dr,r]); | |
else if (queenvp == 0 && !obstacle(r)) move(r); // move into place for shafting | |
else if (queenvp !=-1) move(c); // else don't move around queen | |
else if ((food || fQ != u) && vp == 1) move(mydir==d? [r, ur] : [ur, u]); // move forwards | |
else if ((food || fQ != d) && vp ==-1) move(mydir==u? [r, dr] : [dr, d]); | |
else if ((hp==0 && Math.abs(vp) > 1) || vp == 0) move([movedir, unmovedir]); // move more away from rail into the shaft | |
else if (vp==0) move([r, mydir+1, mydir, notmydir+1, notmydir]); // move forwards | |
else move(r); // TODO: I don't remember ¯\_(ツ)_/¯ | |
if (noop() && vp != 0) { | |
var enemyPos = find({ant:"enemy"}); | |
if (enemyPos && vp<0? enemyPos<=ur : enemyPos>=dl && !correct(enemyPos)) color(enemyPos, [C1,C2,C3,WH][random4()]); | |
} | |
} else { | |
if (!repair(REPAIRORDER)) { | |
if (vp !== 0 && get([notrailside,notrailside-1,l]).every(c=>c.ant) && !obstacle(r) && !random4()) move(r, true); // peer pressure | |
} | |
} | |
} else if (p == 1) { | |
if (get([l,r]).some(c=>c.food)) { | |
var foodL = get(l).food; | |
var shaftsn = shafts.map(c=>c.map((ln,i)=>[ln[0], foodL? foodExt[i] : foodExt[2-i], ln[2]])); | |
for (let cv of PatternKeep) shaftsn[cv] = shafts[cv]; | |
reference({or:shaftsn}, undefined, refScorer); | |
if (repair(REPAIRORDER)) { | |
move(foodL? l : r); | |
} | |
} | |
if ( | |
!( // if not any of the following: | |
(cellsEq(get(mydir), {ant:{type:type,friend:true,food:0}}) && get([mydir+1,mydir-1]).some(c=>c.food)) // someone's preparing to get food | |
|| | |
get([mydir+1,mydir-1]).some(c=>cellsEq(c,{ant:{type:type,friend:true,food:1}})) // someone got food! | |
|| | |
cellsEq(get(mydir), {ant:{type:type,friend:true,food:0}, color:[foodExt[0],foodExt[2]]}) //someone way above is getting food | |
) && repair(REPAIRORDER)) { // otherwise, if repaired | |
move([movedir,unmovedir]); // move to my side | |
} | |
} else if (p == 2) { | |
move(u); | |
} else { | |
ohno("no p for me.."); | |
} | |
} | |
function spawnMiners() { | |
if (view.filter(c=>c.ant).length>3) return false; // we have enough | |
var du = find({ant:{type:MU,friend:true}}); // do up / down | |
var dd = find({ant:{type:MD,friend:true}}); | |
if (du&&!dd) return spawn(dl,MD) || spawn(ul,MU); | |
if (dd&&!du) return spawn(ul,MU) || spawn(dl,MD); | |
if (random4()<2) return spawn(ul,MU) || spawn(dl,MD); | |
else return spawn(dl,MD) || spawn(ul,MU); | |
} | |
if (!toReturn) toReturn = NOP; | |
return toReturn; | |
//---------------------------------helper functions below--------------------------------- | |
function noop() { | |
return !toReturn || (toReturn.cell == 4 && !toReturn.color && !toReturn.type); | |
} | |
function mapP(pt,fn) { | |
var res = pt.slice().map(c=>c.slice()).map(fn); | |
for (let cv of PatternKeep) res[cv] = pt[cv]; | |
return res; | |
} | |
function diagonalSearch (cl) { | |
var colors = view.map(c=>c.color === cl); | |
if (!colors.includes(true)) return color(UL, cl); | |
const nc = [WH,C1,C2,C3,C4,C5,C6,C7].filter(c => c !== cl); | |
if (exactReference([[cl,nc,nc], | |
[nc,cl,nc], | |
[nc,nc,nc]])) return move(dr); | |
if (exactReference([[cl,nc,nc], | |
[nc,nc,nc], | |
[nc,nc,nc]])) return color(C, cl); | |
move(random4()? U : UL); | |
} | |
function generateFoods (useRef) { | |
if (!foods || useRef) | |
foods = ixs.map(a=>view[a].food); | |
if (useRef) { | |
foods = allRots(foods)[ref.rot]; | |
} | |
} | |
/* | |
false - ?? | |
true - gonna draw the color | |
1 - already colored | |
*/ | |
function obstacle (where) { | |
var got = get(where); | |
return got.ant || (type !== QUEEN && got.food); | |
} | |
/* | |
false - coloring in this move | |
0 - incorrect params?!?!!??! | |
true - already colored | |
*/ | |
function color (where, color) { | |
if (where&rp) where = rawp(where); | |
if (get(where).color === color) return true; | |
return result({cell:where, color:color})? false : 0; | |
} | |
function move (where, force) { | |
if (Array.isArray(where)) { | |
// :( return where.some(move /*is possible*/); | |
return where.some(c=>move(c,force) /*is possible*/); | |
} | |
if (where&rp) where = rawp(where); | |
return result({cell:where}, force); | |
} | |
function spawn (where, what, force) { | |
if (Array.isArray(where)) { | |
return where.some(c => spawn(c, what, force)); | |
} | |
if (where&rp) where = rawp(where); | |
return result({cell:where, type:what}, force); | |
} | |
/* | |
either colors the cell white or leaves it correctly colored. | |
Meant for making it as an okay thing to stay like that when moving around | |
false - coloring... | |
true - ready for moving to related! | |
*/ | |
function clear (cell) { | |
if (correct(cell)) return true; | |
else return color(cell, WH); | |
} | |
function correct (cell) { | |
cell = cell&~rp; | |
return cellsEq(ref.view[cell], ref.pt[cell]); | |
} | |
function fix (cell) { | |
cell&= ~rp; | |
let ccolor = defColor(ref.pt[cell]); | |
if (ccolor != ref.view[cell].color) { | |
color(cell|rp, ccolor); | |
return false; | |
} else return true; | |
} | |
function repair (firstdirs) {// firstdirs is lowercase | |
//if (ref.dist == 0) return true; | |
var possibilities = []; | |
var repaired = ref.pt.every((shouldbe, index) => {//return if every cell is correct | |
if (!cellsEq(ref.view[index], shouldbe, true)) { | |
let ccolor = Math.abs(defColor(shouldbe)); | |
if (ccolor != ref.view[index]) { | |
if (!firstdirs) { | |
color(index|rp, ccolor); | |
return false; | |
} else possibilities.push({i:index|rp, c:ccolor}); | |
} | |
} | |
return true; | |
}); | |
if (possibilities.length > 0) { | |
repaired = false; | |
var first = firstdirs.find(c=>possibilities.find(pc=>pc.i==c)); | |
if (first) color(first, possibilities.find(pc=>pc.i==first).c); | |
else color(possibilities[0].i, possibilities[0].c); | |
} | |
return repaired; | |
} | |
function defColor (cell) { | |
if (typeof cell === "number") return cell; | |
if (Array.isArray(cell)) return cell[0]; | |
ohno("defColor recieved bad param type ", cell); | |
} | |
function get (pos) { | |
if (Array.isArray(pos)) return pos.map(get); | |
if (pos&rp) return ref.view[pos^rp]; | |
else return view[pos]; | |
} | |
function gc (pos) { | |
return get(pos).color; | |
} | |
function exactReference (...args) { | |
var pt = match(...args); | |
if (pt.dist === 0) { | |
return ref = pt; | |
} | |
return false; | |
} | |
function reference (...args) { | |
return ref = match(...args); | |
} | |
/* | |
this function makes a pseudo-reference out of a value of a direction | |
For example, if you want a type-2 worker orthogonally to you to be able to be referenced as `r` (and of course the other directions are relative), do | |
define(r, find({ant:{type:2,friend:true}})) | |
*/ | |
function define (whichDir, whatCellItIs) { | |
var rot = [0,1,2,3].find(rot => rotate(whatCellItIs, -rot) === (whichDir&~rp)); | |
ref = {rot:rot, view:allvs[rot]}; | |
} | |
function match (pattern, givendir, scoreResults) { | |
if (Array.isArray(pattern.or)) { | |
var bestPattern = {dist:999, correct: -1, score: -1e308}; | |
pattern.or.forEach((cOr) => { | |
let cres = match(cOr, givendir, scoreResults); | |
if (scoreResults? cres.score > bestPattern.score : compareScores(cres.dist, cres.correct, bestPattern.dist, bestPattern.correct) > 0) { | |
bestPattern = cres; | |
} | |
}); | |
//console.log(bestPattern); | |
return bestPattern; | |
} | |
var bestRotation = 0; | |
var bestDist = 999; | |
var bestCorrect = -1; | |
var bestScore = -1e308; | |
if (Array.isArray(pattern)) { | |
let opattern = pattern; | |
pattern = [...pattern[0],...pattern[1],...pattern[2]]; | |
for (let cv of PatternKeep) pattern[cv] = opattern[cv]; | |
((givendir != undefined)? [allvs[givendir]] : allvs).forEach((cVRot, cRot) => { | |
if (givendir != undefined) cRot = givendir; | |
let dist = 0; | |
let correct = 0; | |
let fatalFail = false; | |
if (scoreResults) scoreResults.new(); | |
// log("match going trough", cVRot.map(c=>c.color), "at", pattern, pattern.hp); | |
cVRot.some((cVCell, cCell) => {//log(cCell, pattern) | |
let eqt = cellsEq(cVCell, pattern[cCell]); | |
if (scoreResults) scoreResults.add(cVCell, pattern[cCell], cCell, pattern); | |
else { | |
if (eqt === 3) correct+=2; | |
if (eqt === 0) fatalFail = true; | |
} | |
if (eqt === true) correct++; | |
if (eqt === false) dist++; | |
return fatalFail; | |
}); | |
//log("distance",dist, "correct",correct); | |
let score; | |
if (scoreResults? (score = scoreResults.finish(bestScore)) > bestScore : !fatalFail && compareScores(dist, correct, bestDist, bestCorrect)>0) { | |
bestDist = dist; | |
bestCorrect = correct; | |
bestRotation = cRot; | |
if (scoreResults) bestScore = score; | |
} | |
}); | |
return {dist:bestDist, correct:bestCorrect, rot:bestRotation, pt:pattern, view:allvs[bestRotation], opt:opattern, score:bestScore}; | |
} | |
ohno("match failed to do anything", pattern); | |
} | |
function compareScores (ad, ac, bd, bc) { | |
//scoring by percentage correct | |
let a = ac / (ad+ac+1); | |
let b = bc / (bd+bc+1); | |
//scoring by correct overhead | |
///let a = ac - ad | |
///let b = bc - bd | |
return a==b? 0 : ((a>b)? 1 : -1); | |
} | |
function bitify (num) { | |
num&=~rp; | |
if (num === U) return bU; | |
if (num === D) return bD; | |
if (num === L) return bL; | |
if (num === R) return bR; | |
if (num === UL) return bUL; | |
if (num === DL) return bDL; | |
if (num === UR) return bUR; | |
if (num === DR) return bDR; | |
} | |
function rawp (dir) { | |
dir &= ~rp; // remove rp 'flag' | |
return rotate(dir, ref.rot); | |
} | |
function refp (dir) { | |
return rp | rotate(dir, -ref.rot); | |
} | |
function rotate (torot, am) { | |
am = am%4; | |
if (am < 0) am+= 4; | |
for (let i = 0; i < am; i++) torot = [2,5,8, 1,4,7, 0,3,6][torot]; | |
return torot; | |
} | |
function find (obj) { | |
var res = ref.view.findIndex(c => cellsEq(c, obj)); | |
if (res === -1) return false; | |
return res | rp; | |
} | |
/* | |
0 - ant isn't how it should be | |
false - colors don't match | |
true - match | |
2 - match, but very easy to match, so shouldn't count | |
3 - matched ants | |
1st param - full object, aka anything that comes from view[x] | |
2nd param - the partical object you want it to equal (e.g. {ant:{friend:true}}; 6 ) | |
*/ | |
function cellsEq (full, required, negativeIncorrect) { // log(full, new Error().stack); | |
if (typeof required === "number") { | |
if (required === 0) return 2; | |
if (!negativeIncorrect && required < 0) return 2; | |
if (Math.abs(required) === full.color) return true; | |
return false; | |
} else if (Array.isArray(required)) { | |
let best = 0; | |
required.some((c) => { | |
let res = cellsEq(full, c); | |
if (res === false && best === 0) best = false; | |
if (res === true && best !== 3) best = true; | |
if (res === 3) best = 3; | |
}); | |
//log("cellsEq array",required,full,best); | |
return best; | |
} else if (typeof required === "object") { | |
if (required.ant==false && full.ant) return 0; | |
if (required.ant) { | |
if (required.ant==="notQueen") { | |
if (full.ant) { | |
if (full.ant.type==5 && full.ant.friend) return 0; | |
} | |
} else if (required.ant==="worker") { | |
if (full.ant) { | |
if (full.ant.type==5 && full.ant.friend) return 0; | |
} else return 0; | |
} else if (required.ant==="enemy") { | |
if (full.ant) { | |
if (full.ant.friend) return 0; | |
} else return 0; | |
} else if (required.ant==="queen") { | |
if (full.ant) { | |
if (full.ant.type!=5 && full.ant.friend) return 0; | |
} else return 0; | |
} else { | |
if (!full.ant) return 0; | |
else { | |
// ಠ_ಠ | |
if (required.ant.type && required.ant.type != full.ant.type) return 0; | |
if (required.ant.friend && required.ant.friend != full.ant.friend) return 0; | |
} | |
} | |
} | |
if (required.color) { | |
if (Array.isArray(required.color)) { | |
if (!required.color.some(c=>c===full.color)) return false; | |
} else if (required.color !== full.color) return false; | |
} | |
if (required.food !== undefined && full.food != required.food) return false; // intentional `!=` | |
if (required.ant) return 3; | |
return true; | |
} | |
ohno("cellsEq failed to do anything", arguments); | |
} | |
function limitSize (pattern, xs, ys) { | |
var out = pattern.slice(0, ys).map(c => c.slice(0,xs)); | |
for (let cv of PatternKeep) out[cv] = pattern[cv]; | |
return out; | |
} | |
function setSize (pattern, xs, ys) { | |
//var out = pattern.slice(0, ys).map(c => c.slice(0,xs)); | |
//while (out[0].length < xs) out.map(c => c.push()); | |
var out = []; | |
for (let y = 0; y < ys; y++) { | |
var ca = []; | |
for (let x = 0; x < xs; x++) { | |
ca.push(pattern[y % pattern.length][x % pattern[0].length]); | |
} | |
out.push(ca); | |
} | |
for (let cv of PatternKeep) out[cv] = pattern[cv]; | |
return out; | |
} | |
function translates (pattern, direction) { | |
var out = [pattern.slice()]; | |
for (let cv of PatternKeep) out[0][cv] = pattern[cv]; | |
for (let i = 0; i < lengthIn(pattern, direction)-1; i++) { | |
pattern = rotatePt(pattern, direction); | |
out.push(pattern); | |
} | |
return out; | |
} | |
function rotatePt (pattern, direction) { | |
if (direction == DR) { | |
return rotatePt(rotatePt(pattern, D), R); | |
} | |
if (direction == R) { | |
let np = pattern.map((c, ln) => c.slice(1).concat([c[0]])); | |
for (let cv of PatternKeep) np[cv] = pattern[cv]; | |
np.hp++; | |
return np; | |
} | |
if (direction == D) { | |
let np = pattern.slice(1).concat([pattern[0]]); | |
for (let cv of PatternKeep) np[cv] = pattern[cv]; | |
np.v++; | |
return np; | |
} | |
if (direction == U) { | |
let np = pattern.slice(); | |
np.splice(0,0,...np.splice(np.length-1)); | |
for (let cv of PatternKeep) np[cv] = pattern[cv]; | |
np.vp--; | |
return np; | |
} | |
ohno("rotatePt failed to do anything", arguments); | |
} | |
function translatePt (pattern, direction) { | |
direction&=~rp; | |
if (direction == R) { | |
let np = pattern.map((ln) => ln.slice(1).concat(-1)); | |
for (let cv of PatternKeep) np[cv] = pattern[cv]; | |
np.hp++; | |
return np; | |
} | |
if (direction == L) { | |
let np = pattern.map((ln) => [-1].concat(ln.slice(0,-1))); | |
for (let cv of PatternKeep) np[cv] = pattern[cv]; | |
np.hp--; | |
return np; | |
} | |
if (direction == U) { | |
let np = [new Array(pattern[0].length).fill(-1)].concat(pattern.slice(0,-1)); | |
for (let cv of PatternKeep) np[cv] = pattern[cv]; | |
np.vp--; | |
return np; | |
} | |
if (direction == D) { | |
let np = pattern.slice(1).concat([new Array(pattern[0].length).fill(-1)]); | |
for (let cv of PatternKeep) np[cv] = pattern[cv]; | |
np.vp++; | |
return np; | |
} | |
ohno("translatePt failed to do anything", arguments); | |
} | |
function lengthIn (pattern, direction) { | |
if (direction == U || direction == D) return pattern.length; | |
if (direction == L || direction == R) return pattern[0].length; | |
ohno("lengthIn failed to do anything", arguments); | |
} | |
function ohno (msg) { | |
log(new Error()); | |
log("FAILURE"); | |
log(...arguments); | |
if (DEBUG) throw msg; | |
else toReturn = NOP; | |
} | |
function log() { | |
if (DEBUG) console.log(...arguments); | |
} | |
//---------------------------------functions from Rail Miners--------------------------------- | |
function result (action, force) { | |
if (force) return resultForce(action); | |
if (toReturn !== undefined) return 0; | |
var color = action.color; | |
var type = action.type; | |
var cell = action.cell; | |
if (!(cell >= 0 && cell <= 8)) return false; | |
if (!color && ((view[cell].ant && cell != 4) || (isQueen? (view[cell].food && type) : (food && view[cell].food)))) return false; | |
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; | |
} | |
function resultForce(action) { | |
var temptoReturn = toReturn; | |
toReturn = undefined; | |
if (result(action)) { | |
return true; | |
} else { | |
toReturn = temptoReturn; | |
return false; | |
} | |
} | |
function random4 () { | |
var scores = allcs.map((cs) => { | |
let cscore = 0; | |
cs.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 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 rotate1CW (c) { | |
return [1, 2, 5, 0, undefined, 8, 3, 6, 7][c]; | |
} | |
function rotate1CCW (c) { | |
return [3, 0, 1, 6, undefined, 2, 7, 8, 5][c]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment