summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <Mike.Buland@mjfirm.com>2016-10-24 15:05:46 -0600
committerMike Buland <Mike.Buland@mjfirm.com>2016-10-24 15:05:46 -0600
commitc8b8770f49883f94678f215b98ece3d67f8aa9ef (patch)
tree673879b7d8615f3f298f55a48f791e787eb81dc1
parent39d593054de993469809170ebf53a231caac92fb (diff)
downloadlost-c8b8770f49883f94678f215b98ece3d67f8aa9ef.tar.gz
lost-c8b8770f49883f94678f215b98ece3d67f8aa9ef.tar.bz2
lost-c8b8770f49883f94678f215b98ece3d67f8aa9ef.tar.xz
lost-c8b8770f49883f94678f215b98ece3d67f8aa9ef.zip
Mainly just lots and lots of comments.
-rw-r--r--js/lost.html4
-rw-r--r--js/lost.js305
2 files changed, 248 insertions, 61 deletions
diff --git a/js/lost.html b/js/lost.html
index d4443ab..c634ba2 100644
--- a/js/lost.html
+++ b/js/lost.html
@@ -10,7 +10,7 @@
10 <div id="maze-box"></div> 10 <div id="maze-box"></div>
11 <div id="button-box"></div> 11 <div id="button-box"></div>
12 </div> 12 </div>
13 <div id="floor-box"></div> 13 <div id="floor-box"></div>
14 <div class="float-clear"></div> 14 <div class="float-clear"></div>
15 <div id="editor-cont"> 15 <div id="editor-cont">
16 <p>Provide a number below for each dimension in the new maze. The numbers are the size of each dimension. Entering "10, 3" will create a maze that is 10 wide and 3 tall. Entering "5, 5, 5, 5, 5" will create a 5 dimensional maze, every dimension will be 5 wide.</p> 16 <p>Provide a number below for each dimension in the new maze. The numbers are the size of each dimension. Entering "10, 3" will create a maze that is 10 wide and 3 tall. Entering "5, 5, 5, 5, 5" will create a 5 dimensional maze, every dimension will be 5 wide.</p>
@@ -21,7 +21,7 @@
21 <script type="text/javascript"> 21 <script type="text/javascript">
22lostInit({ 22lostInit({
23 'render': { 23 'render': {
24 'name': 'RenderCanvas2D', 24 'name': RenderCanvas2D,
25 'params': { 25 'params': {
26 'maze': 'maze-box', 26 'maze': 'maze-box',
27 'buttons': 'button-box', 27 'buttons': 'button-box',
diff --git a/js/lost.js b/js/lost.js
index 20311f2..022c10b 100644
--- a/js/lost.js
+++ b/js/lost.js
@@ -5,27 +5,94 @@
5// Helper functions 5// Helper functions
6// 6//
7 7
8// Return the id for the opposite direction of the direction given.
9function oppositeDir( iDir )
10{
11 if( iDir%2 === 1 )
12 return iDir-1;
13 return iDir+1;
14}
15
16//
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
19// dimension, and in the specified direction.
20//
21// The button created is then returned.
22//
23function createMoveButton( rMap, iDim, iDir, sLabel )
24{
25 let btn = document.createElement('button');
26 btn.addEventListener(
27 'click',
28 Map.prototype.movePlayer.bind(
29 rMap,
30 iDim,
31 iDir
32 )
33 );
34 if( sLabel === null || sLabel === '' )
35 {
36 btn.appendChild(
37 document.createTextNode('Dim ' + (j+1) + ': -')
38 );
39 }
40 else
41 {
42 btn.appendChild(
43 document.createTextNode( sLabel )
44 );
45 }
46 return btn;
47}
48
8// 49//
9// Class: RandomLcg 50// Class: RandomLcg
10// 51//
52// This implements a Linear Congruential Generator PRNG. Is this the best PRNG?
53// Nope! Is it decently random for our purposes, sure.
54//
55// Why was this implemented? I wanted to be able to share mazes, in order to do
56// 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).
58// 2. To be sure that the same algorithm would be used on every version of
59// every browser.
60//
61// Unfortunately JavaScript doesn't gurantee either of these things, so instead
62// of writing a CMWC and using a bunch of memory I just used the settings from
63// the glibc random function and here we are.
64//
11function RandomLcg() 65function RandomLcg()
12{ 66{
67 // Current state
13 this.iState = 0; 68 this.iState = 0;
69
70 // Initial seed, remember this so we can display it easily later.
14 this.iSeed = 0; 71 this.iSeed = 0;
15 72
73 // Set the seed randomly to start.
16 this.inventSeed(); 74 this.inventSeed();
17} 75}
18 76
77//
78// Replace the current seed and reset the state.
79//
19RandomLcg.prototype.setSeed = function setSeed( iSeed ) 80RandomLcg.prototype.setSeed = function setSeed( iSeed )
20{ 81{
21 this.iState = this.iSeed = iSeed; 82 this.iState = this.iSeed = iSeed;
22} 83}
23 84
85//
86// Get the seed that was initially used on this random number generator.
87//
24RandomLcg.prototype.getSeed = function getSeed() 88RandomLcg.prototype.getSeed = function getSeed()
25{ 89{
26 return this.iSeed; 90 return this.iSeed;
27} 91}
28 92
93//
94// Make up a seed.
95//
29RandomLcg.prototype.inventSeed = function inventSeed() 96RandomLcg.prototype.inventSeed = function inventSeed()
30{ 97{
31 // Based on my reading it's safest to assume that we can get 16 bits worth 98 // Based on my reading it's safest to assume that we can get 16 bits worth
@@ -37,48 +104,52 @@ RandomLcg.prototype.inventSeed = function inventSeed()
37 ); 104 );
38} 105}
39 106
107//
108// Get us a random number between 0 and 1.0, exclusive of the upper bound.
109//
40RandomLcg.prototype.random = function random() 110RandomLcg.prototype.random = function random()
41{ 111{
42 this.iState = ((this.iState * 1103515245) + 12345) & 0x7fffffff; 112 this.iState = ((this.iState * 1103515245) + 12345) & 0x7fffffff;
43 return this.iState/(0x7fffffff+1); 113 return this.iState/(0x7fffffff+1);
44} 114}
45 115
116//
117// Get us a random integer between 0 and max, exclusive of the upper bound.
118//
46RandomLcg.prototype.randInt = function randInt( max ) 119RandomLcg.prototype.randInt = function randInt( max )
47{ 120{
48 return Math.floor(this.random() * max); 121 return Math.floor(this.random() * max);
49} 122}
50 123
124// Lets just build a shared prng object to use all over.
51let lRand = new RandomLcg(); 125let lRand = new RandomLcg();
52 126
53// Just return a random integer between 0 and max, exclusive on the upper bound.
54function randInt( max )
55{
56 return lRand.randInt( max );
57// return Math.floor(Math.random() * max);
58}
59
60// Return the id for the opposite direction of the direction given.
61function oppositeDir( iDir )
62{
63 if( iDir%2 === 1 )
64 return iDir-1;
65 return iDir+1;
66}
67
68// 127//
69// Class: Signal 128// Class: Signal
70// 129//
130// 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
132// them en-masse whenever the signal is fired.
133//
71function Signal() 134function Signal()
72{ 135{
73 this.aSlot = new Array(); 136 this.aSlot = new Array();
74} 137}
75 138
139//
140// Connect this signal to a new slot (function to call). I recommend using bind
141// to create valid object-function references that have state supposed to
142// disembodied functions.
143//
76Signal.prototype.connect = function connect( fSlot ) 144Signal.prototype.connect = function connect( fSlot )
77{ 145{
78 this.aSlot.push( fSlot ); 146 this.aSlot.push( fSlot );
79} 147}
80 148
81Signal.prototype.call = function call() 149//
150// Trigger the signal, and notify all slots bound to this signal.
151//
152Signal.prototype.emit = function emit()
82{ 153{
83 for( let j = 0; j < this.aSlot.length; j++ ) 154 for( let j = 0; j < this.aSlot.length; j++ )
84 { 155 {
@@ -89,6 +160,8 @@ Signal.prototype.call = function call()
89// 160//
90// Class: Cell 161// Class: Cell
91// 162//
163// Simple container that tracks info about a cell in the maze.
164//
92function Cell() 165function Cell()
93{ 166{
94 this.iDist = 0; 167 this.iDist = 0;
@@ -99,6 +172,9 @@ function Cell()
99// 172//
100// Class: Position 173// Class: Position
101// 174//
175// 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.
177//
102function Position( iDims, ...Vals ) 178function Position( iDims, ...Vals )
103{ 179{
104 if( typeof iDims === 'string' ) 180 if( typeof iDims === 'string' )
@@ -146,27 +222,45 @@ function Position( iDims, ...Vals )
146 } 222 }
147} 223}
148 224
225//
226// Get the number of dimensions defined in this position.
227//
149Position.prototype.getDims = function getDims() 228Position.prototype.getDims = function getDims()
150{ 229{
151 return this.iDims; 230 return this.iDims;
152} 231}
153 232
233//
234// Get the value of one dimension of the coordinate in this position.
235//
154Position.prototype.get = function get( iDim ) 236Position.prototype.get = function get( iDim )
155{ 237{
156 return this.aiValues[iDim]; 238 return this.aiValues[iDim];
157} 239}
158 240
241//
242// Set the value of one dimension of the coordinate in this position.
243// This modifies the position in place.
244//
159Position.prototype.set = function set( iDim, iVal ) 245Position.prototype.set = function set( iDim, iVal )
160{ 246{
161 this.aiValues[iDim] = iVal; 247 this.aiValues[iDim] = iVal;
162} 248}
163 249
250//
251// Apply a delta to the specified dimension in the current position.
252// This modifies the position in place.
253//
164Position.prototype.add = function add( iDim, iDelta ) 254Position.prototype.add = function add( iDim, iDelta )
165{ 255{
166 this.aiValues[iDim] += iDelta; 256 this.aiValues[iDim] += iDelta;
167 return this.aiValues[iDim]; 257 return this.aiValues[iDim];
168} 258}
169 259
260//
261// Copy the current position object and return one with a modified value in
262// the specified dimension.
263//
170Position.prototype.translate = function translate( iDim, iDelta ) 264Position.prototype.translate = function translate( iDim, iDelta )
171{ 265{
172 let tmp = new Position( this.iDims, ...this.aiValues.slice() ); 266 let tmp = new Position( this.iDims, ...this.aiValues.slice() );
@@ -174,11 +268,18 @@ Position.prototype.translate = function translate( iDim, iDelta )
174 return tmp; 268 return tmp;
175} 269}
176 270
271//
272// Return an exact copy of this position object.
273//
177Position.prototype.copy = function translate() 274Position.prototype.copy = function translate()
178{ 275{
179 return new Position( this.iDims, ...this.aiValues.slice() ); 276 return new Position( this.iDims, ...this.aiValues.slice() );
180} 277}
181 278
279//
280// Compare two position objects for equality. Return true if they are the same,
281// false otherwise.
282//
182Position.prototype.equals = function equals( rhs ) 283Position.prototype.equals = function equals( rhs )
183{ 284{
184 if( this.iDims != rhs.iDims && 285 if( this.iDims != rhs.iDims &&
@@ -194,6 +295,9 @@ Position.prototype.equals = function equals( rhs )
194 return true; 295 return true;
195} 296}
196 297
298//
299// Converts the position to a nicely formatted string of numbers.
300//
197Position.prototype.toString = function toString() 301Position.prototype.toString = function toString()
198{ 302{
199 let ret = this.aiValues[0].toString(); 303 let ret = this.aiValues[0].toString();
@@ -208,6 +312,10 @@ Position.prototype.toString = function toString()
208// 312//
209// Class: Map 313// Class: Map
210// 314//
315// 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
317// generating a maze.
318//
211function Map( Dimensions ) 319function Map( Dimensions )
212{ 320{
213 // Store dimensional data 321 // Store dimensional data
@@ -234,27 +342,44 @@ function Map( Dimensions )
234 } 342 }
235} 343}
236 344
345//
346// Get the number of dimensions in this maze.
347//
237Map.prototype.getDims = function getDims() 348Map.prototype.getDims = function getDims()
238{ 349{
239 return this.Dimensions.getDims(); 350 return this.Dimensions.getDims();
240} 351}
241 352
353//
354// Get the size of the specified dimension.
355//
242Map.prototype.getSize = function getSize( iDim ) 356Map.prototype.getSize = function getSize( iDim )
243{ 357{
244 return this.Dimensions.get( iDim ); 358 return this.Dimensions.get( iDim );
245} 359}
246 360
361//
362// Get a reference to the current player position in the maze.
363//
247Map.prototype.getPlayerPos = function getPlayerPos() 364Map.prototype.getPlayerPos = function getPlayerPos()
248{ 365{
249 return this.pPlayer; 366 return this.pPlayer;
250} 367}
251 368
369//
370// Replace the player position with a new position.
371//
252Map.prototype.setPlayerPos = function setPlayerPos( pNewPos ) 372Map.prototype.setPlayerPos = function setPlayerPos( pNewPos )
253{ 373{
254 this.pPlayer = pNewPos; 374 this.pPlayer = pNewPos;
255 this.ePlayerMoved.call(); 375 this.ePlayerMoved.emit();
256} 376}
257 377
378//
379// Move the player the specified amount (iDelta) along the specified dimension
380// (iDim). This takes walls and maze borders into account, and will not move
381// the player in an "illegal" way.
382//
258Map.prototype.movePlayer = function movePlayer( iDim, iDelta ) 383Map.prototype.movePlayer = function movePlayer( iDim, iDelta )
259{ 384{
260 let cCur = this.get( this.pPlayer ); 385 let cCur = this.get( this.pPlayer );
@@ -271,14 +396,17 @@ Map.prototype.movePlayer = function movePlayer( iDim, iDelta )
271 return; 396 return;
272 397
273 this.pPlayer.add( iDim, iDelta ); 398 this.pPlayer.add( iDim, iDelta );
274 this.ePlayerMoved.call(); 399 this.ePlayerMoved.emit();
275 400
276 if( this.pPlayer.equals( this.pGoal ) ) 401 if( this.pPlayer.equals( this.pGoal ) )
277 { 402 {
278 this.eVictory.call(); 403 this.eVictory.emit();
279 } 404 }
280} 405}
281 406
407//
408// Helper that determines if the provided position is inside the maze or not.
409//
282Map.prototype.isInside = function isInside( Position ) 410Map.prototype.isInside = function isInside( Position )
283{ 411{
284 if( Position.getDims() != this.Dimensions.getDims() ) 412 if( Position.getDims() != this.Dimensions.getDims() )
@@ -299,6 +427,12 @@ Map.prototype.isInside = function isInside( Position )
299 return true; 427 return true;
300} 428}
301 429
430//
431// Internal helper function. This converts from a Position object to an array
432// index, effectively flattening an arbitrarily dimensional coordinate into a
433// one dimensional array coordinate. This is used to find the actual storage
434// location of cells internally.
435//
302Map.prototype.getIndex = function getIndex( Position ) 436Map.prototype.getIndex = function getIndex( Position )
303{ 437{
304 if( !this.isInside( Position ) ) 438 if( !this.isInside( Position ) )
@@ -316,17 +450,25 @@ Map.prototype.getIndex = function getIndex( Position )
316 return iIdx; 450 return iIdx;
317} 451}
318 452
453//
454// Get a cell at the given Position.
455//
319Map.prototype.get = function get( Position ) 456Map.prototype.get = function get( Position )
320{ 457{
321 return this.aCell[this.getIndex( Position )]; 458 return this.aCell[this.getIndex( Position )];
322} 459}
323 460
461//
462// Create a new worm and add it to the maze. Specify the starting position
463// 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.
465//
324Map.prototype.addWorm = function addWorm( pStart, dLoopChance ) 466Map.prototype.addWorm = function addWorm( pStart, dLoopChance )
325{ 467{
326 if( this.pPlayer === null ) 468 if( this.pPlayer === null )
327 { 469 {
328 this.pPlayer = pStart; 470 this.pPlayer = pStart;
329 this.ePlayerSetup.call(); 471 this.ePlayerSetup.emit();
330 } 472 }
331 else if( this.pGoal === null ) 473 else if( this.pGoal === null )
332 { 474 {
@@ -344,6 +486,13 @@ Map.prototype.addWorm = function addWorm( pStart, dLoopChance )
344 return iNewId; 486 return iNewId;
345} 487}
346 488
489//
490// Worker function. This calls the timestep funcion on each worm until they
491// report that they are done working and have exhausted all possible moves.
492//
493// At the moment this function assumes we have 2 worms and connects them
494// automatically once it's done running.
495//
347Map.prototype.buildMaze = function buildMaze() 496Map.prototype.buildMaze = function buildMaze()
348{ 497{
349 do 498 do
@@ -360,6 +509,13 @@ Map.prototype.buildMaze = function buildMaze()
360 this.connect( 1, 2 ); 509 this.connect( 1, 2 );
361} 510}
362 511
512//
513// Connect the pathways created by two worms, specified by iWormId1 and
514// iWormId2 to each other. this searches all walls in the maze and looks for
515// a wall that seperates the path created by these two worms, then finds the
516// wall that seperates the longest combined pathway between the two, and opens
517// it up into a pathway.
518//
363Map.prototype.connect = function connect( iWormId1, iWormId2 ) 519Map.prototype.connect = function connect( iWormId1, iWormId2 )
364{ 520{
365 let p = new Position( this.getDims() ); 521 let p = new Position( this.getDims() );
@@ -432,6 +588,8 @@ Map.prototype.connect = function connect( iWormId1, iWormId2 )
432// 588//
433// Class: Vector 589// Class: Vector
434// 590//
591// Simple helper class that stores a position and direction.
592//
435function Vector( pPos, iDir ) 593function Vector( pPos, iDir )
436{ 594{
437 this.pPos = pPos; 595 this.pPos = pPos;
@@ -441,6 +599,26 @@ function Vector( pPos, iDir )
441// 599//
442// Class: Worm 600// Class: Worm
443// 601//
602// The main workhorse (workworm?) of maze generation. The worm "eats" a path
603// through the maze. The basic algorithm works as follows:
604// 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
606// 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
608// it, but first:
609// 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,
611// then select an adjacent room at random and break through the wall
612// to that room.
613// 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.
615// 4. If we reach the starting position again, then bailout and consider our
616// work done.
617// 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
619// that we've traveled. When backtracking we update our current distance so
620// that all distances are contiguous and increasing away from start.
621//
444function Worm( iId, pStart, rMap, dLoopChance ) 622function Worm( iId, pStart, rMap, dLoopChance )
445{ 623{
446 // Initialize basic state, we start with distance set to 1 624 // Initialize basic state, we start with distance set to 1
@@ -470,11 +648,14 @@ function Worm( iId, pStart, rMap, dLoopChance )
470 if( iDirs.length > 0 ) 648 if( iDirs.length > 0 )
471 { 649 {
472 // We are near a wall, pick a random wall to open a hole in 650 // We are near a wall, pick a random wall to open a hole in
473 this.rMap.get(this.pPosition).iWalls |= iDirs[randInt(iDirs.length)]; 651 this.rMap.get(this.pPosition).iWalls |= iDirs[lRand.randInt(iDirs.length)];
474 this.rMap.get(this.pPosition).iPath = this.iId; 652 this.rMap.get(this.pPosition).iPath = this.iId;
475 } 653 }
476} 654}
477 655
656//
657// Perform one step as descirbed in the constructor.
658//
478Worm.prototype.timestep = function timestep() 659Worm.prototype.timestep = function timestep()
479{ 660{
480 // Handy to reference how many dimensions we have 661 // Handy to reference how many dimensions we have
@@ -553,7 +734,7 @@ Worm.prototype.timestep = function timestep()
553 } 734 }
554 735
555 cCur = this.rMap.get( this.pPosition ); 736 cCur = this.rMap.get( this.pPosition );
556 let iSel = randInt( pDirs.length ); 737 let iSel = lRand.randInt( pDirs.length );
557 cCur.iWalls |= (1<<pDirs[iSel].iDir); 738 cCur.iWalls |= (1<<pDirs[iSel].iDir);
558 let cNext = this.rMap.get( pDirs[iSel].pPos ); 739 let cNext = this.rMap.get( pDirs[iSel].pPos );
559 cNext.iWalls |= (1<<oppositeDir( pDirs[iSel].iDir )); 740 cNext.iWalls |= (1<<oppositeDir( pDirs[iSel].iDir ));
@@ -564,7 +745,7 @@ Worm.prototype.timestep = function timestep()
564 745
565 if( pLoopDirs.length > 0 && lRand.random() <= this.dLoopChance ) 746 if( pLoopDirs.length > 0 && lRand.random() <= this.dLoopChance )
566 { 747 {
567 iSel = pLoopDirs[randInt( pLoopDirs.length )]; 748 iSel = pLoopDirs[lRand.randInt( pLoopDirs.length )];
568 cCur.iWalls |= (1<<iSel.iDir); 749 cCur.iWalls |= (1<<iSel.iDir);
569 cNext = this.rMap.get( iSel.pPos ); 750 cNext = this.rMap.get( iSel.pPos );
570 cNext.iWalls |= (1<<oppositeDir( iSel.iDir )); 751 cNext.iWalls |= (1<<oppositeDir( iSel.iDir ));
@@ -576,45 +757,29 @@ Worm.prototype.timestep = function timestep()
576// 757//
577// Class: Render 758// Class: Render
578// 759//
760// Base class of render classes. Doesn't do anything on it's own.
761//
579function Render( rMap, eMazeContainer ) 762function Render( rMap, eMazeContainer )
580{ 763{
581 this.rMap = rMap; 764 this.rMap = rMap;
582 this.eMazeContainer = eMazeContainer; 765 this.eMazeContainer = eMazeContainer;
583} 766}
584 767
768//
769// Empty base class function specifying that there should be a render function
770// in child classes.
771//
585Render.prototype.render = function render() 772Render.prototype.render = function render()
586{ 773{
587} 774}
588 775
589function createMoveButton( rMap, iDim, iDir, sLabel )
590{
591 let btn = document.createElement('button');
592 btn.addEventListener(
593 'click',
594 Map.prototype.movePlayer.bind(
595 rMap,
596 iDim,
597 iDir
598 )
599 );
600 if( sLabel === null || sLabel === '' )
601 {
602 btn.appendChild(
603 document.createTextNode('Dim ' + (j+1) + ': -')
604 );
605 }
606 else
607 {
608 btn.appendChild(
609 document.createTextNode( sLabel )
610 );
611 }
612 return btn;
613}
614
615// 776//
616// Class: RenderCanvas2D 777// Class: RenderCanvas2D
617// 778//
779// 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
781// manages buttons you can use to interact with the maze.
782//
618function RenderCanvas2D( rMap, params ) // eMazeContainer, eUIContainer ) 783function RenderCanvas2D( rMap, params ) // eMazeContainer, eUIContainer )
619{ 784{
620 let eMazeContainer = document.getElementById(params['maze']); 785 let eMazeContainer = document.getElementById(params['maze']);
@@ -779,9 +944,20 @@ function RenderCanvas2D( rMap, params ) // eMazeContainer, eUIContainer )
779 this.updateButtons(); 944 this.updateButtons();
780} 945}
781 946
947// Setup RenderCanvas2D as a child class of Render
782RenderCanvas2D.prototype = Object.create(Render.prototype); 948RenderCanvas2D.prototype = Object.create(Render.prototype);
783RenderCanvas2D.prototype.constructor = RenderCanvas2D; 949RenderCanvas2D.prototype.constructor = RenderCanvas2D;
784 950
951//
952// Performs the bulk of the work of resetting and rendering the maze. This is
953// called whenever anything changes at all and the entire maze floor is redrawn.
954//
955// Since these are such simple graphics there's not much of an issue with this
956// approach. It could be optomized and only the parts that have changed could
957// bo modified, but it's probably not worth it in the long run. We're as
958// likely to travel along any dimension as X or Y, and every dimension other
959// than X and Y requrie a full redraw of the maze.
960//
785RenderCanvas2D.prototype.render = function render() 961RenderCanvas2D.prototype.render = function render()
786{ 962{
787 let iSize = this.iCellSize; 963 let iSize = this.iCellSize;
@@ -895,6 +1071,10 @@ RenderCanvas2D.prototype.render = function render()
895 } 1071 }
896} 1072}
897 1073
1074//
1075// Helper function that draws the icons for the travel icons for dimensions
1076// after the first two.
1077//
898RenderCanvas2D.prototype.renderDirIcon = function renderDirIcon( 1078RenderCanvas2D.prototype.renderDirIcon = function renderDirIcon(
899 x, y, iIcon, iDir ) 1079 x, y, iIcon, iDir )
900{ 1080{
@@ -952,6 +1132,10 @@ RenderCanvas2D.prototype.renderDirIcon = function renderDirIcon(
952 } 1132 }
953} 1133}
954 1134
1135//
1136// Slot that updates the enabled/disabled status of the UI buttons after the
1137// player's position has changed.
1138//
955RenderCanvas2D.prototype.updateButtons = function updateButtons() 1139RenderCanvas2D.prototype.updateButtons = function updateButtons()
956{ 1140{
957 let c = this.rMap.get( this.rMap.pPlayer ); 1141 let c = this.rMap.get( this.rMap.pPlayer );
@@ -961,6 +1145,10 @@ RenderCanvas2D.prototype.updateButtons = function updateButtons()
961 } 1145 }
962} 1146}
963 1147
1148//
1149// Slot that updates the textual readout label telling us what "floor" we're on
1150// when the player's position has changed.
1151//
964RenderCanvas2D.prototype.updateReadout = function updateReadout() 1152RenderCanvas2D.prototype.updateReadout = function updateReadout()
965{ 1153{
966 if( this.rMap.getDims() <= 2 ) 1154 if( this.rMap.getDims() <= 2 )
@@ -975,6 +1163,10 @@ RenderCanvas2D.prototype.updateReadout = function updateReadout()
975 this.readoutNode.textContent = text; 1163 this.readoutNode.textContent = text;
976} 1164}
977 1165
1166//
1167// Slot that performs the operations needed to display that a victory has
1168// occured when the player has reached the exit.
1169//
978RenderCanvas2D.prototype.setVictory = function setVictory() 1170RenderCanvas2D.prototype.setVictory = function setVictory()
979{ 1171{
980 while( this.btnBox.hasChildNodes() ) 1172 while( this.btnBox.hasChildNodes() )
@@ -989,15 +1181,6 @@ RenderCanvas2D.prototype.setVictory = function setVictory()
989 this.btnBox.appendChild( h1 ); 1181 this.btnBox.appendChild( h1 );
990} 1182}
991 1183
992RenderCanvas2D.prototype.setFloor = function setFloor( aFloor )
993{
994 for( let j = 0; j < aFloor.length; j++ )
995 {
996 this.pExtPosition.set( j+2, aFloor[j] );
997 }
998 this.render();
999}
1000
1001// 1184//
1002// Initialize 1185// Initialize
1003// 1186//
@@ -1038,7 +1221,11 @@ function lostInit( properties )
1038 let eEditorBox = document.getElementById(properties['editor']); 1221 let eEditorBox = document.getElementById(properties['editor']);
1039 let eShareBox = document.getElementById(properties['share']); 1222 let eShareBox = document.getElementById(properties['share']);
1040 1223
1041 let rend = new RenderCanvas2D( m, properties['render']['params'] ); 1224 //let rend = new RenderCanvas2D( m, properties['render']['params'] );
1225 let rend = Reflect.construct(
1226 properties['render']['name'],
1227 [m, properties['render']['params']]
1228 );
1042 1229
1043 let formDiv = eEditorBox; 1230 let formDiv = eEditorBox;
1044 let form = document.createElement('form'); 1231 let form = document.createElement('form');