summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--js/lost.js363
1 files changed, 192 insertions, 171 deletions
diff --git a/js/lost.js b/js/lost.js
index e2cfda5..133dfac 100644
--- a/js/lost.js
+++ b/js/lost.js
@@ -13,20 +13,20 @@ function oppositeDir( iDir )
13 return iDir+1; 13 return iDir+1;
14} 14}
15 15
16// 16/**
17// Create a new button element using the dom that has the given label, 17 * Create a new button element using the dom that has the given label,
18// and calls the movePlayer method on the given map, along the provided 18 * and calls the movePlayer method on the given map, along the provided
19// dimension, and in the specified direction. 19 * dimension, and in the specified direction.
20// 20 *
21// The button created is then returned. 21 * The button created is then returned.
22// 22 */
23function createMoveButton( rMap, iDim, iDir, sLabel ) 23function createMoveButton( rMazeMap, iDim, iDir, sLabel )
24{ 24{
25 let btn = document.createElement('button'); 25 let btn = document.createElement('button');
26 btn.addEventListener( 26 btn.addEventListener(
27 'click', 27 'click',
28 Map.prototype.movePlayer.bind( 28 MazeMap.prototype.movePlayer.bind(
29 rMap, 29 rMazeMap,
30 iDim, 30 iDim,
31 iDir 31 iDir
32 ) 32 )
@@ -46,22 +46,24 @@ function createMoveButton( rMap, iDim, iDir, sLabel )
46 return btn; 46 return btn;
47} 47}
48 48
49// 49/**
50// Class: RandomLcg 50 * Class: RandomLcg
51// 51 *
52// This implements a Linear Congruential Generator PRNG. Is this the best PRNG? 52 * This implements a Linear Congruential Generator PRNG. Is this the best
53// Nope! Is it decently random for our purposes, sure. 53 * PRNG? Nope! Is it decently random for our purposes, sure.
54// 54 *
55// Why was this implemented? I wanted to be able to share mazes, in order to do 55 * Why was this implemented? I wanted to be able to share mazes, in order to
56// that we needed two things that we can't get from JS by default: 56 * do that we needed two things that we can't get from JS by default:
57// 1. To be able to set the seed (and get it if possible). 57 * 1. To be able to set the seed (and get it if possible).
58// 2. To be sure that the same algorithm would be used on every version of 58 * 2. To be sure that the same algorithm would be used on every version of
59// every browser. 59 * every browser.
60// 60 *
61// Unfortunately JavaScript doesn't gurantee either of these things, so instead 61 * Unfortunately JavaScript doesn't gurantee either of these things, so
62// of writing a CMWC and using a bunch of memory I just used the settings from 62 * instead of writing a CMWC and using a bunch of memory I just used the
63// the glibc random function and here we are. 63 * settings from the glibc random function and here we are.
64// 64 *
65 * @constructor
66 */
65function RandomLcg() 67function RandomLcg()
66{ 68{
67 // Current state 69 // Current state
@@ -124,13 +126,15 @@ RandomLcg.prototype.randInt = function randInt( max )
124// Lets just build a shared prng object to use all over. 126// Lets just build a shared prng object to use all over.
125let lRand = new RandomLcg(); 127let lRand = new RandomLcg();
126 128
127// 129/**
128// Class: Signal 130 * Class: Signal
129// 131 *
130// Super simple implementation of a signal/slot concept. I didn't need most of 132 * Super simple implementation of a signal/slot concept. I didn't need most of
131// the features, so this just lets us connect 0-parameter functions and call 133 * the features, so this just lets us connect 0-parameter functions and call
132// them en-masse whenever the signal is fired. 134 * them en-masse whenever the signal is fired.
133// 135 *
136 * @constructor
137 */
134function Signal() 138function Signal()
135{ 139{
136 this.aSlot = new Array(); 140 this.aSlot = new Array();
@@ -157,11 +161,13 @@ Signal.prototype.emit = function emit()
157 } 161 }
158} 162}
159 163
160// 164/**
161// Class: Cell 165 * Class: Cell
162// 166 *
163// Simple container that tracks info about a cell in the maze. 167 * Simple container that tracks info about a cell in the maze.
164// 168 *
169 * @constructor
170 */
165function Cell() 171function Cell()
166{ 172{
167 this.iDist = 0; 173 this.iDist = 0;
@@ -169,13 +175,15 @@ function Cell()
169 this.iWalls = 0; 175 this.iWalls = 0;
170} 176}
171 177
172// 178/**
173// Class: Position 179 * Class: Position
174// 180 *
175// A simple class that keeps track of coordinates in N-dimensional space. 181 * A simple class that keeps track of coordinates in N-dimensional space.
176// That's really just an array of numbers with N spaces in it. 182 * That's really just an array of numbers with N spaces in it.
177// 183 *
178function Position( iDims, ...Vals ) 184 * @constructor
185 */
186function Position( iDims, Vals )
179{ 187{
180 if( typeof iDims === 'string' ) 188 if( typeof iDims === 'string' )
181 { 189 {
@@ -263,7 +271,7 @@ Position.prototype.add = function add( iDim, iDelta )
263// 271//
264Position.prototype.translate = function translate( iDim, iDelta ) 272Position.prototype.translate = function translate( iDim, iDelta )
265{ 273{
266 let tmp = new Position( this.iDims, ...this.aiValues.slice() ); 274 let tmp = new Position( this.iDims, this.aiValues.slice() );
267 tmp.add( iDim, iDelta ); 275 tmp.add( iDim, iDelta );
268 return tmp; 276 return tmp;
269} 277}
@@ -273,7 +281,7 @@ Position.prototype.translate = function translate( iDim, iDelta )
273// 281//
274Position.prototype.copy = function translate() 282Position.prototype.copy = function translate()
275{ 283{
276 return new Position( this.iDims, ...this.aiValues.slice() ); 284 return new Position( this.iDims, this.aiValues.slice() );
277} 285}
278 286
279// 287//
@@ -309,14 +317,16 @@ Position.prototype.toString = function toString()
309 return ret; 317 return ret;
310} 318}
311 319
312// 320/**
313// Class: Map 321 * Class: MazeMap
314// 322 *
315// The maze itself. This doesn't do a whole lot on it's own except track data 323 * The maze itself. This doesn't do a whole lot on it's own except track data
316// and manage the player position and worms. The worms do the real work of 324 * and manage the player position and worms. The worms do the real work of
317// generating a maze. 325 * generating a maze.
318// 326 *
319function Map( Dimensions ) 327 * @constructor
328 */
329function MazeMap( Dimensions )
320{ 330{
321 // Store dimensional data 331 // Store dimensional data
322 this.Dimensions = Dimensions; 332 this.Dimensions = Dimensions;
@@ -345,7 +355,7 @@ function Map( Dimensions )
345// 355//
346// Get the number of dimensions in this maze. 356// Get the number of dimensions in this maze.
347// 357//
348Map.prototype.getDims = function getDims() 358MazeMap.prototype.getDims = function getDims()
349{ 359{
350 return this.Dimensions.getDims(); 360 return this.Dimensions.getDims();
351} 361}
@@ -353,7 +363,7 @@ Map.prototype.getDims = function getDims()
353// 363//
354// Get the size of the specified dimension. 364// Get the size of the specified dimension.
355// 365//
356Map.prototype.getSize = function getSize( iDim ) 366MazeMap.prototype.getSize = function getSize( iDim )
357{ 367{
358 return this.Dimensions.get( iDim ); 368 return this.Dimensions.get( iDim );
359} 369}
@@ -361,7 +371,7 @@ Map.prototype.getSize = function getSize( iDim )
361// 371//
362// Get a reference to the current player position in the maze. 372// Get a reference to the current player position in the maze.
363// 373//
364Map.prototype.getPlayerPos = function getPlayerPos() 374MazeMap.prototype.getPlayerPos = function getPlayerPos()
365{ 375{
366 return this.pPlayer; 376 return this.pPlayer;
367} 377}
@@ -369,7 +379,7 @@ Map.prototype.getPlayerPos = function getPlayerPos()
369// 379//
370// Replace the player position with a new position. 380// Replace the player position with a new position.
371// 381//
372Map.prototype.setPlayerPos = function setPlayerPos( pNewPos ) 382MazeMap.prototype.setPlayerPos = function setPlayerPos( pNewPos )
373{ 383{
374 this.pPlayer = pNewPos; 384 this.pPlayer = pNewPos;
375 this.ePlayerMoved.emit(); 385 this.ePlayerMoved.emit();
@@ -380,7 +390,7 @@ Map.prototype.setPlayerPos = function setPlayerPos( pNewPos )
380// (iDim). This takes walls and maze borders into account, and will not move 390// (iDim). This takes walls and maze borders into account, and will not move
381// the player in an "illegal" way. 391// the player in an "illegal" way.
382// 392//
383Map.prototype.movePlayer = function movePlayer( iDim, iDelta ) 393MazeMap.prototype.movePlayer = function movePlayer( iDim, iDelta )
384{ 394{
385 let cCur = this.get( this.pPlayer ); 395 let cCur = this.get( this.pPlayer );
386 396
@@ -407,7 +417,7 @@ Map.prototype.movePlayer = function movePlayer( iDim, iDelta )
407// 417//
408// Helper that determines if the provided position is inside the maze or not. 418// Helper that determines if the provided position is inside the maze or not.
409// 419//
410Map.prototype.isInside = function isInside( Position ) 420MazeMap.prototype.isInside = function isInside( Position )
411{ 421{
412 if( Position.getDims() != this.Dimensions.getDims() ) 422 if( Position.getDims() != this.Dimensions.getDims() )
413 { 423 {
@@ -433,7 +443,7 @@ Map.prototype.isInside = function isInside( Position )
433// one dimensional array coordinate. This is used to find the actual storage 443// one dimensional array coordinate. This is used to find the actual storage
434// location of cells internally. 444// location of cells internally.
435// 445//
436Map.prototype.getIndex = function getIndex( Position ) 446MazeMap.prototype.getIndex = function getIndex( Position )
437{ 447{
438 if( !this.isInside( Position ) ) 448 if( !this.isInside( Position ) )
439 { 449 {
@@ -453,7 +463,7 @@ Map.prototype.getIndex = function getIndex( Position )
453// 463//
454// Get a cell at the given Position. 464// Get a cell at the given Position.
455// 465//
456Map.prototype.get = function get( Position ) 466MazeMap.prototype.get = function get( Position )
457{ 467{
458 return this.aCell[this.getIndex( Position )]; 468 return this.aCell[this.getIndex( Position )];
459} 469}
@@ -463,7 +473,7 @@ Map.prototype.get = function get( Position )
463// and the loop chance (betweer 0.0 and 1.0). This returns the ID that the 473// and the loop chance (betweer 0.0 and 1.0). This returns the ID that the
464// added worm was assigned, which starts at one and goes up from there. 474// added worm was assigned, which starts at one and goes up from there.
465// 475//
466Map.prototype.addWorm = function addWorm( pStart, dLoopChance ) 476MazeMap.prototype.addWorm = function addWorm( pStart, dLoopChance )
467{ 477{
468 if( this.pPlayer === null ) 478 if( this.pPlayer === null )
469 { 479 {
@@ -493,7 +503,7 @@ Map.prototype.addWorm = function addWorm( pStart, dLoopChance )
493// At the moment this function assumes we have 2 worms and connects them 503// At the moment this function assumes we have 2 worms and connects them
494// automatically once it's done running. 504// automatically once it's done running.
495// 505//
496Map.prototype.buildMaze = function buildMaze() 506MazeMap.prototype.buildMaze = function buildMaze()
497{ 507{
498 do 508 do
499 { 509 {
@@ -516,7 +526,7 @@ Map.prototype.buildMaze = function buildMaze()
516// wall that seperates the longest combined pathway between the two, and opens 526// wall that seperates the longest combined pathway between the two, and opens
517// it up into a pathway. 527// it up into a pathway.
518// 528//
519Map.prototype.connect = function connect( iWormId1, iWormId2 ) 529MazeMap.prototype.connect = function connect( iWormId1, iWormId2 )
520{ 530{
521 let p = new Position( this.getDims() ); 531 let p = new Position( this.getDims() );
522 let pMax1 = null; 532 let pMax1 = null;
@@ -585,46 +595,50 @@ Map.prototype.connect = function connect( iWormId1, iWormId2 )
585 this.get( pMax2 ).iWalls |= (1<<oppositeDir(iDirMax)); 595 this.get( pMax2 ).iWalls |= (1<<oppositeDir(iDirMax));
586} 596}
587 597
588// 598/**
589// Class: Vector 599 * Class: Vector
590// 600 *
591// Simple helper class that stores a position and direction. 601 * Simple helper class that stores a position and direction.
592// 602 *
603 * @constructor
604 */
593function Vector( pPos, iDir ) 605function Vector( pPos, iDir )
594{ 606{
595 this.pPos = pPos; 607 this.pPos = pPos;
596 this.iDir = iDir; 608 this.iDir = iDir;
597} 609}
598 610
599// 611/**
600// Class: Worm 612 * Class: Worm
601// 613 *
602// The main workhorse (workworm?) of maze generation. The worm "eats" a path 614 * The main workhorse (workworm?) of maze generation. The worm "eats" a path
603// through the maze. The basic algorithm works as follows: 615 * through the maze. The basic algorithm works as follows:
604// 1. Search all directions around the current cell and list all unvisited 616 * 1. Search all directions around the current cell and list all unvisited
605// cells, the previous cell that we came from, and all cells that we 617 * cells, the previous cell that we came from, and all cells that we
606// created but are seperated from our current position by a wall. 618 * created but are seperated from our current position by a wall.
607// 2. If there are open cells, then we'll select one at random and travel to 619 * 2. If there are open cells, then we'll select one at random and travel to
608// it, but first: 620 * it, but first:
609// 2.a. If there are adjacent cells that we created, generate a random 621 * 2.a. If there are adjacent cells that we created, generate a random
610// number and compare it to the loop threshold. If it's smaller, 622 * number and compare it to the loop threshold. If it's smaller,
611// then select an adjacent room at random and break through the wall 623 * then select an adjacent room at random and break through the wall
612// to that room. 624 * to that room.
613// 3. If there are not open cells then travel back to the previous cell that 625 * 3. If there are not open cells then travel back to the previous cell that
614// we came from. Start over from #1 in this cell. 626 * we came from. Start over from #1 in this cell.
615// 4. If we reach the starting position again, then bailout and consider our 627 * 4. If we reach the starting position again, then bailout and consider our
616// work done. 628 * work done.
617// Every cell that a worm visits is marked with the worm's id (1 or greater), 629 * Every cell that a worm visits is marked with the worm's id (1 or greater),
618// and a distance value that increases by one for each cell away from the start 630 * and a distance value that increases by one for each cell away from the start
619// that we've traveled. When backtracking we update our current distance so 631 * that we've traveled. When backtracking we update our current distance so
620// that all distances are contiguous and increasing away from start. 632 * that all distances are contiguous and increasing away from start.
621// 633 *
622function Worm( iId, pStart, rMap, dLoopChance ) 634 * @constructor
635 */
636function Worm( iId, pStart, rMazeMap, dLoopChance )
623{ 637{
624 // Initialize basic state, we start with distance set to 1 638 // Initialize basic state, we start with distance set to 1
625 this.iId = iId; 639 this.iId = iId;
626 this.pPosition = pStart; 640 this.pPosition = pStart;
627 this.rMap = rMap; 641 this.rMazeMap = rMazeMap;
628 this.iDist = 1; 642 this.iDist = 1;
629 this.dLoopChance = dLoopChance; 643 this.dLoopChance = dLoopChance;
630 644
@@ -635,12 +649,12 @@ function Worm( iId, pStart, rMap, dLoopChance )
635 let iDirs = []; 649 let iDirs = [];
636 if( this.pPosition.get( 0 ) === 0 ) 650 if( this.pPosition.get( 0 ) === 0 )
637 iDirs.push( 1 ); 651 iDirs.push( 1 );
638 else if( this.pPosition.get( 0 ) === this.rMap.getSize( 0 )-1 ) 652 else if( this.pPosition.get( 0 ) === this.rMazeMap.getSize( 0 )-1 )
639 iDirs.push( 2 ); 653 iDirs.push( 2 );
640 654
641 if( this.pPosition.get( 1 ) === 0 ) 655 if( this.pPosition.get( 1 ) === 0 )
642 iDirs.push( 4 ); 656 iDirs.push( 4 );
643 else if( this.pPosition.get( 1 ) === this.rMap.getSize( 1 )-1 ) 657 else if( this.pPosition.get( 1 ) === this.rMazeMap.getSize( 1 )-1 )
644 iDirs.push( 8 ); 658 iDirs.push( 8 );
645 659
646 // Now that we know if we're near a wall in the first two demensions 660 // Now that we know if we're near a wall in the first two demensions
@@ -648,8 +662,8 @@ function Worm( iId, pStart, rMap, dLoopChance )
648 if( iDirs.length > 0 ) 662 if( iDirs.length > 0 )
649 { 663 {
650 // We are near a wall, pick a random wall to open a hole in 664 // We are near a wall, pick a random wall to open a hole in
651 this.rMap.get(this.pPosition).iWalls |= iDirs[lRand.randInt(iDirs.length)]; 665 this.rMazeMap.get(this.pPosition).iWalls |= iDirs[lRand.randInt(iDirs.length)];
652 this.rMap.get(this.pPosition).iPath = this.iId; 666 this.rMazeMap.get(this.pPosition).iPath = this.iId;
653 } 667 }
654} 668}
655 669
@@ -659,7 +673,7 @@ function Worm( iId, pStart, rMap, dLoopChance )
659Worm.prototype.timestep = function timestep() 673Worm.prototype.timestep = function timestep()
660{ 674{
661 // Handy to reference how many dimensions we have 675 // Handy to reference how many dimensions we have
662 let iDims = this.rMap.getDims(); 676 let iDims = this.rMazeMap.getDims();
663 677
664 // Possible directions 678 // Possible directions
665 let pDirs = []; 679 let pDirs = [];
@@ -668,16 +682,16 @@ Worm.prototype.timestep = function timestep()
668 let cCur; 682 let cCur;
669 for(;;) 683 for(;;)
670 { 684 {
671 cCur = this.rMap.get( this.pPosition ); 685 cCur = this.rMazeMap.get( this.pPosition );
672 let pBack = null; 686 let pBack = null;
673 pLoopDirs = []; 687 pLoopDirs = [];
674 for( let j = 0; j < iDims; j++ ) 688 for( let j = 0; j < iDims; j++ )
675 { 689 {
676 let iSize = this.rMap.getSize( j ); 690 let iSize = this.rMazeMap.getSize( j );
677 let pPos = this.pPosition.translate( j, -1 ); 691 let pPos = this.pPosition.translate( j, -1 );
678 if( pPos.get( j ) >= 0 ) 692 if( pPos.get( j ) >= 0 )
679 { 693 {
680 let xCell = this.rMap.get( pPos ); 694 let xCell = this.rMazeMap.get( pPos );
681 if( xCell.iPath === 0 ) 695 if( xCell.iPath === 0 )
682 { 696 {
683 pDirs.push( new Vector( pPos, j*2 ) ); 697 pDirs.push( new Vector( pPos, j*2 ) );
@@ -697,7 +711,7 @@ Worm.prototype.timestep = function timestep()
697 pPos = this.pPosition.translate( j, 1 ); 711 pPos = this.pPosition.translate( j, 1 );
698 if( pPos.get( j ) < iSize ) 712 if( pPos.get( j ) < iSize )
699 { 713 {
700 let xCell = this.rMap.get( pPos ); 714 let xCell = this.rMazeMap.get( pPos );
701 if( xCell.iPath === 0 ) 715 if( xCell.iPath === 0 )
702 { 716 {
703 pDirs.push( new Vector( pPos, j*2+1 ) ); 717 pDirs.push( new Vector( pPos, j*2+1 ) );
@@ -733,10 +747,10 @@ Worm.prototype.timestep = function timestep()
733 } 747 }
734 } 748 }
735 749
736 cCur = this.rMap.get( this.pPosition ); 750 cCur = this.rMazeMap.get( this.pPosition );
737 let iSel = lRand.randInt( pDirs.length ); 751 let iSel = lRand.randInt( pDirs.length );
738 cCur.iWalls |= (1<<pDirs[iSel].iDir); 752 cCur.iWalls |= (1<<pDirs[iSel].iDir);
739 let cNext = this.rMap.get( pDirs[iSel].pPos ); 753 let cNext = this.rMazeMap.get( pDirs[iSel].pPos );
740 cNext.iWalls |= (1<<oppositeDir( pDirs[iSel].iDir )); 754 cNext.iWalls |= (1<<oppositeDir( pDirs[iSel].iDir ));
741 cNext.iDist = ++this.iDist; 755 cNext.iDist = ++this.iDist;
742 cNext.iPath = this.iId; 756 cNext.iPath = this.iId;
@@ -747,21 +761,23 @@ Worm.prototype.timestep = function timestep()
747 { 761 {
748 iSel = pLoopDirs[lRand.randInt( pLoopDirs.length )]; 762 iSel = pLoopDirs[lRand.randInt( pLoopDirs.length )];
749 cCur.iWalls |= (1<<iSel.iDir); 763 cCur.iWalls |= (1<<iSel.iDir);
750 cNext = this.rMap.get( iSel.pPos ); 764 cNext = this.rMazeMap.get( iSel.pPos );
751 cNext.iWalls |= (1<<oppositeDir( iSel.iDir )); 765 cNext.iWalls |= (1<<oppositeDir( iSel.iDir ));
752 } 766 }
753 767
754 return true; 768 return true;
755} 769}
756 770
757// 771/**
758// Class: Render 772 * Class: Render
759// 773 *
760// Base class of render classes. Doesn't do anything on it's own. 774 * Base class of render classes. Doesn't do anything on it's own.
761// 775 *
762function Render( rMap, eMazeContainer ) 776 * @constructor
777 */
778function Render( rMazeMap, eMazeContainer )
763{ 779{
764 this.rMap = rMap; 780 this.rMazeMap = rMazeMap;
765 this.eMazeContainer = eMazeContainer; 781 this.eMazeContainer = eMazeContainer;
766} 782}
767 783
@@ -773,30 +789,32 @@ Render.prototype.render = function render()
773{ 789{
774} 790}
775 791
776// 792/**
777// Class: RenderCanvas2D 793 * Class: RenderCanvas2D
778// 794 *
779// Our main render class. This generates a single 2d slice of the current maze 795 * Our main render class. This generates a single 2d slice of the current maze
780// on the "floor" that the player is currently on. It also generates and 796 * on the "floor" that the player is currently on. It also generates and
781// manages buttons you can use to interact with the maze. 797 * manages buttons you can use to interact with the maze.
782// 798 *
783function RenderCanvas2D( rMap, params ) // eMazeContainer, eUIContainer ) 799 * @constructor
800 */
801function RenderCanvas2D( rMazeMap, params ) // eMazeContainer, eUIContainer )
784{ 802{
785 let eMazeContainer = document.getElementById(params['maze']); 803 let eMazeContainer = document.getElementById(params['maze']);
786 let eUIContainer = document.getElementById(params['buttons']); 804 let eUIContainer = document.getElementById(params['buttons']);
787 let eReadoutBox = document.getElementById(params['readout']); 805 let eReadoutBox = document.getElementById(params['readout']);
788 806
789 Render.call( this, rMap, eMazeContainer ); 807 Render.call( this, rMazeMap, eMazeContainer );
790 this.rMap.ePlayerMoved.connect( 808 this.rMazeMap.ePlayerMoved.connect(
791 RenderCanvas2D.prototype.render.bind( this ) 809 RenderCanvas2D.prototype.render.bind( this )
792 ); 810 );
793 this.rMap.ePlayerMoved.connect( 811 this.rMazeMap.ePlayerMoved.connect(
794 RenderCanvas2D.prototype.updateButtons.bind( this ) 812 RenderCanvas2D.prototype.updateButtons.bind( this )
795 ); 813 );
796 this.rMap.ePlayerMoved.connect( 814 this.rMazeMap.ePlayerMoved.connect(
797 RenderCanvas2D.prototype.updateReadout.bind( this ) 815 RenderCanvas2D.prototype.updateReadout.bind( this )
798 ); 816 );
799 this.rMap.eVictory.connect( 817 this.rMazeMap.eVictory.connect(
800 RenderCanvas2D.prototype.setVictory.bind( this ) 818 RenderCanvas2D.prototype.setVictory.bind( this )
801 ); 819 );
802 820
@@ -804,10 +822,10 @@ function RenderCanvas2D( rMap, params ) // eMazeContainer, eUIContainer )
804 this.ctx = null; 822 this.ctx = null;
805 this.isSolved = false; 823 this.isSolved = false;
806 824
807 this.pExtPosition = new Position( rMap.getDims() ); 825 this.pExtPosition = new Position( rMazeMap.getDims() );
808 826
809 this.iIconSquare = Math.ceil( 827 this.iIconSquare = Math.ceil(
810 Math.sqrt((this.rMap.getDims()-2)*2 + 1) 828 Math.sqrt((this.rMazeMap.getDims()-2)*2 + 1)
811 ); 829 );
812 830
813 let iTargetSize = eMazeContainer.clientWidth; 831 let iTargetSize = eMazeContainer.clientWidth;
@@ -830,7 +848,7 @@ function RenderCanvas2D( rMap, params ) // eMazeContainer, eUIContainer )
830 this.iBorder = 3; 848 this.iBorder = 3;
831 this.iIconSize = Math.floor( 849 this.iIconSize = Math.floor(
832 ( 850 (
833 (iTargetSize/this.rMap.getSize( 0 )) - 851 (iTargetSize/this.rMazeMap.getSize( 0 )) -
834 3 - (this.iIconSquare*3) 852 3 - (this.iIconSquare*3)
835 )/this.iIconSquare 853 )/this.iIconSquare
836 ); 854 );
@@ -844,8 +862,8 @@ function RenderCanvas2D( rMap, params ) // eMazeContainer, eUIContainer )
844 this.iIconSquare*(this.iIconSize+this.iBorder); 862 this.iIconSquare*(this.iIconSize+this.iBorder);
845 863
846 this.eCanvas = document.createElement('canvas'); 864 this.eCanvas = document.createElement('canvas');
847 this.eCanvas.width = this.iCellSize*this.rMap.getSize( 0 ); 865 this.eCanvas.width = this.iCellSize*this.rMazeMap.getSize( 0 );
848 this.eCanvas.height = this.iCellSize*this.rMap.getSize( 1 ); 866 this.eCanvas.height = this.iCellSize*this.rMazeMap.getSize( 1 );
849 eMazeContainer.appendChild( this.eCanvas ); 867 eMazeContainer.appendChild( this.eCanvas );
850 this.ctx = this.eCanvas.getContext("2d"); 868 this.ctx = this.eCanvas.getContext("2d");
851 this.ctx.lineWidth = 1.0; 869 this.ctx.lineWidth = 1.0;
@@ -872,15 +890,15 @@ function RenderCanvas2D( rMap, params ) // eMazeContainer, eUIContainer )
872 cardRow.appendChild( document.createElement('td') ); 890 cardRow.appendChild( document.createElement('td') );
873 cardTd = document.createElement('td'); 891 cardTd = document.createElement('td');
874 this.aMoveButtons[2] = cardTd.appendChild( 892 this.aMoveButtons[2] = cardTd.appendChild(
875 createMoveButton( this.rMap, 1, -1, "North" ) 893 createMoveButton( this.rMazeMap, 1, -1, "North" )
876 ); 894 );
877 cardRow.appendChild( cardTd ); 895 cardRow.appendChild( cardTd );
878 cardRow.appendChild( document.createElement('td') ); 896 cardRow.appendChild( document.createElement('td') );
879 if( this.rMap.getDims() >= 3 ) 897 if( this.rMazeMap.getDims() >= 3 )
880 { 898 {
881 cardTd = document.createElement('td'); 899 cardTd = document.createElement('td');
882 this.aMoveButtons[4] = cardTd.appendChild( 900 this.aMoveButtons[4] = cardTd.appendChild(
883 createMoveButton( this.rMap, 2, -1, "Up (^)" ) 901 createMoveButton( this.rMazeMap, 2, -1, "Up (^)" )
884 ); 902 );
885 cardRow.appendChild( cardTd ); 903 cardRow.appendChild( cardTd );
886 } 904 }
@@ -889,16 +907,16 @@ function RenderCanvas2D( rMap, params ) // eMazeContainer, eUIContainer )
889 cardTbl.appendChild( cardRow ); 907 cardTbl.appendChild( cardRow );
890 cardTd = document.createElement('td'); 908 cardTd = document.createElement('td');
891 this.aMoveButtons[0] = cardTd.appendChild( 909 this.aMoveButtons[0] = cardTd.appendChild(
892 createMoveButton( this.rMap, 0, -1, "West" ) 910 createMoveButton( this.rMazeMap, 0, -1, "West" )
893 ); 911 );
894 cardRow.appendChild( cardTd ); 912 cardRow.appendChild( cardTd );
895 cardRow.appendChild( document.createElement('td') ); 913 cardRow.appendChild( document.createElement('td') );
896 cardTd = document.createElement('td'); 914 cardTd = document.createElement('td');
897 this.aMoveButtons[1] = cardTd.appendChild( 915 this.aMoveButtons[1] = cardTd.appendChild(
898 createMoveButton( this.rMap, 0, 1, "East" ) 916 createMoveButton( this.rMazeMap, 0, 1, "East" )
899 ); 917 );
900 cardRow.appendChild( cardTd ); 918 cardRow.appendChild( cardTd );
901 if( this.rMap.getDims() >= 3 ) 919 if( this.rMazeMap.getDims() >= 3 )
902 { 920 {
903 cardRow.appendChild( document.createElement('td') ); 921 cardRow.appendChild( document.createElement('td') );
904 } 922 }
@@ -908,38 +926,38 @@ function RenderCanvas2D( rMap, params ) // eMazeContainer, eUIContainer )
908 cardRow.appendChild( document.createElement('td') ); 926 cardRow.appendChild( document.createElement('td') );
909 cardTd = document.createElement('td'); 927 cardTd = document.createElement('td');
910 this.aMoveButtons[3] = cardTd.appendChild( 928 this.aMoveButtons[3] = cardTd.appendChild(
911 createMoveButton( this.rMap, 1, 1, "South" ) 929 createMoveButton( this.rMazeMap, 1, 1, "South" )
912 ); 930 );
913 cardRow.appendChild( cardTd ); 931 cardRow.appendChild( cardTd );
914 cardRow.appendChild( document.createElement('td') ); 932 cardRow.appendChild( document.createElement('td') );
915 if( this.rMap.getDims() >= 3 ) 933 if( this.rMazeMap.getDims() >= 3 )
916 { 934 {
917 cardTd = document.createElement('td'); 935 cardTd = document.createElement('td');
918 this.aMoveButtons[5] = cardTd.appendChild( 936 this.aMoveButtons[5] = cardTd.appendChild(
919 createMoveButton( this.rMap, 2, 1, "Down (v)" ) 937 createMoveButton( this.rMazeMap, 2, 1, "Down (v)" )
920 ); 938 );
921 cardRow.appendChild( cardTd ); 939 cardRow.appendChild( cardTd );
922 } 940 }
923 941
924 this.btnBox.appendChild( cardTbl ); 942 this.btnBox.appendChild( cardTbl );
925 943
926 if( this.rMap.getDims() >= 3 ) 944 if( this.rMazeMap.getDims() >= 3 )
927 { 945 {
928 cardTbl = document.createElement('table'); 946 cardTbl = document.createElement('table');
929 for( let j = 3; j < this.rMap.getDims(); j++ ) 947 for( let j = 3; j < this.rMazeMap.getDims(); j++ )
930 { 948 {
931 cardRow = document.createElement('tr'); 949 cardRow = document.createElement('tr');
932 cardTbl.appendChild( cardRow ); 950 cardTbl.appendChild( cardRow );
933 951
934 cardTd = document.createElement('td'); 952 cardTd = document.createElement('td');
935 this.aMoveButtons[j*2] = cardTd.appendChild( 953 this.aMoveButtons[j*2] = cardTd.appendChild(
936 createMoveButton( this.rMap, j, -1, (j+1) + '-' ) 954 createMoveButton( this.rMazeMap, j, -1, (j+1) + '-' )
937 ); 955 );
938 cardRow.appendChild( cardTd ); 956 cardRow.appendChild( cardTd );
939 957
940 cardTd = document.createElement('td'); 958 cardTd = document.createElement('td');
941 this.aMoveButtons[j*2+1] = cardTd.appendChild( 959 this.aMoveButtons[j*2+1] = cardTd.appendChild(
942 createMoveButton( this.rMap, j, 1, (j+1) + '+' ) 960 createMoveButton( this.rMazeMap, j, 1, (j+1) + '+' )
943 ); 961 );
944 cardRow.appendChild( cardTd ); 962 cardRow.appendChild( cardTd );
945 } 963 }
@@ -970,10 +988,10 @@ RenderCanvas2D.prototype.render = function render()
970 this.ctx.beginPath(); 988 this.ctx.beginPath();
971 989
972 let p; 990 let p;
973 if( this.rMap.pPlayer === null ) 991 if( this.rMazeMap.pPlayer === null )
974 p = this.pExtPosition.copy(); 992 p = this.pExtPosition.copy();
975 else 993 else
976 p = this.rMap.pPlayer.copy(); 994 p = this.rMazeMap.pPlayer.copy();
977 995
978 let iPlayerIcon = 996 let iPlayerIcon =
979 Math.floor(this.iIconSquare*0.5) + 997 Math.floor(this.iIconSquare*0.5) +
@@ -981,29 +999,29 @@ RenderCanvas2D.prototype.render = function render()
981 999
982 this.ctx.beginPath(); 1000 this.ctx.beginPath();
983 this.ctx.strokeStyle = 'whitesmoke'; 1001 this.ctx.strokeStyle = 'whitesmoke';
984 for( let x = 0; x < this.rMap.getSize( 0 ); x++ ) 1002 for( let x = 0; x < this.rMazeMap.getSize( 0 ); x++ )
985 { 1003 {
986 this.ctx.moveTo( x*iSize, 0 ); 1004 this.ctx.moveTo( x*iSize, 0 );
987 this.ctx.lineTo( x*iSize, this.rMap.getSize( 1 )*iSize ); 1005 this.ctx.lineTo( x*iSize, this.rMazeMap.getSize( 1 )*iSize );
988 } 1006 }
989 for( let y = 0; y < this.rMap.getSize( 1 ); y++ ) 1007 for( let y = 0; y < this.rMazeMap.getSize( 1 ); y++ )
990 { 1008 {
991 this.ctx.moveTo( 0, y*iSize ); 1009 this.ctx.moveTo( 0, y*iSize );
992 this.ctx.lineTo( this.rMap.getSize( 0 )*iSize, y*iSize ); 1010 this.ctx.lineTo( this.rMazeMap.getSize( 0 )*iSize, y*iSize );
993 } 1011 }
994 this.ctx.stroke(); 1012 this.ctx.stroke();
995 1013
996 this.ctx.beginPath(); 1014 this.ctx.beginPath();
997 this.ctx.strokeStyle = 'black'; 1015 this.ctx.strokeStyle = 'black';
998 for( let x = 0; x < this.rMap.getSize( 0 ); x++ ) 1016 for( let x = 0; x < this.rMazeMap.getSize( 0 ); x++ )
999 { 1017 {
1000 for( let y = 0; y < this.rMap.getSize( 1 ); y++ ) 1018 for( let y = 0; y < this.rMazeMap.getSize( 1 ); y++ )
1001 { 1019 {
1002 p.set( 0, x ); 1020 p.set( 0, x );
1003 p.set( 1, y ); 1021 p.set( 1, y );
1004 let c = this.rMap.get( p ); 1022 let c = this.rMazeMap.get( p );
1005 1023
1006 if( p.equals( this.rMap.pGoal ) ) 1024 if( p.equals( this.rMazeMap.pGoal ) )
1007 { 1025 {
1008 let oldStyle = this.ctx.fillStyle; 1026 let oldStyle = this.ctx.fillStyle;
1009 this.ctx.fillStyle = 'palegreen'; 1027 this.ctx.fillStyle = 'palegreen';
@@ -1034,7 +1052,7 @@ RenderCanvas2D.prototype.render = function render()
1034 1052
1035 // Extended dimenisons (above 2 :-P) 1053 // Extended dimenisons (above 2 :-P)
1036 let iIcon = 0; 1054 let iIcon = 0;
1037 for( let ed = 2; ed < this.rMap.getDims(); ed++ ) 1055 for( let ed = 2; ed < this.rMazeMap.getDims(); ed++ )
1038 { 1056 {
1039 if( iIcon == iPlayerIcon ) 1057 if( iIcon == iPlayerIcon )
1040 iIcon++; 1058 iIcon++;
@@ -1057,13 +1075,13 @@ RenderCanvas2D.prototype.render = function render()
1057 this.ctx.stroke(); 1075 this.ctx.stroke();
1058 1076
1059 // Draw the player 1077 // Draw the player
1060 if( this.rMap.pPlayer !== null ) 1078 if( this.rMazeMap.pPlayer !== null )
1061 { 1079 {
1062 let bx = this.rMap.pPlayer.get(0)*iSize + 1080 let bx = this.rMazeMap.pPlayer.get(0)*iSize +
1063 this.iBorder + Math.floor(iPlayerIcon%this.iIconSquare)*(this.iBorder+this.iIconSize); 1081 this.iBorder + Math.floor(iPlayerIcon%this.iIconSquare)*(this.iBorder+this.iIconSize);
1064 let by = this.rMap.pPlayer.get(1)*iSize + 1082 let by = this.rMazeMap.pPlayer.get(1)*iSize +
1065 this.iBorder + Math.floor(iPlayerIcon/this.iIconSquare)*(this.iBorder+this.iIconSize); 1083 this.iBorder + Math.floor(iPlayerIcon/this.iIconSquare)*(this.iBorder+this.iIconSize);
1066 this.rMap.pPlayer.equals( p ); 1084 this.rMazeMap.pPlayer.equals( p );
1067 this.ctx.beginPath(); 1085 this.ctx.beginPath();
1068 this.ctx.ellipse( 1086 this.ctx.ellipse(
1069 bx+this.iIconSize*0.5, by+this.iIconSize*0.5, 1087 bx+this.iIconSize*0.5, by+this.iIconSize*0.5,
@@ -1143,8 +1161,8 @@ RenderCanvas2D.prototype.renderDirIcon = function renderDirIcon(
1143// 1161//
1144RenderCanvas2D.prototype.updateButtons = function updateButtons() 1162RenderCanvas2D.prototype.updateButtons = function updateButtons()
1145{ 1163{
1146 let c = this.rMap.get( this.rMap.pPlayer ); 1164 let c = this.rMazeMap.get( this.rMazeMap.pPlayer );
1147 for( let j = 0; j < this.rMap.getDims()*2; j++ ) 1165 for( let j = 0; j < this.rMazeMap.getDims()*2; j++ )
1148 { 1166 {
1149 this.aMoveButtons[j].disabled = (c.iWalls&(1<<j)) === 0; 1167 this.aMoveButtons[j].disabled = (c.iWalls&(1<<j)) === 0;
1150 } 1168 }
@@ -1156,13 +1174,13 @@ RenderCanvas2D.prototype.updateButtons = function updateButtons()
1156// 1174//
1157RenderCanvas2D.prototype.updateReadout = function updateReadout() 1175RenderCanvas2D.prototype.updateReadout = function updateReadout()
1158{ 1176{
1159 if( this.rMap.getDims() <= 2 ) 1177 if( this.rMazeMap.getDims() <= 2 )
1160 return; 1178 return;
1161 1179
1162 let text = 'Floor: ' + (this.rMap.pPlayer.get( 2 )+1); 1180 let text = 'Floor: ' + (this.rMazeMap.pPlayer.get( 2 )+1);
1163 for( let j = 3; j < this.rMap.getDims(); j++ ) 1181 for( let j = 3; j < this.rMazeMap.getDims(); j++ )
1164 { 1182 {
1165 text += ', ' + (this.rMap.pPlayer.get( j )+1); 1183 text += ', ' + (this.rMazeMap.pPlayer.get( j )+1);
1166 } 1184 }
1167 1185
1168 this.readoutNode.textContent = text; 1186 this.readoutNode.textContent = text;
@@ -1192,7 +1210,7 @@ RenderCanvas2D.prototype.setVictory = function setVictory()
1192 1210
1193function lostInit( properties ) 1211function lostInit( properties )
1194{ 1212{
1195 let p = new Position( 4, 3, 3, 3, 3 ); 1213 let p = new Position( 4, [3, 3, 3, 3] );
1196 1214
1197 if( document.location.search !== '' ) 1215 if( document.location.search !== '' )
1198 { 1216 {
@@ -1215,9 +1233,9 @@ function lostInit( properties )
1215 } 1233 }
1216 } 1234 }
1217 1235
1218 let m = new Map( p ); 1236 let m = new MazeMap( p );
1219 let exit1 = new Position( p.getDims() ); 1237 let exit1 = new Position( p.getDims(), null );
1220 let exit2 = new Position( p.getDims() ); 1238 let exit2 = new Position( p.getDims(), null );
1221 exit2.set( 1, p.get( 1 )-1 ); 1239 exit2.set( 1, p.get( 1 )-1 );
1222 m.addWorm( exit1, 0.05 ); 1240 m.addWorm( exit1, 0.05 );
1223 m.addWorm( exit2, 0.05 ); 1241 m.addWorm( exit2, 0.05 );
@@ -1259,3 +1277,6 @@ function lostInit( properties )
1259 d.appendChild(dLink); 1277 d.appendChild(dLink);
1260} 1278}
1261 1279
1280// These are needed to export symbols we want to keep post minification
1281window['lostInit'] = lostInit;
1282window['RenderCanvas2D'] = RenderCanvas2D;