Implement bot wrong state engine
This commit is contained in:
parent
93f56a3b27
commit
c5b310cdd5
137
game.js
137
game.js
@ -3,29 +3,33 @@ var canvas;
|
||||
const WAITING = 0;
|
||||
const RUNNING = 1;
|
||||
const REVIEWING = 2;
|
||||
const TESTING = 3;
|
||||
const FINISH = 4;
|
||||
|
||||
const UP = 0;
|
||||
const RIGHT = 1;
|
||||
const DOWN = 2;
|
||||
const LEFT = 3;
|
||||
|
||||
const RED = 0;
|
||||
const BLUE = 1;
|
||||
const GREEN = 2;
|
||||
const YELLOW = 3;
|
||||
const PURPLE = 4;
|
||||
const PINK = 5;
|
||||
const BLACK = 6;
|
||||
const GRAY = 7;
|
||||
const RED = "R";
|
||||
const BLUE = "B";
|
||||
const GREEN = "G";
|
||||
const YELLOW = "Y";
|
||||
const PURPLE = "P";
|
||||
const PINK = "PI";
|
||||
const BLACK = "BL";
|
||||
const GRAY = "GR";
|
||||
|
||||
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 = [{color:RED},{color:BLUE}]
|
||||
var BOT_TAPE = "RB"
|
||||
var BOT_QUEUE = []
|
||||
|
||||
var BELTDOWN = {type:"BELT",direction:DOWN/*,direction2 - defines a secondary direction. For two belts at once.*/}
|
||||
var BELTRIGHT = {type:"BELT",direction:RIGHT}
|
||||
@ -45,6 +49,7 @@ var lastGameUpdate = 0;
|
||||
var gameSpeed = 1000/1;
|
||||
|
||||
var gameState=RUNNING;
|
||||
var gameStage=0;
|
||||
|
||||
var LEVEL0 = [
|
||||
[{},{},{},{},{},],
|
||||
@ -76,10 +81,16 @@ var LEVEL4 = [
|
||||
[{},{...BELTRIGHT,direction2:DOWN},{},{},{},],
|
||||
[{},{},{...BELTUP,direction2:LEFT},{},{},],
|
||||
[{},{},{},{},{},],]
|
||||
var STAGE1 = {
|
||||
name:"The First Stage!",
|
||||
objective:"Accept all bots",
|
||||
level:createGrid(5,5,4,2),
|
||||
start:{x:0,y:2},
|
||||
accept:(tape)=>true}
|
||||
|
||||
var gameGrid= []
|
||||
|
||||
function createGrid(width,height) {
|
||||
function createGrid(width=5,height=5,exitX=4,exitY=2) {
|
||||
var grid = []
|
||||
for (var i=0;i<width;i++) {
|
||||
var row = []
|
||||
@ -88,9 +99,85 @@ function createGrid(width,height) {
|
||||
}
|
||||
grid.push(row)
|
||||
}
|
||||
grid[exitY][exitX]={type:"EXIT"}
|
||||
return grid
|
||||
}
|
||||
|
||||
function resetGame() {
|
||||
gameGrid=[]
|
||||
gameState=WAITING
|
||||
BOT_X=-1
|
||||
BOT_Y=-1
|
||||
BOT_DIR=RIGHT
|
||||
BOT_STATE=ALIVE
|
||||
BOT_TAPE="RB"
|
||||
BOT_QUEUE=[]
|
||||
lastGameUpdate=0
|
||||
}
|
||||
|
||||
function generateBotQueue() {
|
||||
if (gameState===TESTING) {
|
||||
//Iterate up to...15 RED/BLUE combinations.
|
||||
var MAX_VALUE=1000
|
||||
var startingValue=0
|
||||
while (startingValue<MAX_VALUE) {
|
||||
var tape=ConvertNumberToTape(startingValue++)
|
||||
//console.log(tape)
|
||||
var wrongBot=false //Set to true if a bot that's supposed to pass fails, or a bot that's supposed to fail passes.
|
||||
var isSupposedToBeAccepted=gameStage.accept(tape)
|
||||
var result=getSimulatedBotResult(tape)
|
||||
if (result===isSupposedToBeAccepted) {
|
||||
wrongBot=false;
|
||||
} else {
|
||||
wrongBot=true;
|
||||
}
|
||||
|
||||
if (wrongBot) {
|
||||
BOT_QUEUE.push(tape)
|
||||
}
|
||||
if (BOT_QUEUE.length===3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSimulatedBotResult(tape) {
|
||||
var simulatedBoard = deepCopy(gameGrid)
|
||||
resetBot(gameStage.start.x,gameStage.start.y,TESTING,tape)
|
||||
const MAX_ITERATIONS=10000
|
||||
var iterations=0
|
||||
while (iterations<MAX_ITERATIONS) {
|
||||
runBot(true)
|
||||
//renderGame()
|
||||
if (gameState===REVIEWING) {
|
||||
//console.log("Rejected")
|
||||
return false
|
||||
}
|
||||
if (gameState===FINISH) {
|
||||
//console.log("Accepted")
|
||||
return true
|
||||
}
|
||||
iterations++
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function ConvertNumberToTape(val) {
|
||||
var remainingVal = val
|
||||
var tape = ""
|
||||
while (remainingVal>0) {
|
||||
var mask = remainingVal&1
|
||||
if (mask===1) {
|
||||
tape="B"+tape
|
||||
} else {
|
||||
tape="R"+tape
|
||||
}
|
||||
remainingVal=remainingVal>>>1
|
||||
}
|
||||
return tape;
|
||||
}
|
||||
|
||||
function runBot(testing) {
|
||||
//console.log(new Date().getTime())
|
||||
if (lastGameUpdate<new Date().getTime()||testing) {
|
||||
@ -119,17 +206,17 @@ function runBot(testing) {
|
||||
(nextSquare.direction2===UP||nextSquare.direction2===DOWN))?nextSquare.direction2:nextSquare.direction
|
||||
}break;
|
||||
}
|
||||
if (nextSquare.direction!==undefined) {
|
||||
if (nextSquare.direction!==undefined||nextSquare.type==="EXIT") {
|
||||
switch (nextSquare.type) {
|
||||
case "BRANCH":{
|
||||
//console.log("Branch found")
|
||||
if (BOT_TAPE[0].color===nextSquare.color1) {
|
||||
if (BOT_TAPE[0]===nextSquare.color1) {
|
||||
//console.log("Matches color1")
|
||||
//Move towards left side of the branch.
|
||||
BOT_DIR = LeftOf(nextSquare.direction)
|
||||
ConsumeTape()
|
||||
} else
|
||||
if (BOT_TAPE[0].color===nextSquare.color2) {
|
||||
if (BOT_TAPE[0]===nextSquare.color2) {
|
||||
//console.log("Matches color2")
|
||||
//Move towards left side of the branch.
|
||||
BOT_DIR = RightOf(nextSquare.direction)
|
||||
@ -144,6 +231,10 @@ function runBot(testing) {
|
||||
}
|
||||
BOT_DIR = nextSquare.direction
|
||||
}break;
|
||||
case "EXIT":{
|
||||
gameState=FINISH
|
||||
BOT_STATE=DONE
|
||||
}break;
|
||||
}
|
||||
//console.log("Direction is now "+BOT_DIR)
|
||||
} else {
|
||||
@ -154,6 +245,14 @@ function runBot(testing) {
|
||||
}
|
||||
}
|
||||
|
||||
function resetBot(x,y,state,tape) {
|
||||
gameState=state
|
||||
BOT_STATE = ALIVE
|
||||
BOT_DIR = RIGHT
|
||||
BOT_TAPE=deepCopy(tape)
|
||||
placeBot(x,y)
|
||||
}
|
||||
|
||||
function placeBot(x,y) {
|
||||
BOT_X = x
|
||||
BOT_Y = y
|
||||
@ -173,6 +272,12 @@ function loadLevel(level,botx,boty) {
|
||||
gameGrid = deepCopy(level)
|
||||
}
|
||||
|
||||
function loadStage(stage) {
|
||||
//gameGrid=deepCopy(stage.level)
|
||||
loadLevel(stage.level,stage.start.x,stage.start.y)
|
||||
gameStage=stage
|
||||
}
|
||||
|
||||
function deepCopy(arr) {
|
||||
var newarr = []
|
||||
for (var i=0;i<arr.length;i++) {
|
||||
@ -209,13 +314,13 @@ function draw() {
|
||||
}
|
||||
|
||||
function ConsumeTape() {
|
||||
BOT_TAPE.shift()
|
||||
BOT_TAPE=BOT_TAPE.substring(1)
|
||||
}
|
||||
function AppendTape(col) {
|
||||
BOT_TAPE.push({color:col})
|
||||
BOT_TAPE+=col
|
||||
}
|
||||
function OverwriteTape(col) {
|
||||
BOT_TAPE[0]={color:col}
|
||||
BOT_TAPE=col+BOT_TAPE.substring(1)
|
||||
}
|
||||
|
||||
function LeftOf(dir) {
|
||||
|
149
game.test.js
149
game.test.js
@ -36,18 +36,24 @@ class describe {
|
||||
this.cb()
|
||||
return this
|
||||
}
|
||||
|
||||
showResults = () =>{
|
||||
console.log("==============")
|
||||
console.log("TEST RESULTS: "+TestSuite.passedtests+" passed, "+(TestSuite.totaltests-TestSuite.passedtests)+" failed, "+TestSuite.totaltests+" total")
|
||||
console.log("==============")
|
||||
}
|
||||
}
|
||||
|
||||
function expect(testval1,testval2,test) {
|
||||
function expect(testval1,testval2,name) {
|
||||
if (testval1!==testval2) {
|
||||
console.log(" Test Failed!"+" ("+(new Date().getTime()-TestSuite.starttime)+"ms)")
|
||||
console.log(" Test Failed!"+" ("+(new Date().getTime()-TestSuite.starttime)+"ms)"+((name)?` - ${name}`:""))
|
||||
TestSuite.totaltests++
|
||||
testsPass=false
|
||||
} else
|
||||
{
|
||||
TestSuite.totaltests++
|
||||
TestSuite.passedtests++
|
||||
console.log(" Test Passed!"+" ("+(new Date().getTime()-TestSuite.starttime)+"ms)")
|
||||
console.log(" Test Passed!"+" ("+(new Date().getTime()-TestSuite.starttime)+"ms)"+((name)?` - ${name}`:""))
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,14 +73,7 @@ function runTests() {
|
||||
TestSuite = new describe("Bot moving")
|
||||
TestSuite
|
||||
.beforeEach(()=>{
|
||||
gameGrid=[]
|
||||
gameState=WAITING
|
||||
BOT_X=-1
|
||||
BOT_Y=-1
|
||||
BOT_DIR=RIGHT
|
||||
BOT_STATE=ALIVE
|
||||
BOT_TAPE=[{color:RED},{color:BLUE}]
|
||||
lastGameUpdate=0
|
||||
resetGame()
|
||||
})
|
||||
.it("Blank level exists.",()=>{
|
||||
expect(AllBlankSpaces(LEVEL0),true)
|
||||
@ -116,7 +115,7 @@ function runTests() {
|
||||
.it("Bot obeys branch rules with different colored tape.",()=>{
|
||||
expect(function(){
|
||||
loadLevel(LEVEL2,0,2)
|
||||
BOT_TAPE = [{color:BLUE}]
|
||||
BOT_TAPE = "B"
|
||||
for (var i=0;i<3;i++) {runBot(true)}
|
||||
if (BOT_X===2&&BOT_Y===1) {
|
||||
return true
|
||||
@ -129,7 +128,7 @@ function runTests() {
|
||||
expect(function(){
|
||||
loadLevel(LEVEL2,0,2)
|
||||
for (var i=0;i<3;i++) {runBot(true)}
|
||||
if (BOT_TAPE.length===1&&BOT_TAPE[0].color===BLUE) {
|
||||
if (BOT_TAPE.length===1&&BOT_TAPE[0]==="B") {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -139,7 +138,7 @@ function runTests() {
|
||||
.it("Bot tape is reduced by 1 when passing through a different branch.",()=>{
|
||||
expect(function(){
|
||||
loadLevel(LEVEL2,0,2)
|
||||
BOT_TAPE = [{color:BLUE}]
|
||||
BOT_TAPE = "B"
|
||||
for (var i=0;i<3;i++) {runBot(true)}
|
||||
if (BOT_TAPE.length===0) {
|
||||
return true
|
||||
@ -163,7 +162,7 @@ function runTests() {
|
||||
expect(function(){
|
||||
loadLevel(LEVEL3,0,2)
|
||||
for (var i=0;i<3;i++) {runBot(true)}
|
||||
if (BOT_TAPE.length===3&&BOT_TAPE[2].color===RED) {
|
||||
if (BOT_TAPE.length===3&&BOT_TAPE[2]==="R") {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -173,9 +172,9 @@ function runTests() {
|
||||
.it("Bot obeys writer tape rules - Has correct tape when overwriting",()=>{
|
||||
expect(function(){
|
||||
loadLevel(LEVEL3,0,1)
|
||||
BOT_TAPE=[{color:BLUE},{color:RED}]
|
||||
BOT_TAPE="BR"
|
||||
for (var i=0;i<2;i++) {runBot(true)}
|
||||
if (BOT_TAPE.length===2&&BOT_TAPE[0].color===RED) {
|
||||
if (BOT_TAPE.length===2&&BOT_TAPE[0]==="R") {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -194,6 +193,18 @@ function runTests() {
|
||||
}
|
||||
}(),true)
|
||||
})
|
||||
.it("Bot tape is unaffected if no color matched.",()=>{
|
||||
expect(function(){
|
||||
loadLevel(LEVEL2,0,2)
|
||||
BOT_TAPE = [{color:YELLOW}]
|
||||
for (var i=0;i<2;i++) {runBot(true)}
|
||||
if (BOT_TAPE.length===1) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}(),true)
|
||||
})
|
||||
.it("Bot goes right when approaching a double belt (Left->Right) from the left",()=>{
|
||||
expect(function(){
|
||||
loadLevel(LEVEL4,0,2)
|
||||
@ -241,11 +252,109 @@ function runTests() {
|
||||
}
|
||||
}(),true)
|
||||
})
|
||||
.it("Convert Number to Tape function works as expected. 0 bits=R, 1 bits=B",()=>{
|
||||
expect(ConvertNumberToTape(4),"BRR","4=100=\"BRR\"")
|
||||
expect(ConvertNumberToTape(24),"BBRRR","24=11000=\"BBRRR\"")
|
||||
expect(ConvertNumberToTape(167),"BRBRRBBB","167=10100111=\"BRBRRBBB\"")
|
||||
}).showResults()
|
||||
|
||||
|
||||
console.log("==============")
|
||||
console.log("TEST RESULTS: "+TestSuite.passedtests+" passed, "+(TestSuite.totaltests-TestSuite.passedtests)+" failed, "+TestSuite.totaltests+" total")
|
||||
console.log("==============")
|
||||
TestSuite = new describe("Stage 1")
|
||||
TestSuite
|
||||
.beforeEach(()=>{
|
||||
resetGame()
|
||||
})
|
||||
.it("Stage 1 has a level",()=>{
|
||||
expect(STAGE1.level===undefined,false,"Is defined")
|
||||
expect(Array.isArray(STAGE1.level),true,"Is an array")
|
||||
expect(STAGE1.level.length>0,true,"Cannot be empty")
|
||||
})
|
||||
.it("Stage 1 has a name",()=>{
|
||||
expect(STAGE1.name===undefined,false,"Is defined")
|
||||
expect(typeof(STAGE1.name),"string","Is a string")
|
||||
expect(STAGE1.name.length>0,true,"Cannot be blank")
|
||||
})
|
||||
.it("Stage 1 has an objective",()=>{
|
||||
expect(STAGE1.objective===undefined,false,"Is defined")
|
||||
expect(typeof(STAGE1.objective),"string","Is a string")
|
||||
expect(STAGE1.objective.length>0,true,"Cannot be blank")
|
||||
})
|
||||
.it("Stage 1 has a starting position",()=>{
|
||||
expect(STAGE1.start===undefined,false,"Is defined")
|
||||
expect(typeof(STAGE1.start),"object","Is an object")
|
||||
expect(STAGE1.start.x===undefined,false,"Must have an X coordinate")
|
||||
expect(STAGE1.start.y===undefined,false,"Must have a Y coordinate")
|
||||
})
|
||||
.it("Stage 1 has an acceptance condition",()=>{
|
||||
expect(STAGE1.accept===undefined,false)
|
||||
expect(typeof(STAGE1.accept),"function")
|
||||
})
|
||||
.it("loadStage sets up stage 1",()=>{
|
||||
loadStage(STAGE1)
|
||||
expect(gameGrid.length===STAGE1.level.length,true,"Height of stage is equal")
|
||||
expect(gameGrid[0].length===STAGE1.level[0].length,true,"Width of stage is equal")
|
||||
})
|
||||
.it("current stage set to stage 1",()=>{
|
||||
loadStage(STAGE1)
|
||||
expect(gameStage===STAGE1,true)
|
||||
})
|
||||
.it("accept all bots for stage 1.",()=>{
|
||||
loadStage(STAGE1)
|
||||
expect(gameStage.accept(""),true,"Expect true for \"\"")
|
||||
expect(gameStage.accept("RB"),true,"Expect true for RB")
|
||||
expect(gameStage.accept("BRBR"),true,"Expect true for BRBR")
|
||||
})
|
||||
.it("bot fails at the start.",()=>{
|
||||
loadStage(STAGE1)
|
||||
runBot(true)
|
||||
expect(gameState===REVIEWING,true)
|
||||
})
|
||||
.it("When TESTING state is on, the game should test the current level for cases expecting to pass, but fail and create 3 of them if possible.",()=>{
|
||||
loadStage(STAGE1)
|
||||
expect(BOT_QUEUE.length===0,true,"Bot queue should be empty.")
|
||||
generateBotQueue()
|
||||
expect(BOT_QUEUE.length===0&&gameState!==TESTING,true,"Bot queue should not be modified while state is not TESTING")
|
||||
gameState=TESTING
|
||||
generateBotQueue()
|
||||
expect(BOT_QUEUE.length===3,true,"There should be 3 bots in queue for an unbuilt level, as all bots are supposed to pass.")
|
||||
})
|
||||
.it("A stage should have an Exit.",()=>{
|
||||
loadStage(STAGE1)
|
||||
var hasAnExit=()=>{
|
||||
for (var y=0;y<gameGrid.length;y++) {
|
||||
for (var x=0;x<gameGrid[y].length;x++) {
|
||||
if (gameGrid[y][x].type==="EXIT") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
expect(hasAnExit(),true)
|
||||
})
|
||||
.it("A bot reaching the exit should set the state to FINISH.",()=>{
|
||||
loadStage(STAGE1)
|
||||
placeBot(3,2)
|
||||
runBot(true)
|
||||
expect(gameState===FINISH,true)
|
||||
})
|
||||
.it("Run a TESTING state to see if an acceptable player-built level has no bots in queue.",()=>{
|
||||
loadStage(STAGE1)
|
||||
gameGrid=[
|
||||
[{},{},{},{},{},],
|
||||
[{},{},{},{},{},],
|
||||
[{},{...BELTRIGHT},{...BELTRIGHT},{...BELTRIGHT},{type:"EXIT"},],
|
||||
[{},{},{},{},{},],
|
||||
[{},{},{},{},{},],
|
||||
]
|
||||
expect(BOT_QUEUE.length===0,true,"Bot queue should be empty.")
|
||||
gameState=TESTING
|
||||
generateBotQueue()
|
||||
//console.log(BOT_QUEUE)
|
||||
expect(BOT_QUEUE.length===0,true,"There should be 0 bots in queue for a good level, as all bots are supposed to pass.")
|
||||
})
|
||||
.showResults()
|
||||
|
||||
if (testsPass===undefined) {
|
||||
testsPass=true
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user