1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width"> 6 <title>The Room Adventure: Additional Features</title> 7 8 <link href="/index.css" rel="stylesheet" type="text/css"/> 9 <link href="/roomadventure/rooms.css" rel="stylesheet" type="text/css"/> 10 <link rel="shortcut icon" href="http://stephenjwolf.com/coding/favicon.ico" type="image/x-icon"/> 11 </head> 12 <body> 13 <div id="body"><!-- Required div for navigation bar --> 14 <div class="imgfloater max150px"><img src="/images/SergeiStudious.png"></div> 15 <h1>The Room Adventure: Additional Features</h1> 16 17 <h2>Checking that the Played Can Unlock the Locks</h2> 18 <h4>Difficulty: ★★★☆☆</h4> 19 <h4><em>Requirement: Lock and Key Feature</em></h4> 20 21 <div class="flex-container"> 22 <div> 23 <!--Explanation--> 24 <p>We installed a locked door feature in <a href="addlockedroom.html">Add Locked Rooms</a>. This requires you, as 25 the developer, to place keys in the rooms and to lock doors. This must be done so you don't have a key hidden 26 behind a locked door you need it for.</p> 27 28 <p>Even with good planning, mistakes can happen. You put the brass key in the office to unlock the dining room. 29 You put the silver key in the dining room to unlock the hallway. Sounds good, except, you have to pass through 30 the hallway to get to the office, so you can never get to the brass key, therefore you can never get to the 31 silver key, and you can never unlock the hallway, which would let you get the brass key. (Follow all that?)</p> 32 33 <p>In addition, if you use certain randomization features, this whole process becomes a real mess.</p> 34 35 <p>We need a way to check to make sure the lock and key setup will allow the player to complete the game. Even if 36 you set up the locks and keys yourself, you should create this and at least run it from the console to make sure 37 your game is playable.</p> 38 39 <h2>What we need to do</h2> 40 41 <ul> 42 <li>Create a set of tracking variables so we don't change actual room or player information.</li> 43 <li>Make a list of locked rooms and all keys from the room set we are testing.</li> 44 <li>Take keys from any room we are in and try to unlock any doors we can.</li> 45 <li>Randomly move to any possible, unlocked exit.</li> 46 <li>Continue until all locked doors are unlocked or we run out of tests.</li> 47 </ul> 48 </div> 49 50 <div class="imgwrapper"> 51 <br> 52 <!--Screenshot--> 53 <img src="/roomadventure/screenimages/checkkeys01.png"> 54 </div> 55 </div> 56 57 <h2>Using console.log to debug</h2> 58 <p>This function has a few tricky details. It can be hard to keep track of it all because we can't see what's 59 happening.</p> 60 61 <p>For situations like this, I make heavy use of <code><span class="object">console</span>.<span 62 class="function">log</span>()</code>. I put variables names ini there and then check the console when I run the 63 function so I can check to see what's happening. It helps me figure out if something goes wrong.</p> 64 65 <p>In the code here, you will see a lot of <span class="object">console</span> commands. You do not have to type these 66 in if you don't want to. They won't change how your code runs at all. They're just there so you can see some output 67 in the console.</p> 68 69 <p>You can see the output in the <code>repl.it</code> console window or by accessing developer tools, which you can 70 usually find by pressing <kbd class="key">f12</kbd> on your keyboard.</p> 71 72 <h2>Step 1: Initializing our variables</h2> 73 <p>We only want this function to test the locks and keys. We don't want it to actually unlock anything or really move 74 the player around. So we need to set up a few variables that will hold some information for us.</p> 75 76 <div class="code"> 77 <ul> 78 <li><span class="keyword">function</span> <span class="function">checkKeys</span>(availableRooms, playerStart, 79 allowRandomStart) 80 </li> 81 <li>{ 82 <ul> 83 <li><span class="comment">//we don't want to alter the rooms, so we're making new variables</span></li> 84 <li><span class="object">availableRooms</span> = <span class="object">availableRooms</span> || <span 85 class="object">rooms</span>; 86 </li> 87 <li><span class="object">playerStart</span> = playerStart || <span class="object">player</span>.<span 88 class="property">currentRoom</span>.<span class="property">.name</span>; 89 </li> 90 <li><span class="object">player</span>.<span class="property">_tempkeys</span> = <span 91 class="object">player</span>.<span class="property">_tempkeys</span> || []; 92 </li> 93 <li> </li> 94 <li><span class="keyword">var</span> foundKeys = <span class="object">player</span>.<span class="property">_tempkeys</span>.<span 95 class="function">slice</span>(); 96 </li> 97 <li><span class="keyword">var</span> numberRooms = 0;</li> 98 <li><span class="keyword">var</span> lockedRooms = [];</li> 99 <li><span class="keyword">var</span> startRooms = [];</li> 100 </ul> 101 </li> 102 </ul> 103 </div> 104 105 <h3>Code breakdown</h3> 106 <p><a href="#step2">Or skip directly to the next step.</a></p> 107 108 <h4>The parameters</h4> 109 <p>We are taking in three parameters here. One is a set of <code>availableRooms</code> you want to test out. This 110 could be the global set of rooms, or it could be a smaller set of them, like one floor of the house, or an area of a 111 forest. We are going to put in a failsafe so that if you leave out this parameter, the function will default to 112 using the global <span class="object">rooms</span> object.</p> 113 114 <p>The <code>playerStart</code> is where you want the player to start in the house. This could make a huge difference 115 to the game, depending on locks and keys! If you have a specific setup in mind, you need to control this carefully. 116 </p> 117 118 <p>Like the rooms, we're going to have a backup plan if you don't send in the starting point for the player. In that 119 case, we will use the player's current room.</p> 120 121 <p>We are also using an <code>allowRandomStart</code> switch. If the <code>playerStart</code> location is not a valid 122 room, we can either say the setup doesn't work, or we could randomly pick a room for the player to start in and test 123 that.</p> 124 125 <p>Leaving this out when you call the function would make it default to <span class="keyword">undefined</span>, which 126 would be treated as <span class="keyword">false</span> when we test for it, therefore not allowing the starting 127 point to be randomized.</p> 128 129 <p>If we pass in <span class="keyword">true</span> for this, then it may help you figure out a good starting room if 130 you're using the console to show values.</p> 131 132 <p>It is generally better to control your parameters directly by sending in specific arguments when you write your 133 code. I like to have failsafes in place. By the way, if you don't send in a set of rooms, then you <em>can't</em> 134 send in a player's starting place or the lock-in-place flag. Arguments and parameters have to line up when you send 135 them in and when you assign them in the function.</p> 136 137 <h4>Using the OR <code>||</code> operator for assignment</h4> 138 <p>We usually use OR when we do a conditional test, like in an <span class="keyword">if</span> or <span 139 class="keyword">while</span> statement. But JavaScript lets us use it when we assign values too.</p> 140 141 <p>Go the the equals sign and then start at the first value. If that translates to <span class="keyword">true</span>, 142 then it gets assigned to the variable. So if we send in a set of available rooms, then that's what we'll use. But if 143 we didn't send in a set, leaving it <span class="keyword">undefined</span>, that would be a <span class="keyword">false</span> 144 statement. The OR <code>||</code> operator then moves on to the next variable. If it's the last one in the set, it 145 assigns it, whatever its value. In this case, the global <span class="object">rooms</span> object.</p> 146 147 <p>If you have several OR operators in a row, it would keep moving down the list until either one of them was <span 148 class="keyword">true</span> or until it reaches the last one.</p> 149 150 <h4>The underscore</h4> 151 <p>We usually avoid using the underscore when we name things. By convention, it is used for <em>private</em> 152 variables, or variables that really should not be touched by another programmer. It's not a rule and there's nothing 153 stopping them from messing with it. But it's asking them not to.</p> 154 155 <p>We're using it to control a temporary set of keys that we need to keep track of while we check the 156 locked-room-and-key layout. We are attaching it to the global <span class="object">player</span> object so it can be 157 used again if needed. Why? Well, if you are using the floor/area separator, you may need to know what keys the 158 player has before coming into an area when you're testing things out. And we don't want to change the player's 159 actual key inventory.</p> 160 161 <h4>Copying an array</h4> 162 <p>When we need a shallow copy of an array (like copying strings and numbers), we need to use the <span 163 class="function">slice</span> method. This leaves the original array intact and sends back a new copy of it. <span 164 class="function">slice</span> can also return just sections of an array, but here we need the whole copy.</p> 165 166 <p>We can't just assign the array as equal without the <span class="function">slice</span>. If we did, then the new 167 array would just be a <em>pointer</em> to the original array. So changing one would change "both." It's not really 168 "both" because there's only one array with two names, like having a nickname. So, to make an array copy, we need 169 <span 170 class="function">slice</span>.</p> 171 172 173 <h2 id="step2">Step 2: Make a list of locks and keys</h2> 174 <p>Let's loop through the list of available rooms. We'll count the rooms we have, and make lists of the rooms that are 175 locked, and all the keys that can be found.</p> 176 177 <p>You've seen code like this before.</p> 178 179 <div class="code"> 180 <ul> 181 <li> 182 <ul> 183 <li><span class="keyword">for</span> (<span class="keyword">var</span> roomName <span 184 class="keyword">in</span> <span class="object">availableRooms</span>) 185 </li> 186 <li>{ 187 <ul> 188 <li>numberRooms++;</li> 189 <li><span class="keyword">var</span> <span class="object">room</span> = <span 190 class="object">availableRooms</span>[roomName]; 191 </li> 192 <li>startRooms.<span class="function">push</span>(roomName);</li> 193 <li> </li> 194 <li><span class="keyword">if</span> (<span class="object">room</span>.<span class="property">locked</span> 195 && <span class="object">room</span>.<span class="property">locked</span>.<span 196 class="property">length</span> > 0) 197 </li> 198 <li>{ 199 <ul> 200 <li>lockedRooms.<span class="function">push</span>(roomName);</li> 201 </ul> 202 </li> 203 <li>}</li> 204 <li> </li> 205 <li><span class="keyword">if</span> (<span class="object">room</span>.<span class="property">keys</span> 206 && <span class="object">room</span>.<span class="property">keys</span>.<span 207 class="property">length</span> > 0) 208 </li> 209 <li>{ 210 <ul> 211 <li>foundKeys = foundKeys.<span class="function">concat</span>(<span class="object">room</span>.<span 212 class="property">keys</span>); 213 </li> 214 </ul> 215 </li> 216 <li>}</li> 217 </ul> 218 </li> 219 <li>}</li> 220 </ul> 221 </li> 222 </ul> 223 </div> 224 225 <h3>Code breakdown</h3> 226 <p><a href="#step3">Or skip directly to the next step.</a></p> 227 228 <h4>Counting and listing the rooms</h4> 229 <p>We're keeping track of the number of rooms to help us figure out how many tries we should have to see if the keys 230 and locks work. It's probably not that necessary, but why not?</p> 231 232 <p>We're keeping a list of <code>startRooms</code> in case there isn't a valid starting room for the player. This will 233 then be the list of rooms we could pick from to try out.</p> 234 235 236 <h4>Concatenating arrays</h4> 237 <p>Concatenation just means that we add things together, like when we add strings. Concatenation takes two (or more) 238 arrays and puts them all together into one bigger array, like copying both onto a new sheet.</p> 239 240 <p>The thing to remember, and it's easy to forget, is that this does not change the original arrays. Instead, it sends 241 back a <em>new</em> array. That means you have to save it to a variable if you want to use it, and what's the point 242 of making it if you don't want to use it?</p> 243 244 <p>We're overwriting the <code>foundKeys</code> array here. In essence, it adds the second array to the end of the 245 first one instead of creating a new array. Well, that's just what looks like is happening.</p> 246 247 <h4>Testing object properties safely</h4> 248 <p>You'll use lines like this a lot when you need to test certain properties of objects.</p> 249 250 <div class="code"> 251 <ul> 252 <li><span class="keyword">if</span> (<span class="object">room</span>.<span class="property">locked</span> && 253 <span 254 class="object">room</span>.<span class="property">locked</span>.<span class="property">length</span> > 0) 255 </li> 256 </ul> 257 </div> 258 259 <p>When you decided to add locks to your rooms, did you add a <span class="property">locked</span> property to every 260 single room, or just the ones you locked? We oly added them to the ones we locked, so most of your rooms won't even 261 have this property at all. That means it's <span class="keyword">undefined</span>. By itself, that's no big deal. 262 </p> 263 264 <p>But the <span class="property">locked</span> property is an array (when it's there). All arrays, even empty ones, 265 test as <span class="keyword">true</span>, so we can only tell if the room is locked by seeing if there is at least 266 on key in the <span class="property">locked</span> list.</p> 267 268 <p>So we need the <span class="property">length</span> property of the room's <span class="property">locked</span> 269 array. Buuuut. If the room doesn't even <em>have</em> a <span class="property">locked</span> property, then we would 270 cause an error when we try to get its <span class="property">length</span>.</p> 271 272 <p>Ugh, right? So, we first need to make sure that the object <em>has the property we are looking for before we can 273 check to see if that list has anything in it.</em></p> 274 275 <p>We use the AND <code>&&</code> operator for this and it has to be set up in this order. We test for the <span 276 class="property">locked</span> property first to see if it even exists. If it doesn't, the JavaScript doesn't even 277 look at the next part because the AND operator needs everything to be <span class="keyword">true</span>, so if the 278 first part isn't <span class="keyword">true</span> then the whole thing can't be <span class="keyword">true</span> 279 either. This allows us to prevent an error.</p> 280 <p>At times, we take it one step further and start by testing if there even is an object! Like this.</p> 281 282 <div class="code"> 283 <ul> 284 <li><span class="keyword">if</span> (<span class="object">room</span> && <span class="object">room</span>.<span 285 class="property">locked</span> && <span class="object">room</span>.<span class="property">locked</span>.<span 286 class="property">length</span> > 0) 287 </li> 288 </ul> 289 </div> 290 291 <h2 id="step3">Step 3: Printing to the console</h2> 292 <p>Optional: <a href="#step5">Or skip directly to the next step.</a></p> 293 294 <p>Let's print our first set of variables to the console so we can check them when we run them. This can help us to 295 troubleshoot any problems later when we run the function.</p> 296 297 <div class="code"> 298 <ul> 299 <li> 300 <ul> 301 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"***Start of 302 check"</span>); 303 </li> 304 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"#rooms: 305 "</span> + numberRooms); 306 </li> 307 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"locked: 308 "</span> + lockedRooms); 309 </li> 310 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"keys: "</span> 311 + foundKeys); 312 </li> 313 </ul> 314 </li> 315 </ul> 316 </div> 317 318 <p>There are many ways to debug a program. You can use breakpoints and step through your code, tracking and watching 319 variables as you go. Or you can do something like this.</p> 320 321 <p>I like this method in the beginning of troubleshooting because it gives a quick overview and I can usually find 322 things faster. Also, when you have something that loops a lot, if you're stepping through it, it can take a really 323 long time.</p> 324 325 <p>By the way, if you want to send an object to the console, you can, but put it on its one console line. Don't use 326 the strings like I did. So if you wanted to print the available rooms, you could include this.</p> 327 328 <div class="code"> 329 <ul> 330 <li> 331 <ul> 332 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"available 333 rooms: "</span>; 334 </li> 335 <li><span class="object">console</span>.<span class="function">log</span>(<span 336 class="object">availableRooms</span>); 337 </li> 338 </ul> 339 </li> 340 </ul> 341 </div> 342 343 <p>The reason is that once you have the strings in there, JavaScript converts it to a string using that data type's 344 <span class="function">toString</span> method. In doing that, an object just gets printed as <span class="string">[object 345 Object]</span> which isn't useful at all. Doing it the other way allows you to see all the properties and their 346 values.</p> 347 348 <h2 id="step4">Step 4: Reporting back if we have an answer already</h2> 349 <p>We've barely started the function, we can already test for two situations.</p> 350 351 <ol> 352 <li>If no rooms are locked, then these rooms <em>can</em> be played.</li> 353 <li>If any rooms are locked but there are no keys, these rooms <em>cannot</em> be played.</li> 354 </ol> 355 356 <p>Let's test for these and if either condition happens let's exit out the function and report back.</p> 357 358 <p>Again, the console calls are optional. You can leave them out if you don't want to include them.</p> 359 360 <div class="code"> 361 <ul> 362 <li> 363 <ul> 364 <li><span class="keyword">if</span> (lockedRooms.<span class="property">length</span> === 0)</li> 365 <li>{ 366 <ul> 367 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"Nothing is 368 locked."</span>); 369 </li> 370 <li><span class="keyword">return true</span>; <span class="comment">//nothing is locked so sure, 371 everything is fine</span></li> 372 </ul> 373 <li>} 374 <li><span class="keyword">else if</span> (foundKeys.<span class="property">length</span> === 0)</li> 375 <li>{ 376 <ul> 377 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"#foundkeys: 378 "</span> + foundKeys.<span class="property">length</span>); 379 </li> 380 <li><span class="keyword">return false</span>; <span class="comment">//something is locked but with no 381 keys, there's a problem</span></li> 382 </ul> 383 </li> 384 <li>}</li> 385 </ul> 386 </li> 387 </ul> 388 </div> 389 390 391 <h2 id="step5">Step 5: Was a valid starting position sent in?</h2> 392 393 <p>Let's check to make sure the starting room sent in is in the set of rooms we received too. If not, then we have to 394 do one of two things, and which one depends on that third parameter, <code>allowRandomStart</code>.</p> 395 396 <ul> 397 <li>If the room is invalid and we do allow a random start, then we will pick a random room and try once to solve 398 this. 399 </li> 400 <li>If the room is invalid and we do not allow a random start, then we can't solve this.</li> 401 </ul> 402 403 <div class="code"> 404 <ul> 405 <li> 406 <ul> 407 <li><span class="keyword">if</span> (!<span class="object">availableRooms</span>[playerStart])</li> 408 <li>{ 409 <ul> 410 <li><span class="keyword">if</span> (allowRandomStart)</li> 411 <li>{ 412 <ul> 413 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"Bad 414 room, not picking random: "</span> + playerStart); 415 </li> 416 <li><span class="keyword">return false</span>;</li> 417 </ul> 418 </li> 419 <li>}</li> 420 <li><span class="keyword">else</span> <span class="comment">//pick a random room</span></li> 421 <li>{ 422 <ul> 423 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"Bad 424 room, picking random: "</span> + playerStart); 425 </li> 426 <li><span class="keyword">var</span> index = <span class="object">Math</span>.<span class="function">floor</span>(<span 427 class="object">Math</span>.<span class="function">random</span>() * startRooms.<span 428 class="property">length</span>); 429 </li> 430 <li></li> 431 playerStart = startRooms[index]; 432 </ul> 433 <li>}</li> 434 </ul> 435 </li> 436 <li>}</li> 437 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"start room: 438 "</span> + playerStart); 439 </li> 440 </ul> 441 </li> 442 </ul> 443 </div> 444 445 446 <h2 id="step6">Step 6: Determining the number of steps to take</h2> 447 <p>We are not using artificial intelligence or a tree search, like a <em>breadth-first search</em> or a <em>depth-first 448 search</em>, to find out if the keys and locks work. Those would be better and more efficient ways of doing this 449 process, and if set up correctly, they would always give you the right answer. But they are complicated processes 450 with recursive functions and so on.</p> 451 452 <p>Instead, we're going to use a <em>random walk</em>. The computer is going to randomly pick a valid exit and go in 453 that direction, pick up a key if there is one, unlock a door if it can.</p> 454 455 <p>But for how long should it try? Until everything is unlocked? Well, that's no good if one key is unreachable. So we 456 need to set a limit on the number of times the computer will try to walk from room to room before giving up. It is 457 possible that a room is solvable but we might run out of steps before it's figured out.</p> 458 459 <p>This calculation is pretty arbitrary. It's not based on anything complex. It's affected by the total number of 460 rooms and the number of locked rooms. And it's bound between 1000 and 10000 steps. Yes, 10000.</p> 461 462 <div class="code"> 463 <ul> 464 <li> 465 <ul> 466 <li><span class="comment">//How many steps should the player take through the house before we give up?</span> 467 </li> 468 <li><span class="keyword">var</span> iterations = numberRooms * lockedRooms.<span 469 class="property">length</span> * 100; 470 </li> 471 <li>iterations = <span class="object">Math</span>.<span class="function">min</span>(<span 472 class="object">Math</span>.<span class="function">max</span>(iterations, 1000), 10000); 473 </li> 474 </ul> 475 </li> 476 </ul> 477 </div> 478 479 <p>With my base set of 14 room, two locks and two keys, I ran 100000 iterations to test things out. Yes, one hundred 480 thousand. I created a helper function to do this and to track the results with a temporary tweak or two to the <span 481 class="function">checkKeys</span> function to make it work. I had the player randomly placed into any of the 482 rooms to start and then tested the lock/key placement. At a 100,000 times running the check, it took just over 2.2 483 seconds. The player took a maximum of 943 steps before determining the room could or could not be solved. On 484 average, the player took about 97 steps to traverse the house. And randomly placing the player in a room with my 485 locks and keys where they were created a 78% able-to-play-the-game completion rate. Not bad for our function here. 486 </p> 487 488 <h3>Code breakdown</h3> 489 <p><a href="#step7">Or skip directly to the next step.</a></p> 490 491 <h4>Getting a number within a range</h4> 492 <p>We start by calculating a number of iterations based on the total number of rooms sent in and the number of rooms 493 that are locked in that set. You could multiply it by any number you want, but I figured a hundred steps per room 494 per locked room was plenty.</p> 495 496 <p>If you have very few rooms and locks, there many not be enough steps (iterations) to test it all out. On the other 497 hand, if you have huge numbers, it could take too long or cause a memory issue for the browser.</p> 498 499 <p>So we want to contain the values. I picked 1000 to 10000. Again, it's arbitrary and you can change them.</p> 500 501 <p>We use a combination of <code><span class="object">Math</span>.<span class="function">min</span></code> and 502 <code><span class="object">Math</span>.<span class="function">max</span></code> to do this. You use <code><span 503 class="object">Math</span>.<span class="function">max</span></code> to set the <em>lower</em> boundary. And then 504 you use <code><span class="object">Math</span>.<span class="function">min</span></code> to set the <em>upper</em>. 505 </p> 506 507 <p>It seems backward. Let's say your calculation produced 200 iterations. If you use <code><span 508 class="object">Math</span>.<span class="function">min</span>(200, 1000);</code>, then it would pop out 1000. Now 509 put that with 10000 into <code><span class="object">Math</span>.<span class="function">min</span>(1000, 510 10000)</code> and you get 1000 iterations, which is our lower limit.</p> 511 512 <p>Or, let's say your calculation came up with 3000 iterations. If you use <code><span 513 class="object">Math</span>.<span class="function">min</span>(3000, 1000);</code>, then it would pop out 3000. Now 514 put that with 10000 into <code><span class="object">Math</span>.<span class="function">min</span>(3000, 515 10000)</code> and you get 3000 iterations, which was your number.</p> 516 517 <p>Finally, let's say your calculation came up with 60000 iterations. If you use <code><span 518 class="object">Math</span>.<span class="function">min</span>(60000, 1000);</code>, then it would pop out 60000. 519 Now put that with 10000 into <code><span class="object">Math</span>.<span class="function">min</span>(60000, 10000)</code> 520 and you get 10000 iterations, which is our upper limit.</p> 521 522 <h2 id="step7">Step 7: Start the 'iteration' loop</h2> 523 <p>It's time to start moving the computerized player randomly through the house to test out the layout. We'll start by 524 setting up two pre-loop variables we need, starting the loop, and then I'm putting in some console displays again 525 (which you can still leave out if you want).</p> 526 527 <p>Let's reset the key list to what it was when the function started and put the fake player into the room.</p> 528 529 <div class="code"> 530 <ul> 531 <li> 532 <ul> 533 <li>foundKeys = <span class="object">player</span>.<span class="property">_tempkeys</span>.<span 534 class="function">slice</span>(); 535 </li> 536 <li><span class="keyword">var</span> playerRoom = playerStart;</li> 537 <li> </li> 538 <li><span class="keyword">for</span> (<span class="keyword">var</span> i = 0; i < iterations; i++)</li> 539 <li>{ 540 <ul> 541 <li><span class="object">console</span>.<span class="function">log</span>(<span 542 class="string">"*********"</span>); 543 </li> 544 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"iteration: 545 "</span> + i); 546 </li> 547 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"location: 548 "</span> + playerRoom); 549 </li> 550 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"keys: 551 "</span> + foundKeys); 552 </li> 553 </ul> 554 </li> 555 </ul> 556 </li> 557 </ul> 558 </div> 559 560 <h2 id="step8">Step 8: Looking for a key</h2> 561 <p>For this checker to work, the computer-player needs to pick up a key in any room it's in that has a key. That's 562 what happens here. We also make sure the computer doesn't end up with hundred of copies of keys. We're not actually 563 removing them from the rooms because we're not altering the original rooms at all, so each time the computer goes in 564 the room with the key, it would take another copy!</p> 565 566 <p><strong>Be wary.</strong> We're going to get nested pretty deep here, so watch your braces carefully.</p> 567 <div class="code"> 568 <ul> 569 <li> 570 <ul> 571 <li> 572 <ul> 573 <li><span class="keyword">var</span> <span class="object">room</span> = <span 574 class="object">availableRooms</span>[playerRoom]; 575 </li> 576 <li><span class="keyword">if</span> (<span class="object">room</span>.<span class="property">keys</span> 577 && <span class="object">room</span>.<span class="property">keys</span>.<span 578 class="property">length</span> > 0) <span class="comment">//if the room has a key, take it</span> 579 </li> 580 <li>{ 581 <ul> 582 <li><span class="comment">//we don't want to add a hundred of any key, so let's check to make sure we 583 don't already have it</span></li> 584 <li><span class="keyword">for</span> (<span class="keyword">var</span> k = 0; k < <span 585 class="object">room</span>.<span 586 class="property">keys</span>.<span class="property">length</span>; k++) 587 </li> 588 <li>{ 589 <ul> 590 <li><span class="keyword">var</span> newKey = <span class="object">room</span>.<span 591 class="property">keys</span>[k]; 592 </li> 593 <li><span class="keyword">var</span> keyIndex = foundKeys.<span class="function">indexOf</span>(newKey); 594 </li> 595 <li><span class="keyword">if</span> (keyIndex === -1) <span class="comment">//we don't have the 596 key on the list yet</span> 597 <li>{ 598 <ul> 599 <li>foundKeys.<span class="function">push</span>(newKey);</li> 600 <li><span class="object">console</span>.<span class="function">log</span>(<span 601 class="string">"Found: "</span> + newKey); 602 </li> 603 </ul> 604 </li> 605 <li>}</li> 606 </ul> 607 </li> 608 <li>}</li> 609 </ul> 610 </li> 611 <li>}</li> 612 </ul> 613 </li> 614 </ul> 615 </li> 616 </ul> 617 </div> 618 619 <p>At this point, if there were any keys in this room, you've got them all.</p> 620 621 <h2 id="step9">Step 9: Starting the 'exit' loop</h2> 622 <p>We are still inside the iteration loop, remember. This loop is pretty big because there are a few things we need to 623 look for. At one point, it's going to get nested even deeper than that last one! Just keep track of those braces and 624 you'll be fine.</p> 625 626 <p>We're going to make a list of possible exits we can choose for later. These will be unlocked doors from the room 627 we're in. To do that, we will start with an empty array. Then we begin a <code>for...in</code> loop to run through 628 all the current room's exits.</p> 629 630 <h4>Edge cases</h4> 631 <p>We have one edge case we need to be concerned with. We have to make sure we aren't starting in a room that's 632 locked, unless we already have its key, or unless the key is in that room. So on the first time through the loop, 633 when the loop counter, <code>i</code>, is <code>0</code>, we're going to look at the room we're in, look for keys, 634 check the locks, and if we're stuck, then this test is a bust.</p> 635 636 <p>Another edge case we have to watch for is unavailable rooms. It is possible that one of the rooms that was sent in 637 to the function has an exit to a room that was <em>not</em> sent into the function. Say, for example, we are 638 checking locks and keys on the first floor, but there's an exit to the second floor and we don't have the list of 639 rooms from the second floor here. If that happens, we can't check that room.</p> 640 <p>There's a bit more coming to this loop, but that's enough to get it started. Let's go.</p> 641 642 <div class="code"> 643 <ul> 644 <li> 645 <ul> 646 <li> 647 <ul> 648 <li><span class="comment">//check each exit for a locked door and if we can unlock it</span></li> 649 <li><span class="comment">//we also need to pick an exit at random later, so we're making an array</span> 650 </li> 651 <li><span class="keyword">var</span> exitList = [];</li> 652 <li><span class="keyword">for</span> (<span class="keyword">var</span> exit <span 653 class="keyword">in</span> <span class="object">room</span>.<span class="property">exits</span>) 654 </li> 655 <li>{ 656 <ul> 657 <li> 658 <span class="keyword">var</span> exitRoom = <span class="object">availableRooms</span>[<span 659 class="object">room</span>.<span class="property">exits</span>[exit]]; <span class="comment">//helper 660 variable</span></li> 661 <li> </li> 662 <li><span class="keyword">if</span> (i === 0) <span class="comment">//check the room we start in first 663 to make sure it's not locked</span> 664 <li>{ 665 <ul> 666 <li>exitRoom = <span class="object">availableRooms</span>[playerRoom];</li> 667 </ul> 668 </li> 669 <li>}</li> 670 <li> </li> 671 672 <li><span class="comment">//the rooms sent in may not have some destinations, so we skip them</span> 673 </li> 674 <li><span class="keyword">if</span> (!<span class="object">availableRooms</span>[<span class="object">exitRoom</span>.<span 675 class="property">name</span>]) 676 </li> 677 <li>{ 678 <ul> 679 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"Not 680 available: "</span> + <span class="object">exitRoom</span>.<span class="property">name</span>); 681 </li> 682 <li><span class="keyword">continue</span>;</li> 683 </ul> 684 </li> 685 <li>}</li> 686 </ul> 687 </li> 688 </ul> 689 </li> 690 </ul> 691 </li> 692 </ul> 693 </div> 694 695 <h2 id="step10">Step 10: If it's not locked, it's a possible exit</h2> 696 <p>After that last step, here's an easy one. We'll make a helper variable that we'll again after this. Remember we 697 made that list of <code>lockedRooms</code> in the very beginning of the function in that very first loop?</p> 698 699 <p>We're going to take the name of the exit we're looking at to see if it's on that locked room list. If it isn't, 700 then we can assume that it isn't locked and so, it's a safe exit for us.</p> 701 702 <p>After this step, we're going to start unlocking rooms and taking room names off that <code>lockedRooms</code> list. 703 That's how we're simulating the unlocking of rooms without actually messing up the rooms themselves. Sneaky, huh? 704 </p> 705 706 <div class="code"> 707 <ul> 708 <li> 709 <ul> 710 <li> 711 <ul> 712 <li> 713 <ul> 714 <li><span class="comment">//helper variable</span></li> 715 <li><span class="keyword">var</span> lockIndex = lockedRooms.<span 716 class="function">indexOf</span>(<span 717 class="object">exitRoom</span>.<span class="property">name</span>); 718 </li> 719 <li><span class="keyword">if</span> (lockIndex === -1) <span class="comment">//if the exit isn't 720 locked, we might go that way</span> 721 <li>{ 722 <ul> 723 <li>exitList.<span class="function">push</span>(<span class="object">exitRoom</span>.<span 724 class="property">name</span>); 725 </li> 726 </ul> 727 </li> 728 <li>}</li> 729 </ul> 730 </li> 731 </ul> 732 </li> 733 </ul> 734 </li> 735 </ul> 736 </div> 737 738 739 <h2 id="step11">Step 11: Is it locked and can we unlock it?</h2> 740 <p>Now we're at the crux of what we need this function to do: Find locked rooms and try to unlock them.</p> 741 742 <p>The problem is... doing that requires quite a bit <em>more</em> nesting. We are already three layers deep. We're 743 inside the 'exit' loop, which is inside the 'iteration' loop, which is inside the function itself. And here we need 744 to go further in.</p> 745 746 <p>Part of the issue is that it's possible for a room to have more than one key that open it. That means we have to 747 check all those possibilities, which adds another loop into the mix.</p> 748 749 750 <h3>Here's the plan.</h3> 751 752 <ul> 753 <li>See if the room is locked.</li> 754 <li>If yes: 755 <ul> 756 <li>Loop through the keys that can unlock that room. 757 <ul> 758 <li>For each key the room needs, see if we also have that key.</li> 759 <li>If yes: 760 <ul> 761 <li>Unlock the door by removing it from the <code>lockedRooms</code> array.</li> 762 <li>See if the <code>lockedRooms</code> array is empty (all rooms are unlocked)</li> 763 <li>If yes: 764 <ul> 765 <li>Put the keys in your temporary pocket.</li> 766 <li>Leave this function, saying it was a success.</li> 767 </ul> 768 </li> 769 <li>If no: 770 <ul> 771 <li>Add this unlocked room to the possible exit options.</li> 772 </ul> 773 </li> 774 </ul> 775 </li> 776 <li>If no: 777 <ul> 778 <li>Keep looping through the keys the room needs.</li> 779 </ul> 780 </li> 781 </ul> 782 </li> 783 </ul> 784 </li> 785 <li>If no: 786 <ul> 787 <li>Check any other exits.</li> 788 </ul> 789 </li> 790 </ul> 791 792 <p>Here we go.</p> 793 794 <div class="code"> 795 <ul> 796 <li> 797 <ul> 798 <li> 799 <ul> 800 <li> 801 <ul> 802 <li><span class="comment">//let's see if we can unlock the exit and remove it from the locked 803 list</span></li> 804 <li><span class="keyword">if</span> (<span class="object">exitRoom</span>.<span 805 class="property">locked</span> && <span class="object">exitRoom</span>.<span 806 class="property">locked</span>.<span class="property">length</span> > 0) 807 </li> 808 <li>{ 809 <ul> 810 <li><span class="keyword">for</span> (<span class="keyword">var</span> lock = 0; lock < <span 811 class="object">exitRoom</span>.<span class="property">locked</span>.<span class="property">length</span>; 812 lock++) 813 </li> 814 <li>{ 815 <ul> 816 <li><span class="keyword">var</span> keyNeeded = <span class="object">exitRoom</span>.<span 817 class="property">locked</span>[lock]; 818 </li> 819 <li><span class="keyword">var</span> keyIndex = foundKeys.<span 820 class="function">indexOf</span>(keyNeeded); 821 </li> 822 <li> </li> 823 <li><span class="keyword">if</span> (keyIndex >= 0 && lockIndex >= 0) <span class="comment">//we 824 have the key and the door is locked</span></li> 825 <li>{ 826 <ul> 827 <li><span class="object">console</span>.<span class="function">log</span>(<span 828 class="string">"Unlocked: "</span> + <span class="object">exitRoom</span>.<span 829 class="property">name</span>); 830 </li> 831 <li>lockedRooms.<span class="function">splice</span>(lockIndex, 1); <span class="comment">//remove 832 locked room from the list</span></li> 833 <li> </li> 834 <li><span class="keyword">if</span> (lockedRooms.<span class="property">length</span> === 835 0) <span class="comment">//if no rooms are still locked, we're good</span></li> 836 <li>{ 837 <ul> 838 <li><span class="object">player</span>.<span class="property">_tempkeys</span> = 839 foundKeys; <span class="comment">//in case these keys are needed to test other room 840 sets</span></li> 841 <li><span class="keyword">return true</span>;</li> 842 </ul> 843 </li> 844 <li>}</li> 845 <li><span class="keyword">else</span></li> 846 <li>{ 847 <ul> 848 <li><span class="object">exitList</span>.<span class="function">push</span>(<span 849 class="object">exitRoom</span>.<span class="property">name</span>); <span 850 class="comment">//now that the room is not locked, we might go that way</span> 851 </li> 852 </ul> 853 </li> 854 <li>}</li> 855 </ul> 856 </li> 857 858 <li>} <span class="comment">//closes the unlock door is statement</span></li> 859 </ul> 860 </li> 861 <li>} <span class="comment">//closes the check for all keys that could unlock the door</span></li> 862 </ul> 863 </li> 864 <li>} <span class="comment">//closes the check to see if the exit is locked</span></li> 865 </ul> 866 </li> 867 </ul> 868 </li> 869 </ul> 870 </li> 871 </ul> 872 </div> 873 <p>Really deep, wasn't it?</p> 874 875 876 <h2 id="step12">Step 12: Finishing the 'exits' loop</h2> 877 <p>We are getting close to the finish. We have one more detail to tend to before we close up the 'exits' loop.</p> 878 879 <p>The first time through the 'iteration' loop, we're just checking the room we're in to make sure we can leave it. If 880 we can, it will have already been placed on the <code>exitList</code>. But right now, it's trying to loop through 881 all the exits of that room, so if it has four exits, then this room will end up on that list four times. It's not a 882 big deal, really, but unnecessary. So, if we're still in the first iteration of the loop, let's break out of it 883 here, then end the 'exits' loop.</p> 884 885 <div class="code"> 886 <ul> 887 <li> 888 <ul> 889 <li> 890 <ul> 891 <li> 892 <ul> 893 <li><span class="comment">//the first iteration tests the start room itself; we don't need to check 894 its exits yet</span></li> 895 <li><span class="keyword">if</span> (i === 0)</li> 896 <li>{ 897 <ul> 898 <li><span class="keyword">break</span>;</li> 899 </ul> 900 </li> 901 <li>}</li> 902 </ul> 903 </li> 904 <li>} <span class="comment">//closes the loop that runs through the current room's possible exits</span> 905 </li> 906 </ul> 907 </li> 908 </ul> 909 </li> 910 </ul> 911 </div> 912 913 914 <h2 id="step13">Step 13: Closing the 'iteration' loop</h2> 915 <p>At this point in the function, whatever room the computer-player is in, all the exits have been checked and 916 possibly unlocked. We have a list of exits we can possibly go to.</p> 917 918 <p>Now we need to pick one of the those exits at random—that's where the name <em>random walk</em> comes from—and 919 move the player there to keep the check going.</p> 920 921 <div class="code"> 922 <ul> 923 <li> 924 <ul> 925 <li> 926 <ul> 927 <li><span class="comment">//now we have a list of viable exits the player could go into in 928 <em>exitList</em></span> 929 </li> 930 <li><span class="comment">//let's randomly pick one and make that the new location</span> 931 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"Exits: 932 "</span> + exitList); 933 </li> 934 <li><span class="keyword">if</span> (exitList.<span class="property">length</span> === 0) <span 935 class="comment">//there are no exits; the player is trapped, so this check fails</span></li> 936 <li>{ 937 <ul> 938 <li><span class="keyword">break</span>;</li> 939 </ul> 940 </li> 941 <li>}</li> 942 <li> </li> 943 <li><span class="keyword">var</span> randomExit = <span class="object">Math</span>.<span class="function">floor</span>(<span 944 class="object">Math</span>.<span class="function">random</span>() * exitList.<span class="property">length</span>); 945 </li> 946 <li>playerRoom = exitList[randomExit];</li> 947 </ul> 948 </li> 949 <li>} <span class="comment">//end of the random walk 'iteration' loop</span></li> 950 </ul> 951 </li> 952 </ul> 953 </div> 954 955 <h2 id="step14">Step 14: Finishing the function</h2> 956 957 <p>Ok, we set the computer-player loose in the rooms, picking up keys and unlocking doors, seeing if it was possible 958 to unlock them all. If it <em>is</em>, then this function escaped back up when the <code>lockedRooms</code> array 959 was emptied out.</p> 960 961 <p>We just closed the 'iteration' loop a moment ago, so what's left to do? Well, if the function hasn't returned a 962 successful rating at this point, then it means the computer was not able to unlock everything in the number of steps 963 (iterations) it had available.</p> 964 965 <p>So all that's left is to send that result back and close the function.</p> 966 967 <p>We're there... at the end. Let's finish this function!</p> 968 969 <div class="code"> 970 <ul> 971 <li> 972 <ul> 973 <li><span class="object">console</span>.<span class="function">log</span>(<span class="string">"Couldn't 974 unlock everything."</span>); 975 </li> 976 <li><span class="keyword">return false</span>;</li> 977 </ul> 978 </li> 979 <li>}</li> 980 </ul> 981 </div> 982 983 <h2>What's next?</h2> 984 <p>That was a lot, but you got to this point. Now you need to test it out. Here's one way.</p> 985 986 <ol> 987 <li>Make sure you have at least one locked room and one key set up in your layout.</li> 988 <li>Run your game. If you're in the text version, quit when you can.</li> 989 <li>Get to the console window while your game variables are in memory. 990 <ul> 991 <li>In <code>repl.it</code>, click on the console tab.</li> 992 <li>In a browser, open developer tools. Try pressing <kbd class="key">f12</kbd>.</li> 993 </ul> 994 </li> 995 <li>Call the new function from the console. 996 <ul> 997 <li>This will run the default: Full room set based on the player's current room.</li> 998 <li><code>checkKeys();</code></li> 999 <li>Or substitute in other values as desired. 1000 <li>Choose a specific room to start checking from. 1001 <ul> 1002 <li><code>checkKeys(rooms, "den", false);</code></li> 1003 </ul> 1004 </li> 1005 <li>Send in a subset of rooms and a starting room (you have to create the <code>firstfloor</code> set first) 1006 <ul> 1007 <li><code>checkKeys(firstFloor, "stairway", false);</code></li> 1008 </ul> 1009 </li> 1010 <li>Let the computer pick a random room and test it out 1011 <ul> 1012 <li><code>checkKeys(rooms, "", true);</code></li> 1013 <li>The console will tell you which room was the starting point if you have this line of code in there 1014 before the iteration loop starts. 1015 <ul> 1016 <li><code><span class="object">console</span>.<span class="function">log</span>(<span class="string">"start 1017 room: "</span> + playerStart);</code></li> 1018 </ul> 1019 </li> 1020 </ul> 1021 </li> 1022 </ul> 1023 </li> 1024 <li>Read the output in the console. 1025 <ul> 1026 <li>If it says <span class="keyword">true</span> then it works with the settings you put in. Congrats!</li> 1027 <li>If it says <span class="keyword">false</span>, it's <em>possible</em> the setup could still be correct. 1028 <ul> 1029 <li>This is because we're testing by random walk, not by a tree search.</li> 1030 <li>You could run it again with the same settings and see if it figures it out a second time.</li> 1031 <li>But it did run 1000 to 10000 steps through your house... Unless you passed in a lot of rooms at once, 1032 maybe it just won't work the way it's set up. 1033 </li> 1034 </ul> 1035 </li> 1036 </ul> 1037 </li> 1038 <li>Adjust your locks and keys as needed.</li> 1039 </ol> 1040 1041 <h2>What if I want to use other randomizers?</h2> 1042 <p>If you plan to use randomizers like <span class="function">randomizeRoomLayout</span>, <span class="function">randomizePlayerStart</span>, 1043 or <span class="function">randomizeLocksAndKeys</span>, then you'll need to use the <span 1044 class="function">checkKeys</span> function inside <span class="function">startGame</span>.</p> 1045 1046 <p>Here's a quick brute-force solution. It will cause your game to shuffle things a bunch of times until the game is 1047 playable. That might cause it to hang when you start it up.</p> 1048 1049 1050 <h4>Original code section</h4> 1051 <p>Inside your <span class="function">startGame</span> function, you have a set of lines that look like this, though 1052 possibly in a different order and some may be missing if you didn't add certain features.</p> 1053 1054 <div class="code"> 1055 <ul> 1056 <li><span class="object">rooms</span> = <span class="function">randomizeRoomLayout</span>(<span class="object">rooms</span>); 1057 </li> 1058 <li><span class="object">rooms</span> = <span class="function">randomizeBrokenThings</span>(<span class="object">rooms</span>); 1059 </li> 1060 <li><span class="function">randomizePlayerStart</span>(<span class="object">rooms</span>);</li> 1061 <li><span class="function">randomizeItems</span>(<span class="object">rooms</span>);</li> 1062 <li><span class="function">randomizePoints</span>(<span class="object">rooms</span>);</li> 1063 <li><span class="object">rooms</span> = <span class="function">randomizeKeys</span>(<span 1064 class="object">rooms</span>, <span class="keyword">true</span>); 1065 </li> 1066 </ul> 1067 </div> 1068 1069 <h4>Reorganize those lines to this</h4> 1070 <p>We need to group together just the functions that affect the lock and key situation.</p> 1071 1072 <div class="code"> 1073 <ul> 1074 <li><span class="object">rooms</span> = <span class="function">randomizeRoomLayout</span>(<span class="object">rooms</span>); 1075 </li> 1076 <li><span class="object">rooms</span> = <span class="function">randomizeKeys</span>(<span 1077 class="object">rooms</span>, <span class="keyword">true</span>); 1078 </li> 1079 <li><span class="function">randomizePlayerStart</span>(<span class="object">rooms</span>);</li> 1080 <li> </li> 1081 <li><span class="object">rooms</span> = <span class="function">randomizeBrokenThings</span>(<span class="object">rooms</span>); 1082 </li> 1083 <li><span class="function">randomizeItems</span>(<span class="object">rooms</span>);</li> 1084 <li><span class="function">randomizePoints</span>(<span class="object">rooms</span>);</li> 1085 </ul> 1086 </div> 1087 1088 <h4>Wrap the related randomizers in a loop</h4> 1089 <p>We don't want this to run forever. We want it to break out at some point no matter what. I'm going to have two 1090 checks. One is an iteration counter and the other is whether we are successful.</p> 1091 1092 <p>I'm setting up the two variable first and then wrapping the related function in the loop. The other functions will 1093 be after the loop. I'm not deleting them.</p> 1094 <div class="code"> 1095 <ul> 1096 1097 <li><span class="keyword">var</span> successful = <span class="keyword">false</span>;</li> 1098 <li><span class="keyword">var</span> attempts = 0;</li> 1099 <li> </li> 1100 <li><span class="keyword">while</span> (!successful && attempts < 1000)</li> 1101 <li>{ 1102 <ul> 1103 <li><span class="object">rooms</span> = <span class="function">randomizeRoomLayout</span>(<span 1104 class="object">rooms</span>); 1105 </li> 1106 <li><span class="object">rooms</span> = <span class="function">randomizeKeys</span>(<span 1107 class="object">rooms</span>, <span class="keyword">true</span>); 1108 </li> 1109 <li><span class="function">randomizePlayerStart</span>(<span class="object">rooms</span>);</li> 1110 <li>successful = <span class="function">checkKeys</span>(<span class="object">rooms</span>, <span 1111 class="object">player</span>.<span class="property">currentRoom</span>.<span class="property">name</span>, 1112 <span class="keyword">false</span>); 1113 </li> 1114 <li>attempts++;</li> 1115 </ul> 1116 </li> 1117 <li>}</li> 1118 <li> </li> 1119 <li><span class="keyword">if</span> (!successful)</li> 1120 <li>{ 1121 <ul> 1122 <li><span class="function">alert</span>(<span class="string">"I got stuck and couldn't unlock everything. You 1123 might want to restart and let me try again."</span>); 1124 </li> 1125 </ul> 1126 </li> 1127 <li>}</li> 1128 <li> </li> 1129 <li><span class="comment">//these function calls are still here from when we sorted them a moment ago</span></li> 1130 <li><span class="object">rooms</span> = <span class="function">randomizeBrokenThings</span>(<span class="object">rooms</span>); 1131 </li> 1132 <li><span class="function">randomizeItems</span>(<span class="object">rooms</span>);</li> 1133 <li><span class="function">randomizePoints</span>(<span class="object">rooms</span>);</li> 1134 </ul> 1135 </div> 1136 1137 <h4>alert vs throw</h4> 1138 <p>Typically, instead of an <span class="function">alert</span>, programmers would use a <span 1139 class="keyword">throw</span> to cause a "crash" in the browser. It's on purpose, so it's not the same as when 1140 something goes wrong. The <span class="function">alert</span> is less scary. If want to use the <span 1141 class="keyword">throw</span>, swap out the <span class="function">alert</span> line with this.</p> 1142 1143 <div class="code"> 1144 <ul> 1145 <li> 1146 <ul> 1147 <li> 1148 <span class="keyword">throw</span> <span class="string">"I got stuck and couldn't unlock everything. You 1149 might want to restart and let me try again.";</span> 1150 </li> 1151 </ul> 1152 </li> 1153 </ul> 1154 </div> 1155 1156 <p>When you <span class="keyword">throw</span> an error, the program stops running completely. There's more you can do 1157 with <span class="keyword">throw</span>, but we're not getting into it right here.</p> 1158 1159 <h4>Simpler success?</h4> 1160 <p>Because of how we set up our <span class="function">checkKeys</span> function, we could simplify this line as 1161 shown.</p> 1162 1163 <div class="code"> 1164 <ul> 1165 <li> 1166 <li>successful = <span class="function">checkKeys</span>(<span class="object">rooms</span>, <span 1167 class="object">player</span>.<span class="property">currentRoom</span>.<span class="property">name</span>, 1168 <span class="keyword">false</span>); 1169 </li> 1170 <li> 1171 <li>successful = <span class="function">checkKeys</span>(); <span class="comment">//much shorter</span></li> 1172 </ul> 1173 </div> 1174 <p>But this is only ok to do if we are using the global set of all rooms. Currently, my code here does. But it's 1175 better to send in the expected arguments any time you can for readability and code clarity.</p> 1176 1177 1178 <h2>May you always be able to unlock the doors to your future!</h2> 1179 <h2>—Dr. Wolf</h2> 1180 1181 <div id="prevnext"></div> 1182 <!-- required section for navigation sidebar --></div> 1183 <script src="/navigator.js"></script> 1184 <script>begin("roomadventure");</script> 1185 <!-- end of required section for navigation sidebar --> 1186 </body> 1187 </html> 1188