var canvas; const WAITING = 0; const RUNNING = 1; const REVIEWING = 2; const TESTING = 3; const FINISH = 4; const PAUSED = 5; const UP = 0; const RIGHT = 1; const DOWN = 2; const LEFT = 3; const RED = "R"; const BLUE = "B"; const GREEN = "G"; const YELLOW = "Y"; const PURPLE = "P"; const PINK = "p"; const BLACK = "b"; const GRAY = "g"; const ALIVE = 0; const DEAD = 1; const DONE = 2; var BOT_X = -1 var BOT_Y = -1 var BOT_DIR = RIGHT var BOT_STATE = ALIVE var BOT_TAPE = "RB" var BOT_QUEUE = [] var DELETEMODE = false var DRAGGING = false var DRAG_X = -1 var DRAG_Y = -1 var BOT_PREVX = BOT_X var BOT_PREVY = BOT_Y var MOBILE = false var BELTDOWN = {type:"BELT",direction:DOWN/*,direction2 - defines a secondary direction. For two belts at once.*/} var BELTRIGHT = {type:"BELT",direction:RIGHT} var BELTUP = {type:"BELT",direction:UP} var BELTLEFT = {type:"BELT",direction:LEFT} var BRANCHDOWN = {type:"BRANCH",direction:DOWN,color1:RED,color2:BLUE} //color 1 points clockwise(right), color 2 points counter-clockwise(left) var BRANCHLEFT = {type:"BRANCH",direction:LEFT,color1:RED,color2:BLUE} var BRANCHRIGHT = {type:"BRANCH",direction:RIGHT,color1:RED,color2:BLUE} var BRANCHUP = {type:"BRANCH",direction:UP,color1:RED,color2:BLUE} var WRITERDOWN = {type:"WRITER",direction:DOWN,color1:RED/*overwrite - if turned on, the writer overwrites the current tape position instead of appending.*/} var WRITERLEFT = {type:"WRITER",direction:LEFT,color1:RED} var WRITERRIGHT = {type:"WRITER",direction:RIGHT,color1:RED} var WRITERUP = {type:"WRITER",direction:UP,color1:RED} var DEF_BRANCHUP_RB = {img:IMAGE_BRANCH,color1:RED,color2:BLUE,type:"BRANCH"} var DEF_BRANCHUP_BR = {img:IMAGE_BRANCH,color1:BLUE,color2:RED,type:"BRANCH"} var DEF_BRANCHUP_GY = {img:IMAGE_BRANCH,color1:GREEN,color2:YELLOW,type:"BRANCH"} var DEF_BRANCHUP_YG = {img:IMAGE_BRANCH,color1:YELLOW,color2:GREEN,type:"BRANCH"} var DEF_BRANCHUP_PPI = {img:IMAGE_BRANCH,color1:PURPLE,color2:PINK,type:"BRANCH"} var DEF_BRANCHUP_PIP = {img:IMAGE_BRANCH,color1:PINK,color2:PURPLE,type:"BRANCH"} var DEF_BRANCHUP_BLGR = {img:IMAGE_BRANCH,color1:BLACK,color2:GRAY,type:"BRANCH"} var DEF_BRANCHUP_GRBL = {img:IMAGE_BRANCH,color1:GRAY,color2:BLACK,type:"BRANCH"} var DEF_WRITERRIGHT_R = {img:IMAGE_WRITER,color1:RED,type:"WRITER"} var DEF_WRITERRIGHT_B = {img:IMAGE_WRITER,color1:BLUE,type:"WRITER"} var DEF_WRITERRIGHT_G = {img:IMAGE_WRITER,color1:GREEN,type:"WRITER"} var DEF_WRITERRIGHT_Y = {img:IMAGE_WRITER,color1:YELLOW,type:"WRITER"} var DEF_WRITERRIGHT_P = {img:IMAGE_WRITER,color1:PURPLE,type:"WRITER"} var DEF_WRITERRIGHT_PI = {img:IMAGE_WRITER,color1:PINK,type:"WRITER"} var DEF_WRITERRIGHT_BL = {img:IMAGE_WRITER,color1:BLACK,type:"WRITER"} var DEF_WRITERRIGHT_GR = {img:IMAGE_WRITER,color1:GRAY,type:"WRITER"} var DEF_CONVEYOR = {img:IMAGE_CONVEYOR,type:"BELT"} var GRID_W = 32 var GRID_H = 32 var GRID_X = 20 var GRID_Y = 20 var LAST_MOUSE_X=0; var LAST_MOUSE_Y=0; var ITEM_DIRECTION=RIGHT; var dashOffset=0 var SUBMENU = { visible:false, width:0, height:0, buttons:[] } var BUTTON_SELECTED = undefined var ITEM_SELECTED = undefined var KEY_ROTATION_RIGHT = ["d","l","6","ArrowRight"] var KEY_ROTATION_LEFT = ["a","h","4","ArrowLeft"] var KEY_ROTATION_UP = ["w","k","8","ArrowUp"] var KEY_ROTATION_DOWN = ["s","j","2","ArrowDown"] var CONVEYOR_BUILD_BUTTON = {img:IMAGE_CONVEYOR,x:-1,y:-1,w:-1,h:-1,lastselected:DEF_CONVEYOR} var BRANCH_BUILD_BUTTON = {img:IMAGE_BRANCH,x:-1,y:-1,w:-1,h:-1,submenu_buttons:[DEF_BRANCHUP_RB,DEF_BRANCHUP_BR,DEF_BRANCHUP_GY,DEF_BRANCHUP_YG,DEF_BRANCHUP_PPI,DEF_BRANCHUP_PIP,DEF_BRANCHUP_BLGR,DEF_BRANCHUP_GRBL],lastselected:undefined} var WRITER_BUILD_BUTTON = {img:IMAGE_WRITER,x:-1,y:-1,w:-1,h:-1,submenu_buttons:[DEF_WRITERRIGHT_R,DEF_WRITERRIGHT_B,DEF_WRITERRIGHT_G,DEF_WRITERRIGHT_Y,DEF_WRITERRIGHT_P,DEF_WRITERRIGHT_PI,DEF_WRITERRIGHT_BL,DEF_WRITERRIGHT_GR],lastselected:undefined} var ROTATE_CLOCKWISE_BUTTON = {img:IMAGE_ROTATE_CLOCKWISE,x:-1,y:-1,w:-1,h:-1,cb:rotateClockwise } var ROTATE_COUNTERCLOCKWISE_BUTTON = {img:IMAGE_ROTATE_COUNTERCLOCKWISE,x:-1,y:-1,w:-1,h:-1,cb:rotateCounterClockwise } var WRITER_BUILD_BUTTON = {img:IMAGE_WRITER,x:-1,y:-1,w:-1,h:-1,submenu_buttons:[DEF_WRITERRIGHT_R,DEF_WRITERRIGHT_B,DEF_WRITERRIGHT_G,DEF_WRITERRIGHT_Y,DEF_WRITERRIGHT_P,DEF_WRITERRIGHT_PI,DEF_WRITERRIGHT_BL,DEF_WRITERRIGHT_GR],lastselected:undefined} var PLAY_BUTTON = {img:IMAGE_PLAY,x:-1,y:-1,w:-1,h:-1,cb:runGameSimulation } var PAUSE_BUTTON = {img:IMAGE_PAUSE,x:-1,y:-1,w:-1,h:-1,cb:pauseGameSimulation } var RESET_BUTTON = {img:IMAGE_RESET,x:-1,y:-1,w:-1,h:-1,cb:resetSimulation } var DELETE_BUTTON = {img:IMAGE_DELETE,x:-1,y:-1,w:-1,h:-1,cb:toggleDeleteMode } var MENU = { visible:true, buttons:[CONVEYOR_BUILD_BUTTON,BRANCH_BUILD_BUTTON,WRITER_BUILD_BUTTON,ROTATE_COUNTERCLOCKWISE_BUTTON,ROTATE_CLOCKWISE_BUTTON,DELETE_BUTTON,PLAY_BUTTON,RESET_BUTTON] } function runGameSimulation(){ gameState=TESTING generateBotQueue() //console.log(BOT_QUEUE) if (BOT_QUEUE.length>0) { BOT_TAPE=BOT_QUEUE[0] } else { BOT_TAPE="BR" } BOT_STATE=ALIVE gameState=WAITING BOT_X=gameStage.start.x BOT_Y=gameStage.start.y BOT_PREVX=BOT_X BOT_PREVY=BOT_Y BOT_DIR=RIGHT gameState=RUNNING for (var i=0;itrue} var STAGE2 = { name:"Blue Blue", objective:"Accept only Blue Bots", level:createGrid(5,5,4,2), start:{x:0,y:2}, accept:(tape)=>{ if (tape.length===0) { return false; } for (var i=0;i0) { var mask = remainingVal&1 if (mask===1) { tape="B"+tape } else { tape="R"+tape } remainingVal=remainingVal>>>1 } return tape; } function setNextSquare(offsetX,offsetY) { if (gameGrid[BOT_Y+offsetY]!==undefined) { var nextSquare = gameGrid[BOT_Y+offsetY][BOT_X+offsetX]; BOT_X+=offsetX BOT_Y+=offsetY return nextSquare } else { gameState = REVIEWING BOT_STATE = DEAD return undefined } } function runBot(testing) { //console.log(new Date().getTime()) if (lastGameUpdate=button.x && getMousePos(e).x<=button.x+button.w && getMousePos(e).y>=button.y && getMousePos(e).y<=button.y+button.h) } function clickEvent(e) { //console.log(MENU.buttons) if (e instanceof TouchEvent) { MOBILE=true e.preventDefault() } else { MOBILE=false } if (MENU.visible) { for (var button of MENU.buttons) { if (mouseOverButton(canvas,e,button)) { if (button.cb!==undefined) { button.cb() return; } else { DELETEMODE=false document.body.style.cursor="url('cursor.png') 8 8,auto" if (button.submenu_buttons&&button.submenu_buttons.length>0) { BUTTON_SELECTED=button; SUBMENU.visible=true; SUBMENU.buttons=[] var index = 0; for (var button2 of BUTTON_SELECTED.submenu_buttons) { var buttonX = ((index%3)*48)+16 var buttonY = canvas.height*0.8-(Math.floor(index/3)*48)-40 SUBMENU.buttons.push({def:button2,img:button2.img,x:buttonX,y:buttonY,w:32,h:32}) index++; } } ITEM_SELECTED=button.lastselected //console.log(button) return } } } } //console.log(getGridCoords(getMousePos(e))) if (ITEM_SELECTED!==undefined||DELETEMODE) { var clickCoords = getGridCoords(getMousePos(e)) if (coordsInBounds(clickCoords)) { modifyBoard(clickCoords,ITEM_SELECTED) DRAGGING = true DRAG_X = clickCoords.x DRAG_Y = clickCoords.y //console.log(gameGrid) } } } function coordsInBounds(coords) { return coords.x>=0&&coords.y>=0&&coords.ywidth-24) { xOffset=0; yOffset+=24; } } } function createVerticalGradient(x,y,up,ctx,scale) { var gradient = ctx.createLinearGradient(x, y+32*scale*((up)?1:0), x, y+32*scale*((up)?0:1)); gradient.addColorStop(0,"rgb(124,162,157)") gradient.addColorStop(0.31,"black") gradient.addColorStop(0.6,"rgb(124,162,157)") gradient.addColorStop(0.61,"black") gradient.addColorStop(0.9,"rgb(124,162,157)") gradient.addColorStop(0.91,"white") gradient.addColorStop(1,"white") return gradient } function createHorizontalGradient(x,y,right,ctx,scale) { var gradient = ctx.createLinearGradient(x+32*scale*((right)?0:1), y, x+32*scale*((right)?1:0), y); gradient.addColorStop(0,"rgb(124,162,157)") gradient.addColorStop(0.31,"black") gradient.addColorStop(0.6,"rgb(124,162,157)") gradient.addColorStop(0.61,"black") gradient.addColorStop(0.9,"rgb(124,162,157)") gradient.addColorStop(0.91,"white") gradient.addColorStop(1,"white") return gradient } function DrawSingleConveyor(x,y,dir,ctx,scale) { ctx.lineWidth = 16*scale; ctx.lineCap = "square" ctx.strokeStyle="rgb(124,162,157)" ctx.setLineDash([]) if (dir===LEFT||dir===RIGHT) { ctx.beginPath() ctx.moveTo(x+8*scale,y+16*scale) ctx.lineTo(x+24*scale,y+16*scale) ctx.stroke() ctx.setLineDash([5*scale,5*scale]) ctx.lineDashOffset = -dashOffset*((dir===LEFT)?-1*scale:1*scale); ctx.strokeStyle=createHorizontalGradient(x,y,dir===RIGHT,ctx,scale) ctx.lineWidth = 3.5*scale; ctx.beginPath() ctx.moveTo(x+2*scale,y+16*scale) ctx.lineTo(x+30*scale,y+16*scale) ctx.stroke() } else { ctx.beginPath() ctx.moveTo(x+16*scale,y+8*scale) ctx.lineTo(x+16*scale,y+24*scale) ctx.stroke() ctx.strokeStyle="rgb(34,62,57)" ctx.setLineDash([5*scale,5*scale]) ctx.lineDashOffset = -dashOffset*((dir===DOWN)?1:-1); ctx.strokeStyle=createVerticalGradient(x,y,dir===UP,ctx,scale) ctx.lineWidth = 3.5*scale; ctx.beginPath() ctx.moveTo(x+16*scale,y+2*scale) ctx.lineTo(x+16*scale,y+30*scale) ctx.stroke() } } function GetOppositeDirection(dir) { switch (dir) { case UP:{return DOWN} case DOWN:{return UP} case LEFT:{return RIGHT} case RIGHT:{return LEFT} } } function DrawConnectedConveyor(x,y,ctx,connections,dir,scale,pass=0) { ctx.lineWidth = 15*scale; ctx.lineCap = "round" ctx.strokeStyle="rgb(124,162,157)" switch (Object.keys(connections).length) { case 0:{ DrawSingleConveyor(x*scale,y*scale,dir,ctx,scale) }break; default:{ ctx.lineWidth = 15*scale; ctx.lineCap = "square" ctx.strokeStyle="rgb(124,162,157)" ctx.setLineDash([]) ctx.beginPath() ctx.moveTo(x+16*scale,y+16*scale) var endingPoint={x:0,y:0} switch (dir) { case UP:{startingPoint={x:0,y:-12*scale};endingPoint={x:0,y:-14*scale}}break; case DOWN:{startingPoint={x:0,y:12*scale};endingPoint={x:0,y:14*scale}}break; case RIGHT:{startingPoint={x:12*scale,y:0};endingPoint={x:14*scale,y:0}}break; case LEFT:{startingPoint={x:-12*scale,y:0};endingPoint={x:-14*scale,y:0}}break; } ctx.moveTo(x+16*scale+startingPoint.x,y+16*scale+startingPoint.y) ctx.lineTo(x+16*scale+endingPoint.x,y+16*scale+endingPoint.y) if (pass===0) {ctx.stroke();} for (var connection of Object.keys(connections)) { var startingPoint={x:x,y:y} switch (Number(connection)) { case UP:{startingPoint={x:x+16*scale,y:y+8*scale}}break; case DOWN:{startingPoint={x:x+16*scale,y:y+24*scale}}break; case RIGHT:{startingPoint={x:x+24*scale,y:y+16*scale}}break; case LEFT:{startingPoint={x:x+8*scale,y:y+16*scale}}break; } ctx.lineWidth = 16*scale; ctx.lineCap = "square" ctx.strokeStyle="rgb(124,162,157)" ctx.setLineDash([]) ctx.beginPath() ctx.moveTo(startingPoint.x,startingPoint.y) ctx.lineTo(x+16*scale,y+16*scale) if (pass===0) {ctx.stroke()} ctx.setLineDash([5*scale,5*scale]) ctx.lineDashOffset = -dashOffset*1; if (Number(connection)===RIGHT||Number(connection)===LEFT) { ctx.strokeStyle=createHorizontalGradient(x,y,Number(connection)===LEFT,ctx,scale) } else { ctx.strokeStyle=createVerticalGradient(x,y,Number(connection)===UP,ctx,scale) } ctx.lineWidth = 3.5*scale; ctx.beginPath() startingPoint={x:x,y:y} switch (Number(connection)) { case UP:{startingPoint={x:x+16*scale,y:y+2*scale}}break; case DOWN:{startingPoint={x:x+16*scale,y:y+30*scale}}break; case RIGHT:{startingPoint={x:x+30*scale,y:y+16*scale}}break; case LEFT:{startingPoint={x:x+2*scale,y:y+16*scale}}break; } ctx.moveTo(startingPoint.x,startingPoint.y) ctx.lineTo(x+16*scale,y+16*scale) if (pass===1) {ctx.stroke()} } if (dir===RIGHT||dir===LEFT) { ctx.strokeStyle=createHorizontalGradient(x,y,dir===LEFT,ctx,scale) } else { ctx.strokeStyle=createVerticalGradient(x,y,dir===UP,ctx,scale) } ctx.setLineDash([5*scale,5*scale]) ctx.lineWidth = 3.5*scale; ctx.beginPath() switch (dir) { case UP:{startingPoint={x:0,y:-14*scale}}break; case DOWN:{startingPoint={x:0,y:14*scale}}break; case RIGHT:{startingPoint={x:14*scale,y:0}}break; case LEFT:{startingPoint={x:-14*scale,y:0}}break; } ctx.moveTo(x+16*scale,y+16*scale) ctx.lineTo(x+16*scale+startingPoint.x,y+16*scale+startingPoint.y) if (pass===1) {ctx.stroke();} }break; } } function RenderConveyor(x,y,ctx,icon_definition,dir=0,background=undefined,grid=undefined,scale) { if (grid===undefined) { DrawSingleConveyor(x,y,dir,ctx,scale) } else { var connections = {} if (grid.x>0) {if (gameGrid[grid.y][grid.x-1].direction===RIGHT){connections[LEFT]=true}} if (grid.x0) {if (gameGrid[grid.y-1][grid.x].direction===DOWN){connections[UP]=true}} if (grid.y=buttonX&&LAST_MOUSE_X<=buttonX+32&&LAST_MOUSE_Y>=buttonY&&LAST_MOUSE_Y<=buttonY+32)?"#555555":"#b5b5b5") index++; } } } function RenderMenu(ctx) { if (MENU.visible) { ctx.fillStyle="#20424a" ctx.fillRect(0,canvas.height*0.8,canvas.width,canvas.height*0.2) var buttonX = 16 var buttonY = canvas.height*0.8+16 for (var button of MENU.buttons) { if (button.lastselected) { RenderIcon(buttonX,buttonY,ctx,button.lastselected,(button.cb===undefined)?ITEM_DIRECTION:0,"#b5b5b5") } else { AddButton(button.img,buttonX,buttonY,ctx,button,(button.cb===undefined)?ITEM_DIRECTION:0) } button.x=buttonX button.y=buttonY button.w=32 button.h=32 buttonX+=48 } } } function AddButton(img,x,y,ctx,button,dir=0) { ctx.fillStyle="#b5b5b5" ctx.fillRect(x,y,32,32) if (img===IMAGE_WRITER) { drawImage(x+16,y+16,img,ctx,dir*90-90) } else { drawImage(x+16,y+16,img,ctx,dir*90) } } function ConsumeTape() { BOT_TAPE=BOT_TAPE.substring(1) } function AppendTape(col) { BOT_TAPE+=col } function OverwriteTape(col) { BOT_TAPE=col+BOT_TAPE.substring(1) } function LeftOf(dir) { return (dir+1)%4 } function RightOf(dir) { if (dir===0) {dir=4} return (dir-1)%4 }