From 1545f1d23e2dd8956593c6294518c4f3dc5c2028 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 21 Oct 2016 15:06:14 -0600 Subject: A simple get form lets you pick maze dims. It would be cooler to have something more dynamic and interactive, but this is pretty good for now. It should probably try to detect issues with your syntax, too, but that can come later. You can also share maps now. That's a fun feature overall. --- js/lost.html | 2 + js/lost.js | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 256 insertions(+), 42 deletions(-) diff --git a/js/lost.html b/js/lost.html index 38f246e..820b1fc 100644 --- a/js/lost.html +++ b/js/lost.html @@ -1,5 +1,7 @@ + + Lost diff --git a/js/lost.js b/js/lost.js index 58a7840..43a0b13 100644 --- a/js/lost.js +++ b/js/lost.js @@ -5,10 +5,56 @@ // Helper functions // +// +// Class: RandomLcg +// +function RandomLcg() +{ + this.iState = 0; + this.iSeed = 0; + + this.inventSeed(); +} + +RandomLcg.prototype.setSeed = function setSeed( iSeed ) +{ + this.iState = this.iSeed = iSeed; +} + +RandomLcg.prototype.getSeed = function getSeed() +{ + return this.iSeed; +} + +RandomLcg.prototype.inventSeed = function inventSeed() +{ + // Based on my reading it's safest to assume that we can get 16 bits worth + // of random data reliably. Let's build a 32 bit number from two 16 bit + // numbers. + this.setSeed( + (Math.floor(Math.random()*0xffff)) | + (Math.floor(Math.random()*0xffff)<<16) + ); +} + +RandomLcg.prototype.random = function random() +{ + this.iState = ((this.iState * 1103515245) + 12345) & 0x7fffffff; + return this.iState/(0x7fffffff+1); +} + +RandomLcg.prototype.randInt = function randInt( max ) +{ + return Math.floor(this.random() * max); +} + +let lRand = new RandomLcg(); + // Just return a random integer between 0 and max, exclusive on the upper bound. function randInt( max ) { - return Math.floor(Math.random() * max); + return lRand.randInt( max ); +// return Math.floor(Math.random() * max); } // Return the id for the opposite direction of the direction given. @@ -55,34 +101,47 @@ function Cell() // function Position( iDims, ...Vals ) { - // Store dimension count - this.iDims = iDims; - - // Check to see if Vals is a non-empty array - if( Array.isArray(Vals) && Vals.length > 0 ) + if( typeof iDims === 'string' ) { - // Make sure Vals has the right number of elements - if( Vals.length != iDims ) + let sChunks = iDims.split(','); + this.iDims = sChunks.length; + this.aiValues = new Array(this.iDims); + for( let j = 0; j < this.iDims; j++ ) { - throw new Error( - 'Position must be initialized with no dimensional data, '+ - 'or the correct number of elements.'); + this.aiValues[j] = parseInt( sChunks[j].trim(), 10 ); } - - // If it does have the correct number of elements, just - // use it instead of creating a new array - this.aiValues = Vals; } else { - // We don't have values from the constructor, let's just - // create a new blank one... - this.aiValues = new Array( this.iDims ); + // Store dimension count + this.iDims = iDims; - // ...and set the position to zero in all dimensions. - for( let j = 0; j < this.iDims; j++ ) + // Check to see if Vals is a non-empty array + if( Array.isArray(Vals) && Vals.length > 0 ) + { + // Make sure Vals has the right number of elements + if( Vals.length != iDims ) + { + throw new Error( + 'Position must be initialized with no dimensional data, '+ + 'or the correct number of elements.'); + } + + // If it does have the correct number of elements, just + // use it instead of creating a new array + this.aiValues = Vals; + } + else { - this.aiValues[j] = 0; + // We don't have values from the constructor, let's just + // create a new blank one... + this.aiValues = new Array( this.iDims ); + + // ...and set the position to zero in all dimensions. + for( let j = 0; j < this.iDims; j++ ) + { + this.aiValues[j] = 0; + } } } } @@ -135,6 +194,17 @@ Position.prototype.equals = function equals( rhs ) return true; } +Position.prototype.toString = function toString() +{ + let ret = this.aiValues[0].toString(); + for( let j = 1; j < this.aiValues.length; j++ ) + { + ret += ',' + this.aiValues[j].toString(); + } + + return ret; +} + // // Class: Map // @@ -144,7 +214,10 @@ function Map( Dimensions ) this.Dimensions = Dimensions; this.aWorms = new Array(); this.pPlayer = null; + this.pGoal = null; this.ePlayerMoved = new Signal(); + this.eVictory = new Signal(); + this.ePlayerSetup = new Signal(); // Compute the total number of cells let iTotalSize = 1; @@ -199,6 +272,11 @@ Map.prototype.movePlayer = function movePlayer( iDim, iDelta ) this.pPlayer.add( iDim, iDelta ); this.ePlayerMoved.call(); + + if( this.pPlayer.equals( this.pGoal ) ) + { + this.eVictory.call(); + } } Map.prototype.isInside = function isInside( Position ) @@ -245,9 +323,14 @@ Map.prototype.get = function get( Position ) Map.prototype.addWorm = function addWorm( pStart ) { - if( this.aWorms.length === 0 ) + if( this.pPlayer === null ) { this.pPlayer = pStart; + this.ePlayerSetup.call(); + } + else if( this.pGoal === null ) + { + this.pGoal = pStart; } let iNewId = this.aWorms.length+1; this.aWorms.push( @@ -513,9 +596,16 @@ function RenderCanvas2D( rMap, eParent ) this.rMap.ePlayerMoved.connect( RenderCanvas2D.prototype.render.bind( this ) ); + this.rMap.ePlayerMoved.connect( + RenderCanvas2D.prototype.updateButtons.bind( this ) + ); + this.rMap.eVictory.connect( + RenderCanvas2D.prototype.setVictory.bind( this ) + ); this.eCanvas = null; this.ctx = null; + this.isSolved = false; this.pExtPosition = new Position( rMap.getDims() ); @@ -535,13 +625,17 @@ function RenderCanvas2D( rMap, eParent ) eParent.appendChild( this.eCanvas ); this.ctx = this.eCanvas.getContext("2d"); this.ctx.lineWidth = 1.0; + this.ctx.font = Math.ceil(this.iIconSize) + 'px sans serif'; + this.ctx.textBaseline = 'top'; + + this.aMoveButtons = []; this.render(); - let btnBox = document.createElement('div'); + this.btnBox = document.createElement('div'); eParent.appendChild( document.createElement('br') ); eParent.appendChild( document.createElement('br') ); - eParent.appendChild( btnBox ); + eParent.appendChild( this.btnBox ); let cardTbl; let cardRow; @@ -552,24 +646,32 @@ function RenderCanvas2D( rMap, eParent ) cardTbl.appendChild( cardRow ); cardRow.appendChild( document.createElement('td') ); cardTd = document.createElement('td'); - cardTd.appendChild( createMoveButton( this.rMap, 1, -1, "North" ) ); + this.aMoveButtons[2] = cardTd.appendChild( + createMoveButton( this.rMap, 1, -1, "North" ) + ); cardRow.appendChild( cardTd ); cardRow.appendChild( document.createElement('td') ); if( this.rMap.getDims() >= 3 ) { cardTd = document.createElement('td'); - cardTd.appendChild( createMoveButton( this.rMap, 2, -1, "Up" ) ); + this.aMoveButtons[4] = cardTd.appendChild( + createMoveButton( this.rMap, 2, -1, "Up (^)" ) + ); cardRow.appendChild( cardTd ); } cardRow = document.createElement('tr'); cardTbl.appendChild( cardRow ); cardTd = document.createElement('td'); - cardTd.appendChild( createMoveButton( this.rMap, 0, -1, "West" ) ); + this.aMoveButtons[0] = cardTd.appendChild( + createMoveButton( this.rMap, 0, -1, "West" ) + ); cardRow.appendChild( cardTd ); cardRow.appendChild( document.createElement('td') ); cardTd = document.createElement('td'); - cardTd.appendChild( createMoveButton( this.rMap, 0, 1, "East" ) ); + this.aMoveButtons[1] = cardTd.appendChild( + createMoveButton( this.rMap, 0, 1, "East" ) + ); cardRow.appendChild( cardTd ); if( this.rMap.getDims() >= 3 ) { @@ -580,23 +682,25 @@ function RenderCanvas2D( rMap, eParent ) cardTbl.appendChild( cardRow ); cardRow.appendChild( document.createElement('td') ); cardTd = document.createElement('td'); - cardTd.appendChild( createMoveButton( this.rMap, 1, 1, "South" ) ); + this.aMoveButtons[3] = cardTd.appendChild( + createMoveButton( this.rMap, 1, 1, "South" ) + ); cardRow.appendChild( cardTd ); cardRow.appendChild( document.createElement('td') ); if( this.rMap.getDims() >= 3 ) { cardTd = document.createElement('td'); - cardTd.appendChild( createMoveButton( this.rMap, 2, 1, "Down" ) ); + this.aMoveButtons[5] = cardTd.appendChild( + createMoveButton( this.rMap, 2, 1, "Down (v)" ) + ); cardRow.appendChild( cardTd ); } - btnBox.appendChild( cardTbl ); + this.btnBox.appendChild( cardTbl ); let names = []; - names[6] = 'In'; - names[7] = 'Out'; - names[8] = 'Through'; - names[9] = 'Around'; +// names[6] = 'In (<)'; +// names[7] = 'Out (>)'; cardTbl = document.createElement('table'); for( let j = 3; j < this.rMap.getDims(); j++ ) @@ -607,24 +711,30 @@ function RenderCanvas2D( rMap, eParent ) let label; if( typeof names[j*2] === 'undefined' ) - label = 'Dim ' + (j+1) + ': -'; + label = (j+1) + '-'; else label = names[j*2]; cardTd = document.createElement('td'); - cardTd.appendChild( createMoveButton( this.rMap, j, -1, label ) ); + this.aMoveButtons[j*2] = cardTd.appendChild( + createMoveButton( this.rMap, j, -1, label ) + ); cardRow.appendChild( cardTd ); if( typeof names[j*2+1] === 'undefined' ) - label = 'Dim ' + (j+1) + ': +'; + label = (j+1) + '+'; else label = names[j*2+1]; cardTd = document.createElement('td'); - cardTd.appendChild( createMoveButton( this.rMap, j, 1, label ) ); + this.aMoveButtons[j*2+1] = cardTd.appendChild( + createMoveButton( this.rMap, j, 1, label ) + ); cardRow.appendChild( cardTd ); } - btnBox.appendChild( cardTbl ); + this.btnBox.appendChild( cardTbl ); + + this.updateButtons(); } RenderCanvas2D.prototype = Object.create(Render.prototype); @@ -649,6 +759,15 @@ RenderCanvas2D.prototype.render = function render() p.set( 0, x ); p.set( 1, y ); let c = this.rMap.get( p ); + + if( p.equals( this.rMap.pGoal ) ) + { + let oldStyle = this.ctx.fillStyle; + this.ctx.fillStyle = 'palegreen'; + this.ctx.fillRect( x*iSize+2, y*iSize+2, iSize-4, iSize-4 ); + this.ctx.fillStyle = oldStyle; + } + if( (c.iWalls&1) === 0 && x === 0) { this.ctx.moveTo( x*iSize, y*iSize ); @@ -704,7 +823,7 @@ RenderCanvas2D.prototype.render = function render() 0, Math.PI*2.0, false - ); + ); this.ctx.fill(); } } @@ -753,7 +872,7 @@ RenderCanvas2D.prototype.renderDirIcon = function renderDirIcon( by ); break; - +/* case 6: // In this.ctx.moveTo( @@ -785,9 +904,42 @@ RenderCanvas2D.prototype.renderDirIcon = function renderDirIcon( by+this.iIconSize ); break; +*/ + default: + let label = + Math.floor((iDir/2.0)+1).toString() + + (((iDir%2)===0)?'-':'+'); + this.ctx.fillText( + label, + bx, by + ); + break; + } +} + +RenderCanvas2D.prototype.updateButtons = function updateButtons() +{ + let c = this.rMap.get( this.rMap.pPlayer ); + for( let j = 0; j < this.rMap.getDims()*2; j++ ) + { + this.aMoveButtons[j].disabled = (c.iWalls&(1<= 0 ) +{ + trgUrl = trgUrl.substring(0, query); +} +trgUrl += '?seed=' + lRand.getSeed() + '&dims=' + p.toString(); +dLink.href = trgUrl; +dLink.appendChild( document.createTextNode('Share this maze!') ); +d.appendChild(dLink); +document.body.appendChild( document.createElement('br') ); +document.body.appendChild( d ); -- cgit v1.2.3