-
-
Save dzaima/3b0b3650faf9568202ad9b57d60ab4fe 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 = false; | |
//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; | |
//binary directions | |
const bUL = 3; const bU = 1; const bUR = 5; | |
const bL = 2; const bC = 0; const bR = 4; | |
const bDL = 10; const bD = 8; const bDR = 12; | |
const rp = 16; | |
const NOP = {cell:C}; | |
var toReturn = undefined; | |
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 -1 is ignore | |
const WH = 1; | |
const C1 = 6; // should stay green (or whatever is trail-eraser most ignorant of :p) | |
const C2 = 2; // yellow | |
const C3 = 3; // purple | |
const C4 = 4; // cyan | |
const C5 = 5; // red | |
const C6 = 8; // black | |
const C7 = 7; // blue | |
const TRAIL = C1; | |
const SETTINGUP = WH; | |
const DONE = C5; | |
const H1 = 1; | |
const H2 = 2; | |
const MINER = 3; | |
const QUEENOBJ = {ant:{friend:true,type:5}}; | |
const defRail = [[C1,C7,C3], | |
[C1,C6,C4], | |
[C7,C1,C3]]; | |
defRail.vp = 0; | |
defRail.hp = 0; | |
const railParts = translates(defRail, R); | |
const TRlambda = (side) => (rp, ctr) => translatePt(rp, side) | |
const rail = {or: | |
[ | |
...railParts, | |
...isQueen?[]:(railParts.map(TRlambda(U))), | |
...isQueen?[]:(railParts.map(TRlambda(D))) | |
].map(c => limitSize(c, 3, 3)) | |
}; | |
var foods; | |
var ref; | |
reference(rail); | |
// CODE | |
if (isQueen) { | |
var h1found = 1+find({ant:{type:H1}}); | |
var h2found = 1+find({ant:{type:H2}}); | |
if (!h2found && !h1found) { | |
if (food > 0) { | |
spawn(DL,H1); | |
} else { | |
diagonalSearch(C1); | |
} | |
} else if (h1found && !h2found) { | |
if (food <= 8) { | |
move(rotate1CW(h1found-1)); | |
} else { | |
if (repair()) { | |
spawn(l, H2); | |
} | |
} | |
} else if (h1found && h2found) { | |
spawn(random4(), MINER) | |
} | |
} else if (type == H1) { | |
if (find({ant:{type:H1}}) !== 1) { | |
move(rotate1CCW(find({ant:{type:5}}))); | |
} | |
} else if (type == H2) { | |
move(c); | |
} else if (type == MINER) { | |
move(U); // lazy | |
} | |
// END CODE | |
if (!toReturn) toReturn = NOP; | |
return toReturn; | |
//---------------------------------helper functions below--------------------------------- | |
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 color (where, color) { | |
if (where&rp) where = rawp(where); | |
if (get(where).color === color) return 1; | |
return result({cell:where, color:color}); | |
} | |
function move (where) { | |
if (Array.isArray(where)) { | |
return where.some(move /*is possible :p*/); | |
} | |
if (where&rp) where = rawp(where); | |
return result({cell:where}); | |
} | |
function spawn (where, what) { | |
if (Array.isArray(where)) { | |
return where.some(c => spawn(c, what)); | |
} | |
if (where&rp) where = rawp(where); | |
return result({cell:where, type:what}); | |
} | |
function repair (firstdirs) { | |
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)) { | |
let ccolor = defColor(shouldbe); | |
if (ccolor != ref.view[index]) { | |
if (!firstdirs || firstdirs.includes(index)) { | |
color(index|rp, ccolor); | |
return false; | |
} else possibilities.push({i:index|rp, c:ccolor}); | |
} | |
} | |
return true; | |
}); | |
if (repaired && possibilities.length > 0) { | |
repaired = false; | |
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 (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) { | |
if (Array.isArray(pattern.or)) { | |
var bestPattern = {dist:999, correct: -1}; | |
pattern.or.forEach((cOr) => { | |
let cres = match(cOr, givendir); | |
if (compareScores(cres.dist, cres.correct, bestPattern.dist, bestPattern.correct) > 0) { | |
bestPattern = cres; | |
} | |
}); | |
return bestPattern; | |
} | |
var bestRotation = 0; | |
var bestDist = 999; | |
var bestCorrect = -1; | |
if (Array.isArray(pattern)) { | |
let opattern = pattern; | |
pattern = [...pattern[0],...pattern[1],...pattern[2]]; | |
pattern.vp = opattern.vp; | |
pattern.hp = opattern.hp; | |
((givendir != undefined)? [allvs[givendir]] : allvs).forEach((cVRot, cRot) => { | |
if (givendir != undefined) cRot = givendir; | |
let dist = 0; | |
let correct = 0; | |
let fatalFail = false; | |
// 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 (eqt === 3) correct+=2; | |
if (eqt === 0) fatalFail = true; | |
if (eqt === true) correct++; | |
if (eqt === false) dist++; | |
return fatalFail; | |
}); | |
//log("distance",dist, "correct",correct); | |
if (!fatalFail && compareScores(dist, correct, bestDist, bestCorrect)>0) { | |
bestDist = dist; | |
bestCorrect = correct; | |
bestRotation = cRot; | |
} | |
}); | |
return {dist:bestDist, correct:bestCorrect, rot:bestRotation, pt:pattern, view:allvs[bestRotation], opt:opattern}; | |
} | |
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 = view.findIndex(c => cellsEq(c, obj)); | |
if (res === -1) return -1; | |
return res; | |
} | |
/* | |
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) { // log(full, new Error().stack); | |
if (typeof required === "number") { | |
if (required === -1) return 2; | |
if (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 (!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 && required.color !== full.color) return false; | |
if (required.food !== undefined && full.food !== required.food) return false; | |
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)); | |
out.hp = pattern.hp; | |
out.vp = pattern.vp; | |
return out; | |
} | |
function translates (pattern, direction) { | |
var ovp = pattern.vp; | |
var ohp = pattern.hp; | |
var out = [pattern.slice()]; | |
out[0].vp = ovp; | |
out[0].hp = ohp; | |
//if (direction & L || direction & R) { | |
// out[0].hp = 0; | |
// out[0].vp = ohp; | |
//} else { | |
// out[0].vp = 0; | |
// out[0].hp = ohp; | |
//} | |
for (let i = 0; i < lengthIn(pattern, direction)-1; i++) { | |
pattern = rotatePt(pattern, direction); | |
//if (direction & L || direction & R) { | |
// pattern.hp = i+1; | |
// pattern.vp = ohp; | |
//} else { | |
// pattern.vp = i+1; | |
// pattern.hp = ohp; | |
//} | |
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]])); | |
np.vp = pattern.vp; | |
np.hp = pattern.hp+1; | |
return np; | |
} | |
if (direction == D) { | |
let np = pattern.slice(1).concat([pattern[0]]); | |
np.vp = pattern.vp+1; | |
np.hp = pattern.hp; | |
return np; | |
} | |
if (direction == U) { | |
let np = pattern.slice(); | |
np.splice(0,0,...np.splice(np.length-1)); | |
np.vp = pattern.vp-1; | |
np.hp = pattern.hp; | |
return np; | |
} | |
ohno("rotatePt failed to do anything", arguments); | |
} | |
function translatePt (pattern, direction) { | |
if (direction == R) { | |
let np = pattern.map((ln) => ln.slice(1).concat(-1)); | |
np.hp = pattern.hp+1; | |
np.vp = pattern.vp; | |
return np; | |
} | |
if (direction == L) { | |
let np = pattern.map((ln) => [-1].concat(ln.slice(0,-1))); | |
np.hp = pattern.hp-1; | |
np.vp = pattern.vp; | |
return np; | |
} | |
if (direction == U) { | |
let np = [new Array(pattern[0].length).fill(-1)].concat(pattern.slice(0,-1)); | |
np.hp = pattern.hp; | |
np.vp = pattern.vp-1; | |
return np; | |
} | |
if (direction == D) { | |
let np = pattern.slice(1).concat([new Array(pattern[0].length).fill(-1)]); | |
np.hp = pattern.hp; | |
np.vp = pattern.vp+1; | |
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) { | |
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() { | |
var temptoReturn = toReturn; | |
toReturn = undefined; | |
if (result) { | |
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