Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // FORMIC FRAMEWORK //
- // Version 6.1.10 //
- const WHITE = 1;
- const QUEEN = 5;
- const CENTER = 4;
- const HERE = view[CENTER];
- const ME = HERE.ant;
- const ORTHOGONALS = [1, 3, 5, 7];
- const DIAGONALS = [0, 2, 6, 8];
- const DIAGONALS_ORTHOGONALS = [0, 2, 6, 8, 1, 3, 5, 7];
- const DIRECTIONS = [0, 1, 2, 3, 5, 6, 7, 8];
- const CLOCKWISE_DIRECTIONS = [0, 1, 2, 5, 8, 7, 6, 3];
- const CELLS = [0, 1, 2, 3, 4, 5, 6, 7, 8];
- const ROTATIONS = [
- [0, 1, 2,
- 3, 4, 5,
- 6, 7, 8],
- [6, 3, 0,
- 7, 4, 1,
- 8, 5, 2],
- [8, 7, 6,
- 5, 4, 3,
- 2, 1, 0],
- [2, 5, 8,
- 1, 4, 7,
- 0, 3, 6]
- ];
- const NEIGHBORS = [
- [1, 4, 3],
- [2, 5, 4, 3, 0],
- [5, 4, 1],
- [0, 1, 4, 7, 6],
- [0, 1, 2, 5, 8, 7, 6, 3],
- [8, 7, 4, 1, 2],
- [3, 4, 7],
- [6, 3, 4, 5, 8],
- [7, 4, 5]
- ];
- const HORIZONTAL_FLIP = [2, 1, 0, 5, 4, 3, 8, 7, 6];
- const VERTICAL_FLIP = [6, 7, 8, 3, 4, 5, 0, 1, 2];
- const DEBUG_MODE = true;
- function dump() {
- if (DEBUG_MODE) {
- throw "dump() not implemented";
- }
- }
- function log(...args) {
- if (DEBUG_MODE) {
- console.log(...args);
- }
- }
- function error(...args) {
- log("Transformed view state:", view);
- log(...args);
- throw "A critical error has occurred!";
- }
- function createArray(func, length) {
- const arr = [];
- for (let i = 0; i < length; i++) {
- arr.push(func(i, arr));
- }
- return arr;
- }
- class Test {
- run(cell) {
- error("No run method defined for this instance of Test:", this);
- }
- find(cells = CELLS) {
- return cells.find((c) => this.run(c));
- }
- findIndex(cells = CELLS) {
- return cells.findIndex((c) => this.run(c));
- }
- filter(cells = CELLS) {
- return cells.filter((c) => this.run(c));
- }
- every(cells = CELLS) {
- return cells.every((c) => this.run(c));
- }
- some(cells = CELLS) {
- return cells.some((c) => this.run(c));
- }
- count(cells = CELLS) {
- return this.filter(cells).length;
- }
- invert() {
- return new InverseTest(this);
- }
- and(test) {
- return new EveryTest(this, test);
- }
- or(test) {
- return new SomeTest(this, test);
- }
- }
- class InverseTest extends Test {
- constructor(test) {
- super();
- this.test = test;
- }
- run(cell) {
- return !this.test.run(cell);
- }
- invert() {
- return this.test;
- }
- }
- class CombinedTest extends Test {
- constructor(...tests) {
- super();
- this.tests = tests;
- }
- append(test) {
- this.tests.push(test);
- return this;
- }
- }
- class EveryTest extends CombinedTest {
- run(cell) {
- return this.tests.every((test) => test.run(cell));
- }
- and(test) {
- return this.append(test);
- }
- }
- class SomeTest extends CombinedTest {
- run(cell) {
- return this.tests.some((test) => test.run(cell));
- }
- or(test) {
- return this.append(test);
- }
- }
- class ColorTest extends Test {
- constructor(color) {
- super();
- this.color = color;
- }
- run(cell) {
- return view[cell].color === this.color;
- }
- }
- class ColorBandTest extends SomeTest {
- constructor(colorBand) {
- super(...colorBand.map((color) => new ColorTest(color)));
- }
- }
- class FoodTest extends Test {
- constructor(hasFood = true) {
- super();
- this.food = hasFood ? 1 : 0;
- }
- run(cell) {
- return view[cell].food === this.food;
- }
- }
- class AntTest extends Test {
- constructor(friend, type, food) {
- super();
- this.friend = friend;
- this.type = type;
- this.food = food;
- }
- run(cell) {
- const ant = view[cell].ant;
- return ant !== null && (this.type === undefined || ant.type === this.type) && (this.friend === undefined || ant.friend === this.friend) && (this.food === undefined || (this.food ? ant.food > 0 : ant.food === 0));
- }
- }
- class NeighborTest extends Test {
- constructor(test) {
- super();
- this.test = test;
- }
- run(cell) {
- return this.test.some(NEIGHBORS[cell]);
- }
- }
- class MatchTest extends Test {
- constructor(matches) {
- super();
- this.matches = matches;
- }
- run(cell) {
- return this.matches[cell];
- }
- }
- class CustomTest extends Test {
- constructor(func, ...args) {
- super();
- this.func = func;
- this.args = args;
- }
- run(cell) {
- return this.func(cell, ...this.args);
- }
- }
- class Action {
- constructor(cell, test) {
- this.cell = cell;
- this.test = test;
- }
- valid() {
- return this.cell >= 0 && this.cell < 9 && (!this.test || this.test.run(this.cell));
- }
- attempt() {
- return this.valid() ? this : null;
- }
- static tryAll(...actions) {
- return actions.find((action) => action instanceof this && action.valid()) || null;
- }
- }
- class Move extends Action {
- constructor(cell, test) {
- super(cell, test);
- }
- valid() {
- return super.valid() && view[this.cell].ant === null && (view[this.cell].food === 0 || ME.food === 0 || ME.type === QUEEN);
- }
- static many(cells, test) {
- return cells.map((cell) => new this(cell, test));
- }
- }
- class Paint extends Action {
- constructor(cell, color, test) {
- super(cell, test);
- this.color = color;
- }
- valid() {
- return super.valid() && view[this.cell].color !== this.color && this.color >= 1 && this.color <= 8;
- }
- static many(cells, colors, test) {
- return cells.map((cell, i) => new this(cell, colors[i % colors.length], test));
- }
- }
- class Spawn extends Action {
- constructor(cell, type, test) {
- super(cell, test);
- this.type = type;
- }
- valid() {
- return super.valid() && view[this.cell].ant === null && view[this.cell].food === 0 && ME.food > 0 && ME.type === QUEEN && this.type >= 1 && this.type <= 4;
- }
- static many(cells, type, test) {
- return cells.map((cell, i) => new this(cell, type, test));
- }
- }
- class NOP extends Action {
- constructor() {
- super(CENTER);
- }
- valid() {
- return true;
- }
- }
- class Context {
- apply(func, ...args) {
- const hiddenView = view;
- if (this.viewTranslator) {
- view = this.viewTranslator(hiddenView);
- }
- let output = func(...args);
- if (output instanceof Action && this.outputTranslator) {
- this.outputTranslator(output);
- }
- view = hiddenView;
- return output;
- }
- }
- class TranslationContext extends Context {
- constructor(translationArray) {
- super();
- this.translationArray = translationArray;
- }
- viewTranslator(oldView) {
- const newView = [];
- for (let i = 0; i < 9; i++) {
- newView.push(oldView[this.translationArray[i]]);
- }
- return newView;
- }
- outputTranslator(out) {
- out.cell = this.translationArray[out.cell];
- }
- }
- class RotationContext extends TranslationContext {
- constructor(orientation) {
- super(ROTATIONS[orientation]);
- this.orientation = orientation;
- }
- }
- class OffsetContext extends TranslationContext {
- constructor(centerCell) {
- throw "OffsetContext not implemented";
- }
- }
- class HorizontalReflectionContext extends TranslationContext {
- constructor() {
- super(HORIZONTAL_FLIP);
- }
- }
- class VerticalReflectionContext extends TranslationContext {
- constructor() {
- super(VERTICAL_FLIP);
- }
- }
- class ColorMapContext extends Context {
- constructor(map, unmap) {
- super();
- this.map = map;
- this.unmap = unmap;
- }
- viewTranslator(oldView) {
- return oldView.map((cell) => ({color: this.map[cell.color - 1], food: cell.food, ant: cell.ant}));
- }
- outputTranslator(out) {
- out.color = this.unmap[out.color - 1];
- }
- }
- class XY {
- constructor(x = 0, y = 0) {
- this.x = x;
- this.y = y;
- }
- static fromTuples(...xyTuples) {
- return xyTuples.map((xy) => new this(xy[0], xy[1]));
- }
- }
- class WrapProperties {
- constructor(horizontal, vertical, size, wrapOffsets) {
- this.horizontal = !!horizontal;
- this.vertical = !!vertical;
- this.size = size;
- this.wrapOffsets = wrapOffsets || {};
- }
- }
- class ScoredTest {
- constructor(test, score = 1) {
- this.test = test;
- this.score = score;
- }
- run(cell) {
- return this.test.run(cell) ? this.score : 0;
- }
- }
- class Environment {
- constructor(tests, wrapping) {
- this.tests = tests.map((test) => test instanceof Test ? new ScoredTest(test) : test);
- this.wrapping = wrapping;
- }
- at(x, y) {
- const w = this.wrapping;
- while ((w.horizontal && (x < 0 || x >= w.size.x)) || (w.vertical && (y < 0 || y >= w.size.y))) {
- if (w.horizontal) {
- if (x < 0) {
- x += w.size.x;
- y += w.wrapOffsets.left || 0;
- } else if (x >= w.size.x) {
- x -= w.size.x;
- y += w.wrapOffsets.right || 0;
- }
- }
- if (w.vertical) {
- if (y < 0) {
- y += w.size.y;
- x += w.wrapOffsets.up || 0;
- } else if (y >= w.size.y) {
- y -= w.size.y;
- x += w.wrapOffsets.down || 0;
- }
- }
- }
- if ((!w.horizontal || (x >= 0 && x < w.size.x)) && (!w.vertical || (y >= 0 || y < w.size.y))) {
- return this.tests[x + y * w.size.x];
- } else {
- return null;
- }
- }
- around(x, y) {
- const arr = [];
- for (let oy = -1; oy <= 1; oy++) {
- for (let ox = -1; ox <= 1; ox++) {
- arr.push(this.at(x + ox, y + oy));
- }
- }
- return arr;
- }
- detect(...positions) {
- return createArray((i) => new RotationContext(i), 4).reduce((best, context) => {
- const next = context.apply(() => {
- return positions.reduce((best, pos, i) => {
- let score = 0;
- const matches = this.around(pos.x, pos.y).map((test, i) => {
- if (test && (test.test instanceof Test)) {
- const result = test.run(i);
- if (result) {
- score += result;
- return true;
- } else {
- return false;
- }
- } else {
- return null;
- }
- });
- if (score > best.score) {
- return {position: pos, positionIndex: i, orientation: context.orientation, environment: this, matches: matches, score: score, confidence: score - best.score};
- } else {
- best.confidence = Math.min(best.score - score, best.confidence);
- return best;
- }
- }, {position: positions[0], positionIndex: 0, orientation: 0, environment: this, matches: [], score: 0, confidence: 0});
- });
- if (next.score > best.score) {
- next.confidence = next.score - best.score;
- return next;
- } else {
- best.confidence = Math.min(best.score - next.score, best.confidence);
- return best;
- }
- }, {position: positions[0], positionIndex: 0, orientation: 0, environment: this, matches: [], score: 0, confidence: 0});
- }
- static chooseBest(...detectionResults) {
- const r = detectionResults.reduce((best, result, i) => {
- if (result.score > best.score) {
- result.index = i;
- result.confidence = result.score - best.score;
- return result;
- } else {
- best.confidence = Math.min(best.score - result.score, best.confidence);
- return best;
- }
- });
- r.index = r.index || 0;
- return r;
- }
- }
- class ColoredEnvironment extends Environment {
- constructor(colors, wrapping) {
- super(colors.map((color) => new ColorTest(color)), wrapping);
- }
- getPainter(detectionResult) {
- return new (class Painter {
- constructor(loc) {
- this.pos = loc.position;
- this.matches = loc.matches;
- this.colors = loc.environment.around(this.pos.x, this.pos.y).map((test) => test && test.test instanceof ColorTest ? test.test.color : null);
- this.test = new MatchTest(loc.matches).invert();
- this.orient = loc.orientation;
- }
- paint(...cells) {
- return cells.map((cell) => new Paint(cell, this.colors[cell], this.test));
- }
- cleanup(eraseColor, eraseTargets, ...cells) {
- const eraseQual = this.test.and(new ColorBandTest(eraseTargets));
- return cells.map((cell) => new Paint(cell, eraseColor, eraseQual));
- }
- })(detectionResult);
- }
- }
- // HIGH-LEVEL LOGIC STARTS HERE //
- const COLOR_BAND = [4, 7, 3, 2, 8];
- const PARTNER = 2;
- const WORKER = 1;
- const START_FOOD = 6;
- const MIN_CONFIDENCE = 2;
- const PATTERN = new ColoredEnvironment(COLOR_BAND, new WrapProperties(true, true, new XY(COLOR_BAND.length, 1), {up: 2, down: -2})).detect(...createArray((i) => new XY(i, 0), COLOR_BAND.length));
- function shouldSpawn() {
- return PATTERN.orientation === 0 && PATTERN.positionIndex % 3 === 0 && (ME.food < 50 || PATTERN.positionIndex === 0) && ME.food < 400;
- }
- function lightspeed() {
- // TODO: Do a 180 when 3 workers are in front of us
- function logicOrthogonal(frontC, sideC, backC, backCells, moveCells) {
- const a = [frontC, sideC, backC, backCells, moveCells];
- const f = new FoodTest;
- return Action.tryAll(
- ...Move.many([frontC, sideC], f),
- f.some(backCells) ? new Move(backC) : null,
- ...Move.many(moveCells),
- new NOP
- );
- }
- function logicDiagonal(adjacentC) {
- return Action.tryAll(...Move.many(adjacentC), new NOP);
- }
- function logic(partnerTest, partnerOrthC, partnerDiagC, frontC, sideC, backC, backCells, moveCells, adjacentC) {
- function detectEnv(c) {
- return new Environment(createArray((i) => i === c ? partnerTest : undefined, 9), new WrapProperties(false, false, new XY(3, 3), null)).detect(new XY(1, 1));
- }
- const orth = detectEnv(partnerOrthC);
- const diag = detectEnv(partnerDiagC);
- return orth.score === 1 ? new RotationContext(orth.orientation).apply(() => logicOrthogonal(frontC, sideC, backC, backCells, moveCells)) :
- diag.score === 1 ? new RotationContext(diag.orientation).apply(() => logicDiagonal(adjacentC)) :
- error("How did we get here?");
- }
- if (ME.type === QUEEN) {
- const partner = new AntTest(true, PARTNER);
- if (partner.some(DIRECTIONS)) {
- return logic(partner, 5, 8, 2, 1, 7, [0, 3, 6, 7], [2, 7, 1, 8], [5, 7]);
- } else {
- const COLOR = 5;
- const bgTest = new ColorTest(WHITE);
- if (bgTest.run(CENTER)) {
- return new Paint(CENTER, COLOR).attempt() || error("Something went terribly wrong while painting own cell");
- }
- const food = new FoodTest().find(DIRECTIONS);
- if (food !== undefined) {
- return new Move(food);
- }
- const det = new ColoredEnvironment([
- WHITE, WHITE, WHITE,
- WHITE, undefined, undefined,
- WHITE, undefined, COLOR
- ], new WrapProperties(false, false, new XY(3, 3))).detect(new XY(1, 1));
- return (ME.food > 0 ? Action.tryAll(...Spawn.many(ORTHOGONALS, PARTNER)) : null) ||
- (det.score === 6 ? new RotationContext(det.orientation).apply(() => Action.tryAll(...Move.many([0, 2, 6, 1, 3, 5, 7, 8]))) : null) ||
- Action.tryAll(...Move.many(DIAGONALS_ORTHOGONALS), new NOP);
- }
- } else {
- return logic(new AntTest(true, QUEEN), 1, 0, 2, 5, 3, [8, 7, 6, 3], [2, 3, 5, 0], [1, 3]);
- }
- }
- function queen() {
- if (PATTERN.confidence < MIN_CONFIDENCE && ME.food < START_FOOD) return lightspeed();
- return new RotationContext(PATTERN.orientation).apply(() => {
- const partnerCell = new AntTest(true, PARTNER).find(DIRECTIONS);
- const p = PATTERN.environment.getPainter(PATTERN);
- const e = new AntTest(false);
- const enemy = e.some(DIRECTIONS);
- return Action.tryAll(
- ...!PATTERN.matches[8] ? [
- ...!enemy ? [...p.paint(6, 7, 3, 4, 5, 0, 1, 2), ...shouldSpawn() ? Spawn.many([0, 2], WORKER) : []] : [],
- ...partnerCell === 1 ? Move.many(e.run(5) ? [0, 2] : [5, 2]) :
- partnerCell === 0 ? Move.many(e.run(1) ? [3] : e.run(2) ? [1, 3] : []) :
- []
- ] : [
- ...!enemy ? p.paint(8, 7, 6, 5, 4, 3, 2, 1, 0) : [],
- ...Move.many(partnerCell === 1 ? [2, 0] : partnerCell === 0 ? [1, 3] : [])
- ],
- new NOP
- )
- });
- }
- function partner() {
- const queenTest = new AntTest(true, QUEEN)
- const queenCell = queenTest.find(DIRECTIONS);
- if (queenCell === undefined) {
- return new NOP; // TODO: What do we do if we've lost our queen?
- }
- if (PATTERN.confidence < MIN_CONFIDENCE && view[queenCell].ant.food < START_FOOD) return lightspeed();
- return PATTERN.confidence >= MIN_CONFIDENCE ? new RotationContext(PATTERN.orientation).apply(() => {
- const queenCell = queenTest.find(DIRECTIONS);
- const e = new AntTest(false);
- const enemy = e.some(DIRECTIONS);
- return Action.tryAll(
- ...!enemy ? PATTERN.environment.getPainter(PATTERN).paint(...CELLS) : [],
- ...Move.many([
- [1],
- [0, 2],
- [1],
- [0, 1],
- [], // Queen can't be on cell 4 - I'm here, after all!
- [2, 1],
- [3],
- [],
- [5]
- ][queenCell]),
- new NOP
- )
- }) : new NOP;
- }
- function worker() {
- const m = new MatchTest(PATTERN.matches);
- const n = m.invert();
- const u = new AntTest(true, WORKER, false);
- const l = new AntTest(true, WORKER, true);
- const q = new AntTest(true, QUEEN);
- const pt = new AntTest(true, PARTNER);
- const p = PATTERN.environment.getPainter(PATTERN);
- return new RotationContext(PATTERN.orientation).apply(() => { // TODO: Unique (random?) behavior when confidence low
- if (ME.food === 0) {
- const f = new FoodTest();
- const count = n.count([6, 7, 8]);
- return Action.tryAll(
- ...p.paint(4, 0, 1, 2),
- //...p.cleanup(WHITE, COLOR_BAND, ...CELLS),
- ...((food) => food !== undefined ? [...p.paint(...NEIGHBORS[food], food), new Move(food)] : [])(f.find(DIRECTIONS)),
- ...q.or(pt).some(DIRECTIONS) || u.some([6, 7, 8, 5, 2]) ? Move.many([0, 1, 3], m) : [],
- ...count > 1 ? p.paint(...[6, 7, 8]) : [],
- ...count === 1 ? [...p.paint(...[3, 5]), ...Move.many([7, 6, 3, 8], m)] : [],
- /*n.run(6) ? new Move(3, m) : null,
- ...n.run(7) ? Move.many([6, 3], m) : [],
- n.run(8) ? new Move(7, m) : null,*/
- n.run(5) ? new Move(5) : null,
- ...Move.many([2, 1, 0, 3], m),
- new NOP
- /*
- ...(PATTERN.confidence >= 2 ? [...(PATTERN.score < 8 || new AntTest(false).some(DIRECTIONS) ? p.paint(4, 3, 0, 1, 2, 5) : []), ...p.cleanup(WHITE, COLOR_BAND, ...CELLS)] : []),
- ...((food) => food !== undefined ? [...p.paint(...NEIGHBORS[food]), new Move(food)] : [])(f.find(DIRECTIONS)), ...(
- w ? Move.many([1, 0, 2]) :
- m.some([4, 3]) ? p.paint(4, 3) :
- m.some([0, 1, 2]) ? Move.many([1, 5]) :
- m.run(6) ? [new Move(3)] :
- m.run(7) ? Move.many([6, 3]) :
- m.run(8) ? [new Move(7)] :
- m.run(5) ? Move.many([5, 7]) :
- Move.many([2, 1, 5])
- )
- new NOP*/
- );
- } else {
- return Action.tryAll(
- //...Move.many(new AntTest(true, WORKER).some([2, 5, 8, 7]) || PATTERN.score < 9 ? [8, 7, 6, 3] : [5, 8, 2], m.invert()),
- ...((test) => createArray((i) => new Move(CLOCKWISE_DIRECTIONS[(6 - i) % 8], test), 5))(new CustomTest((cell, moveTest, blockTest) => {
- const i = CLOCKWISE_DIRECTIONS.findIndex((c) => c === cell);
- return moveTest.run(CLOCKWISE_DIRECTIONS[i]) && blockTest.run(CLOCKWISE_DIRECTIONS[((i - 1) + 8) % 8]);
- }, m, n.or(new AntTest().and(l.invert())))),
- ...Move.many([2, 5, 1, 8], m),
- //...Move.many([...(PATTERN.score === 9 && !new AntTest(true, WORKER).some(DIRECTIONS) ? [2] : []), 5, 8, 7, 6, 3], m),
- new NOP
- );
- }
- });
- }
- switch (ME.type) {
- case QUEEN: {
- return queen();
- }
- case PARTNER: {
- return partner();
- }
- case WORKER: {
- return worker();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment