diff options
author | Mike Buland <eichlan@xagasoft.com> | 2016-11-23 08:13:29 -0700 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2016-11-23 08:13:29 -0700 |
commit | 4a6d948d10eb0aacc9d036e5152ad28488f66515 (patch) | |
tree | 9e610f9217dff3f609c97966eda55bf303f78db8 | |
parent | a267b561f392c2f3355b4f2e8c4536501e8d327d (diff) | |
download | lost-main.tar.gz lost-main.tar.bz2 lost-main.tar.xz lost-main.zip |
It works with the google javascript compiler now.
-rw-r--r-- | js/lost.js | 363 |
1 files changed, 192 insertions, 171 deletions
@@ -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 | */ |
23 | function createMoveButton( rMap, iDim, iDir, sLabel ) | 23 | function 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 | */ | ||
65 | function RandomLcg() | 67 | function 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. |
125 | let lRand = new RandomLcg(); | 127 | let 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 | */ | ||
134 | function Signal() | 138 | function 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 | */ | ||
165 | function Cell() | 171 | function 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 | * |
178 | function Position( iDims, ...Vals ) | 184 | * @constructor |
185 | */ | ||
186 | function 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 | // |
264 | Position.prototype.translate = function translate( iDim, iDelta ) | 272 | Position.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 | // |
274 | Position.prototype.copy = function translate() | 282 | Position.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 | * |
319 | function Map( Dimensions ) | 327 | * @constructor |
328 | */ | ||
329 | function 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 | // |
348 | Map.prototype.getDims = function getDims() | 358 | MazeMap.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 | // |
356 | Map.prototype.getSize = function getSize( iDim ) | 366 | MazeMap.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 | // |
364 | Map.prototype.getPlayerPos = function getPlayerPos() | 374 | MazeMap.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 | // |
372 | Map.prototype.setPlayerPos = function setPlayerPos( pNewPos ) | 382 | MazeMap.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 | // |
383 | Map.prototype.movePlayer = function movePlayer( iDim, iDelta ) | 393 | MazeMap.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 | // |
410 | Map.prototype.isInside = function isInside( Position ) | 420 | MazeMap.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 | // |
436 | Map.prototype.getIndex = function getIndex( Position ) | 446 | MazeMap.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 | // |
456 | Map.prototype.get = function get( Position ) | 466 | MazeMap.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 | // |
466 | Map.prototype.addWorm = function addWorm( pStart, dLoopChance ) | 476 | MazeMap.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 | // |
496 | Map.prototype.buildMaze = function buildMaze() | 506 | MazeMap.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 | // |
519 | Map.prototype.connect = function connect( iWormId1, iWormId2 ) | 529 | MazeMap.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 | */ | ||
593 | function Vector( pPos, iDir ) | 605 | function 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 | * |
622 | function Worm( iId, pStart, rMap, dLoopChance ) | 634 | * @constructor |
635 | */ | ||
636 | function 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 ) | |||
659 | Worm.prototype.timestep = function timestep() | 673 | Worm.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 | * |
762 | function Render( rMap, eMazeContainer ) | 776 | * @constructor |
777 | */ | ||
778 | function 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 | * |
783 | function RenderCanvas2D( rMap, params ) // eMazeContainer, eUIContainer ) | 799 | * @constructor |
800 | */ | ||
801 | function 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 | // |
1144 | RenderCanvas2D.prototype.updateButtons = function updateButtons() | 1162 | RenderCanvas2D.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 | // |
1157 | RenderCanvas2D.prototype.updateReadout = function updateReadout() | 1175 | RenderCanvas2D.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 | ||
1193 | function lostInit( properties ) | 1211 | function 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 | ||
1281 | window['lostInit'] = lostInit; | ||
1282 | window['RenderCanvas2D'] = RenderCanvas2D; | ||