From e3a6b64a9dcae8e4d1d02969e28779be1337af7e Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 21 Oct 2016 10:45:54 -0600 Subject: Hey! It's interactive! --- js/lost.js | 453 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 358 insertions(+), 95 deletions(-) diff --git a/js/lost.js b/js/lost.js index b2b908c..58a7840 100644 --- a/js/lost.js +++ b/js/lost.js @@ -19,6 +19,27 @@ function oppositeDir( iDir ) return iDir+1; } +// +// Class: Signal +// +function Signal() +{ + this.aSlot = new Array(); +} + +Signal.prototype.connect = function connect( fSlot ) +{ + this.aSlot.push( fSlot ); +} + +Signal.prototype.call = function call() +{ + for( let j = 0; j < this.aSlot.length; j++ ) + { + (this.aSlot[j])(); + } +} + // // Class: Cell // @@ -99,6 +120,21 @@ Position.prototype.copy = function translate() return new Position( this.iDims, ...this.aiValues.slice() ); } +Position.prototype.equals = function equals( rhs ) +{ + if( this.iDims != rhs.iDims && + this.aiValues.length != rhs.aiValues.length ) + return false; + + for( let j = 0; j < this.aiValues.length; j++ ) + { + if( this.aiValues[j] != rhs.aiValues[j] ) + return false; + } + + return true; +} + // // Class: Map // @@ -106,6 +142,9 @@ function Map( Dimensions ) { // Store dimensional data this.Dimensions = Dimensions; + this.aWorms = new Array(); + this.pPlayer = null; + this.ePlayerMoved = new Signal(); // Compute the total number of cells let iTotalSize = 1; @@ -132,6 +171,36 @@ Map.prototype.getSize = function getSize( iDim ) return this.Dimensions.get( iDim ); } +Map.prototype.getPlayerPos = function getPlayerPos() +{ + return this.pPlayer; +} + +Map.prototype.setPlayerPos = function setPlayerPos( pNewPos ) +{ + this.pPlayer = pNewPos; + this.ePlayerMoved.call(); +} + +Map.prototype.movePlayer = function movePlayer( iDim, iDelta ) +{ + let cCur = this.get( this.pPlayer ); + + let iBit = iDim*2; + if( iDelta > 0 ) + iBit++; + + if( (cCur.iWalls&(1<= this.getSize( iDim ) ) + return; + + this.pPlayer.add( iDim, iDelta ); + this.ePlayerMoved.call(); +} + Map.prototype.isInside = function isInside( Position ) { if( Position.getDims() != this.Dimensions.getDims() ) @@ -174,6 +243,39 @@ Map.prototype.get = function get( Position ) return this.aCell[this.getIndex( Position )]; } +Map.prototype.addWorm = function addWorm( pStart ) +{ + if( this.aWorms.length === 0 ) + { + this.pPlayer = pStart; + } + let iNewId = this.aWorms.length+1; + this.aWorms.push( + new Worm( + iNewId, + pStart, + this + ) + ); + return iNewId; +} + +Map.prototype.buildMaze = function buildMaze() +{ + do + { + for( let j = 0; j < this.aWorms.length; j++ ) + { + if( !this.aWorms[j].timestep() ) + { + this.aWorms.splice( j, 1 ); + j--; + } + } + } while( this.aWorms.length > 0 ); + this.connect( 1, 2 ); +} + Map.prototype.connect = function connect( iWormId1, iWormId2 ) { let p = new Position( this.getDims() ); @@ -376,12 +478,41 @@ Render.prototype.render = function render() { } +function createMoveButton( rMap, iDim, iDir, sLabel ) +{ + let btn = document.createElement('button'); + btn.addEventListener( + 'click', + Map.prototype.movePlayer.bind( + rMap, + iDim, + iDir + ) + ); + if( sLabel === null || sLabel === '' ) + { + btn.appendChild( + document.createTextNode('Dim ' + (j+1) + ': -') + ); + } + else + { + btn.appendChild( + document.createTextNode( sLabel ) + ); + } + return btn; +} + // // Class: RenderCanvas2D // function RenderCanvas2D( rMap, eParent ) { Render.call( this, rMap, eParent ); + this.rMap.ePlayerMoved.connect( + RenderCanvas2D.prototype.render.bind( this ) + ); this.eCanvas = null; this.ctx = null; @@ -390,9 +521,13 @@ function RenderCanvas2D( rMap, eParent ) this.iIconSize = 11; this.iBorder = 3; + this.iIconSquare = Math.ceil( + Math.sqrt((this.rMap.getDims()-2)*2 + 1) + ); + this.iCellSize = this.iBorder + - (this.rMap.getDims()-2)*2*(this.iIconSize+this.iBorder); + this.iIconSquare*(this.iIconSize+this.iBorder); this.eCanvas = document.createElement('canvas'); this.eCanvas.width = this.iCellSize*this.rMap.getSize( 0 ); @@ -408,24 +543,88 @@ function RenderCanvas2D( rMap, eParent ) eParent.appendChild( document.createElement('br') ); eParent.appendChild( btnBox ); - for( let j = 2; j < this.rMap.getDims(); j++ ) + let cardTbl; + let cardRow; + let cardTd; + + cardTbl = document.createElement('table'); + cardRow = document.createElement('tr'); + cardTbl.appendChild( cardRow ); + cardRow.appendChild( document.createElement('td') ); + cardTd = document.createElement('td'); + cardTd.appendChild( createMoveButton( this.rMap, 1, -1, "North" ) ); + cardRow.appendChild( cardTd ); + cardRow.appendChild( document.createElement('td') ); + if( this.rMap.getDims() >= 3 ) { - for( let k = 0; k < this.rMap.getSize( j ); k++ ) - { - let btn = document.createElement('button'); - btn.addEventListener( - 'click', - RenderCanvas2D.prototype.setFloor.bind( - this, - [k] - ) - ); - btn.appendChild( - document.createTextNode('Floor ' + (k+1) ) - ); - btnBox.appendChild( btn ); - } + cardTd = document.createElement('td'); + 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" ) ); + cardRow.appendChild( cardTd ); + cardRow.appendChild( document.createElement('td') ); + cardTd = document.createElement('td'); + cardTd.appendChild( createMoveButton( this.rMap, 0, 1, "East" ) ); + cardRow.appendChild( cardTd ); + if( this.rMap.getDims() >= 3 ) + { + cardRow.appendChild( document.createElement('td') ); + } + + cardRow = document.createElement('tr'); + cardTbl.appendChild( cardRow ); + cardRow.appendChild( document.createElement('td') ); + cardTd = document.createElement('td'); + 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" ) ); + cardRow.appendChild( cardTd ); } + + btnBox.appendChild( cardTbl ); + + let names = []; + names[6] = 'In'; + names[7] = 'Out'; + names[8] = 'Through'; + names[9] = 'Around'; + + cardTbl = document.createElement('table'); + for( let j = 3; j < this.rMap.getDims(); j++ ) + { + cardRow = document.createElement('tr'); + cardTbl.appendChild( cardRow ); + + let label; + + if( typeof names[j*2] === 'undefined' ) + label = 'Dim ' + (j+1) + ': -'; + else + label = names[j*2]; + + cardTd = document.createElement('td'); + cardTd.appendChild( createMoveButton( this.rMap, j, -1, label ) ); + cardRow.appendChild( cardTd ); + + if( typeof names[j*2+1] === 'undefined' ) + label = 'Dim ' + (j+1) + ': +'; + else + label = names[j*2+1]; + + cardTd = document.createElement('td'); + cardTd.appendChild( createMoveButton( this.rMap, j, 1, label ) ); + cardRow.appendChild( cardTd ); + } + btnBox.appendChild( cardTbl ); } RenderCanvas2D.prototype = Object.create(Render.prototype); @@ -437,76 +636,156 @@ RenderCanvas2D.prototype.render = function render() this.ctx.clearRect( 0, 0, this.eCanvas.width, this.eCanvas.height ); this.ctx.beginPath(); - let p = this.pExtPosition.copy(); + let p; + if( this.rMap.pPlayer === null ) + p = this.pExtPosition.copy(); + else + p = this.rMap.pPlayer.copy(); + + for( let x = 0; x < this.rMap.getSize( 0 ); x++ ) { - for( let x = 0; x < this.rMap.getSize( 0 ); x++ ) + for( let y = 0; y < this.rMap.getSize( 1 ); y++ ) { - for( let y = 0; y < this.rMap.getSize( 1 ); y++ ) + p.set( 0, x ); + p.set( 1, y ); + let c = this.rMap.get( p ); + if( (c.iWalls&1) === 0 && x === 0) { - p.set( 0, x ); - p.set( 1, y ); - let c = this.rMap.get( p ); - if( (c.iWalls&1) === 0 && x === 0) - { - this.ctx.moveTo( x*iSize, y*iSize ); - this.ctx.lineTo( x*iSize, (y+1)*iSize ); - } - if( (c.iWalls&2) === 0 ) - { - this.ctx.moveTo( (x+1)*iSize, y*iSize ); - this.ctx.lineTo( (x+1)*iSize, (y+1)*iSize ); - } - if( (c.iWalls&4) === 0 && y === 0) - { - this.ctx.moveTo( x*iSize, y*iSize ); - this.ctx.lineTo( (x+1)*iSize, y*iSize ); - } - if( (c.iWalls&8) === 0 ) - { - this.ctx.moveTo( x*iSize, (y+1)*iSize ); - this.ctx.lineTo( (x+1)*iSize, (y+1)*iSize ); - } + this.ctx.moveTo( x*iSize, y*iSize ); + this.ctx.lineTo( x*iSize, (y+1)*iSize ); + } + if( (c.iWalls&2) === 0 ) + { + this.ctx.moveTo( (x+1)*iSize, y*iSize ); + this.ctx.lineTo( (x+1)*iSize, (y+1)*iSize ); + } + if( (c.iWalls&4) === 0 && y === 0) + { + this.ctx.moveTo( x*iSize, y*iSize ); + this.ctx.lineTo( (x+1)*iSize, y*iSize ); + } + if( (c.iWalls&8) === 0 ) + { + this.ctx.moveTo( x*iSize, (y+1)*iSize ); + this.ctx.lineTo( (x+1)*iSize, (y+1)*iSize ); + } - if( (c.iWalls&16) !== 0 ) + // Extended dimenisons (above 2 :-P) + let iIcon = 0; + for( let ed = 2; ed < this.rMap.getDims(); ed++ ) + { + if( (c.iWalls&(1<<(ed*2))) !== 0 ) { - // Up - let bx = x*iSize+this.iBorder; - let by = y*iSize+this.iBorder; - this.ctx.moveTo( - bx, - by+this.iIconSize - ); - this.ctx.lineTo( - bx+this.iIconSize/2, - by - ); - this.ctx.lineTo( - bx+this.iIconSize, - by+this.iIconSize - ); + this.renderDirIcon( x, y, iIcon, ed*2 ); } - if( (c.iWalls&32) !== 0 ) + iIcon++; + if( (c.iWalls&(1<<(ed*2+1))) !== 0 ) { - // Down - let bx = x*iSize+this.iBorder*2+this.iIconSize; - let by = y*iSize+this.iBorder; - this.ctx.moveTo( - bx, - by - ); - this.ctx.lineTo( - bx+this.iIconSize/2, - by+this.iIconSize - ); - this.ctx.lineTo( - bx+this.iIconSize, - by - ); + this.renderDirIcon( x, y, iIcon, ed*2+1 ); } + iIcon++; } } } this.ctx.stroke(); + + // Draw the player + if( this.rMap.pPlayer !== null ) + { + let bx = this.rMap.pPlayer.get(0)*iSize + + this.iBorder + (this.iIconSquare-1)*(this.iBorder+this.iIconSize); + let by = this.rMap.pPlayer.get(1)*iSize + + this.iBorder + (this.iIconSquare-1)*(this.iBorder+this.iIconSize); + this.rMap.pPlayer.equals( p ); + this.ctx.beginPath(); + this.ctx.ellipse( + bx+this.iIconSize*0.5, by+this.iIconSize*0.5, + this.iIconSize*0.4, this.iIconSize*0.4, + 0, + Math.PI*2.0, + false + ); + this.ctx.fill(); + } +} + +RenderCanvas2D.prototype.renderDirIcon = function renderDirIcon( + x, y, iIcon, iDir ) +{ + let bx = x*this.iCellSize + + this.iBorder + + (iIcon%this.iIconSquare)*(this.iIconSize+this.iBorder); + let by = y*this.iCellSize + + this.iBorder + + Math.floor(iIcon/this.iIconSquare)*(this.iIconSize+this.iBorder); + + //this.ctx.rect(bx, by, this.iIconSize, this.iIconSize ); + switch( iDir ) + { + case 4: + // Up + this.ctx.moveTo( + bx, + by+this.iIconSize + ); + this.ctx.lineTo( + bx+this.iIconSize/2, + by + ); + this.ctx.lineTo( + bx+this.iIconSize, + by+this.iIconSize + ); + break; + + case 5: + // Down + this.ctx.moveTo( + bx, + by + ); + this.ctx.lineTo( + bx+this.iIconSize/2, + by+this.iIconSize + ); + this.ctx.lineTo( + bx+this.iIconSize, + by + ); + break; + + case 6: + // In + this.ctx.moveTo( + bx+this.iIconSize, + by + ); + this.ctx.lineTo( + bx, + by+this.iIconSize/2 + ); + this.ctx.lineTo( + bx+this.iIconSize, + by+this.iIconSize + ); + break; + + case 7: + // Out + this.ctx.moveTo( + bx, + by + ); + this.ctx.lineTo( + bx+this.iIconSize, + by+this.iIconSize/2 + ); + this.ctx.lineTo( + bx, + by+this.iIconSize + ); + break; + } } RenderCanvas2D.prototype.setFloor = function setFloor( aFloor ) @@ -521,29 +800,13 @@ RenderCanvas2D.prototype.setFloor = function setFloor( aFloor ) // // Initialize // -let p = new Position( 3, 15, 15, 3 ); +let p = new Position( 4, 3, 3, 3, 3 ); let m = new Map( p ); let exit1 = new Position( p.getDims() ); let exit2 = new Position( p.getDims() ); exit2.set( 1, p.get( 1 )-1 ); -let w = [ - new Worm( 1, exit1, m ), - new Worm( 2, exit2, m ) - ]; - -do -{ - for( let j = 0; j < w.length; j++ ) - { - if( !w[j].timestep() ) - { - w.splice( j, 1 ); - j--; - } - } -} while( w.length > 0 ); - -m.connect( 1, 2 ); +m.addWorm( exit1 ); +m.addWorm( exit2 ); +m.buildMaze(); let rend = new RenderCanvas2D( m, document.body ); -//rend.render( document.body ); -- cgit v1.2.3