;; SUMMARY ;;;; A block-busting game! ;; COPYRIGHT & LICENSE ;;;; Copyright (C) 2005 James P. Steiner ;;;; Some Rights Reserved. ;;;; Creative Commons Attribution-NonCommercial-ShareAlike License v. 2.0. ;;;; Visit http://creativecommons.org/licenses/by-nc-sa/2.0/ for more information. ;; remove comment symbols below and at bottom (on "to noise") to enable sounds ;; __extensions [ "sound.jar" ] globals [ click? ;; used by the mouse handler to tell if the mouse is down click ;; click-start ;; click-list ;; list of locations that the mouse has been clicked ;; in other words, the input buffer game-area ;; agentset of patches in the play area top-row ;; agentset of top row of play area bottom-row ;; agentset of bottom row of play area left-most ;; xcor of the left most col in the play area right-most ;; xcor of the right most col in the play area top-most ;; ycor of the top most row in the play area bottom-most ;; ycor of the top most row in the play area block-fade-time ;; how long for clicked groups to fade to black and vanish score ;; current score tumble! ;; flag that tells the game to tumble the blocks next-click ;; holds the time that the auto-player will click again. tumble-count ;; holds count of number of consecutive tubles tumble-limit ;; holds the limit of tumbles before game over game-over? ;; flag that tells the game that the game is over level ;; the current difficulty ] patches-own [ timeout ;; color-group ;; used when testing clicks mode ; 0 = normal, 1 = clicked / needs testing, 2 = vanishing, 3 = falling, 4 = new game-area? ;; is this patch in the game area temp ;; temporary--various uses my-column ;; contains the patch that is at the base of this patch's column ] breeds [ sparks ;; appear when blocks are removed scores ;; floating numbers blocks ;; future use: for turtle-based version ] sparks-own [ lifespan ;; sparks go out when lifespan reaches 0 ddx ;; acceleration in x ddy ;; acceleration in y ] scores-own [ my-group ;; group the numbers together (not really used yet) lifespan ;; when this reaches 0, scores disappear my-index ;; position of the number in the group ] to startup setup end to setup ca setup-sparks set level difficulty ask patches [ set color-group -1 set game-area? false set my-column nobody ] set left-most (- screen-edge-x) + 1 set right-most (screen-edge-x) - 1 set top-most screen-edge-y - 1 set bottom-most (- screen-edge-y) + 1 set game-area patches with [ pxcor >= left-most and pxcor <= right-most and pycor >= bottom-most and pycor <= top-most ] set bottom-row game-area with [ pycor = bottom-most ] ask bottom-row [ set my-column game-area with [ pxcor = pxcor-of myself ] ] set top-row game-area with [ pycor = top-most ] set block-fade-time .25 ask game-area [ set game-area? true initialize-patch ; set mode 4 ] ask bottom-row [ let eat random 5 ask my-column with [ pycor > top-most - eat ] [ set pcolor black ] ] set click 0 set click? false set click-list [] set tumble-count 0 set tumble-limit 5 set game-over? false set level difficulty let colors remove-duplicates values-from patches [ pcolor ] print "There are " + (length colors - 1)+ " unique colors" end to setup-sparks set-default-shape sparks "spark" end to watch-click if mouse-down? and click = 0 [ set click 1 set click-start patch (round mouse-xcor) (round mouse-ycor) ] if (not mouse-down? ) and click = 1 [ if click-start = patch (round mouse-xcor) (round mouse-ycor) [ set click-list lput click-start click-list ] set click 0 ] end to-report get-clicked [ check-or-get ] locals [ clicked-item ] ifelse check-or-get = 0 [ report (length click-list > 0) ] [ set clicked-item first click-list set click-list but-first click-list report clicked-item ] end to go locals [ xclick yclick clicked ] if game-over? = 2 [ setup ] every .05 [ ifelse game-over? != false [ go-game-over if game-over? = 2 [ stop ] ] [ ;; always watch for click-events ;; check for click event if not auto-play? [ watch-click ] ;; always do sparks go-sparks ;; always do scores go-scores ;; any open blocks? let blocks fall in, set as needing testing, ;; unless these are add-in blocks ifelse any? game-area with [ pcolor = black and pcolor-of patch-at 0 1 > white ] [ noise 1 (20 + random 40) .5 let index (- screen-edge-y) repeat screen-size-y [ ask game-area with [ pycor = index and pcolor = black and pcolor-of patch-at 0 1 > white ] [ set pcolor pcolor-of patch-at 0 1 set mode mode-of patch-at 0 1 ask patch-at 0 1 [ set pcolor black set mode 0 ] ] set index index + 1 ] ] [ ;; above will continue until all falling blocks have fallen ;; now, if there are any empty columns (bottom row cell is black), ;; slide columns left or right, toward center column ;; find left-most non-empty column let left-x 0 let right-x 0 if any? (bottom-row with [ pcolor != black ]) [ set left-x min values-from (bottom-row with [ pcolor != black ]) [ pxcor ] set right-x max values-from (bottom-row with [ pcolor != black ]) [ pxcor ] ] ;; find center-most empty column let empty-column max-one-of (bottom-row with [ pxcor > left-x and pxcor < right-x and pcolor = black ]) [ abs pxcor ] ifelse is-patch? empty-column [ let direction 1 set pcolor-of empty-column white ifelse pxcor-of empty-column = 0 [ set direction (((random 2) * 2) - 1) ] [ if pxcor-of empty-column < 0 [ set direction -1 ] ] ask my-column-of empty-column [ set pcolor pcolor-of patch-at direction 0 set pcolor-of patch-at direction 0 black ] ][ ;; now that all falling blocks have settled ;; examine blocks marked to be tested (mode = 3) ifelse any? game-area with [ mode = 3 ] [ ask game-area with [ mode = 3 ] [ test-block ] ] [ ;; now that all blockes have been tested ;; (and now that any cascading fall / test cycles have ended) ;; unmark fall-only blocks (change 4 to 0) ask game-area with [ mode = 4 ] [ set mode 0 ] ;; there's probably some blocks to fade. ;; fade them ifelse any? game-area with [ mode = 2 ] [ ask game-area with [ mode = 2 ] [ set pcolor scale-color pcolor (timeout - timer) (0) (block-fade-time) if timer > timeout [ make-spark set pcolor black set mode 0 set timeout 0 ] ] ] [ ;; see if there's any tumbling to do ;; ifelse tumble! = true [ tumble ] [ ;; finally, things have settled down ;; so lets check for auto-play or user input ;; that is, a click event. ifelse auto-play? [ ;; auto-play is on, so get a click from the selectect ;; auto-player set clicked auto-player-click ] [ ;; otherwise, pull click events off click stack ;; from the human player if get-clicked 0 = true [ set clicked (get-clicked 1) ] ;; make sure the clicked patch in in the game area if any? game-area with [ self = clicked and mode = 0 ] [ set mode-of clicked 3 ] ] ] ] ] ] ] ] ] end to find-same-colors [ the-color the-group ] locals [ new-members ] without-interruption [ set new-members neighbors4 with [ pcolor = the-color and color-group = -1 ] if any? new-members [ ask new-members [ set color-group the-group ] ask new-members [ find-same-colors pcolor the-group ] ] ] end to initialize-patch let colors [ 15 45 75 105 135 25 55 85 115 35 65 95 125 ] set pcolor item (random (1 + level)) colors set mode 4 set color-group -1 end to test-block locals [ selected-group ] ifelse pcolor = black [ set mode 0 show "empty" ] [ without-interruption [ ; if mode != 3 [ stop ] set color-group abs (pxcor * pycor) find-same-colors pcolor color-group set selected-group game-area with [ color-group = color-group-of myself ] show (word pcolor " " selected-group) ifelse count selected-group >= 3 [ set tumble-count 0 ask selected-group [ set mode 2 ; fading set timeout timer + block-fade-time set color-group -1 ] let group-size count selected-group let new-score group-size * group-size * level * level set score score + new-score num-to-turtles new-score self (screen-size-x / 15) gray noise 1 (30 + 3 * ((group-size + pycor) mod 12) ) .5 ] [ show "not enough" ask selected-group [ set mode 0 set color-group -1 ] ] ] ] end to tumble set tumble! false set score score - 10 if score < 0 [ set score 0 ] set tumble-count tumble-count + 1 if tumble-count > tumble-limit [ set game-over? true ] ask game-area [ set temp pcolor-of patch (- pycor) ( pxcor) ] ask game-area [ set pcolor temp ] end to make-spark ;; make sparks! let index -45 sprout 1 [ set breed sparks set color pcolor + 8 set size 1 set lifespan 15 set heading -45 + (22.5 * (who mod 6)); index let spark-speed 1 + random-float .5 set ddx dx * spark-speed set ddy dy * spark-speed set index index + 45 ] end to go-sparks ask sparks [ if lifespan < 1 [ die ] if size * .99 < .1 [ die ] if size < .1 [ die ] set ddy ddy - .075 if (ycor + ddy ) > screen-edge-y [ set ddy 0 ] if abs (xcor + ddx ) > screen-edge-x [ set ddx (- ddx) * .85 ] if abs (ycor + ddy ) > screen-edge-y [ set ddy (- ddy) * .85 ] if abs (ycor + ddy) < (- screen-edge-y ) or abs (xcor + ddx ) > screen-edge-x [ die ] set color 139.99 - color ;; white ; 15 + random 5 + 10 * random 13 set size size * .99 set lifespan lifespan - 1 setxy (xcor + ddx) (ycor + ddy) ] end to go-scores ask scores [ if lifespan < 1 [ die ] if size * .99 < .1 [ die ] if size < .1 [ die ] if pycor + .1 > screen-edge-y [ die ] set ycor ycor + .01 ;; set xcor xcor + random-float .01 set size size * 0.99 set lifespan lifespan - 1 set color color + 10 ] end to num-to-turtles [ num location scale hue ] ;; converts a number to a series of turtles of breed "scores" that look like the number ;; convert num to string of numbers ;; only positive integerts here! set num (word abs int num) let index 0 ask location [ sprout 1 [ set breed scores let char substring num index (index + 1) set shape char set my-group self set my-index index set lifespan 20 set size scale set color hue set ycor ycor + 3 hatch ((length num) - 1) [ set index index + 1 set char substring num index (index + 1) set shape char set my-index index set xcor xcor + index * size * .66 set size size * (1 + .25 * (index mod 2)) ] ] ] end to-report auto-player-click locals [ clicked ] set clicked nobody if next-click < timer [ set next-click timer + auto-play-speed * .25 ifelse auto-player = "Randomia" [ set clicked auto-player-random ][ ifelse auto-player = "Centrella" [ set clicked auto-player-center ][ ifelse auto-player = "Specificious" [ set clicked auto-player-color-killer ][ ]]] ifelse clicked = nobody [ set tumble! true ] [ set mode-of clicked 3 ] ] report clicked end to-report auto-player-random ;; randomly clicks a block of three or more report (random-one-of game-area with [ pcolor != black and count ( neighbors4 with [ pcolor = pcolor-of myself ] ) > 1 ] ) end to-report auto-player-center ;; prefers to click blocks in the center nearest the bottom, ;; always clicking a group of three or more, ;; with no preference for size report (min-one-of game-area with [ pcolor != black and count ( neighbors4 with [ pcolor = pcolor-of myself ] ) > 1 ] [ pycor + abs (pxcor)] ) end to-report auto-player-color-killer ;; prefers to click blocks of groups of three or more ;; trying to eliminate one color before doing the next color report (min-one-of game-area with [ pcolor != black and count ( neighbors4 with [ pcolor = pcolor-of myself ] ) > 1 ] [ pcolor] ) end to-report auto-player-bottom ;; prefers to click blocks on the bottom ;; always clicking a group of three or more, ;; with no preference for size report (min-one-of game-area with [ pcolor != black and count ( neighbors4 with [ pcolor = pcolor-of myself ] ) > 1 ] [ pycor ] ) end to go-game-over ifelse game-over? = true [ set plabel-of patch 15 10 "* GAME OVER *" set plabel-of patch 15 13 "SCORE: " + score set plabel-of patch 15 7 "Click PLAY " set plabel-of patch 15 4 "to try again." ask game-area with [ pcolor != black ] [ make-spark ] set game-over? 1 ] [ if game-over? = 1 [ ifelse any? sparks [ go-sparks ] [ set game-over? 2 ] ] ] end to noise [ sfx input1 input2 ] ;; remove comment symbols below and at top (on __extensions) to enable sounds ;; ifelse sfx = 1 ;; [ ;; input1 = group-size, input2 = pcolor ;; play-note (random-one-of ["WOODBLOCK" ]) input1 volume input2 ;; ][ ;; ] end @#$#@#$#@ GRAPHICS-WINDOW 236 10 698 493 15 15 14.6 1 48 1 1 1 0 0 0 1 CC-WINDOW 5 514 894 609 Command Center 0 BUTTON 11 46 105 79 New Game setup NIL 1 T OBSERVER T N BUTTON 11 82 111 115 Play / Pause go T 1 T OBSERVER NIL P TEXTBOX 29 266 186 401 Click New Game, then Play.\n\nClick on any group of 3 or more blocks of the same color to make the group vanish. Use Tumble to rearrange the blocks, but lose 10 points! Tumble more than 5 times in a row... GAME OVER! MONITOR 121 11 208 60 NIL Score 0 1 BUTTON 116 75 171 108 Tumble! set tumble! true NIL 1 T OBSERVER T T SLIDER 10 10 105 43 Difficulty Difficulty 1 10 4 1 1 NIL SWITCH 27 127 131 160 auto-play? auto-play? 0 1 -1000 BUTTON 64 127 177 160 Auto-Play On/Off set auto-play? not auto-play? NIL 1 T OBSERVER T A MONITOR 172 66 231 115 Tumbles tumble-count 0 1 CHOOSER 36 166 174 211 auto-player auto-player "Randomia" "Centrella" "Specificious" 2 OUTPUT 17 413 214 500 SLIDER 713 102 885 135 volume volume 0 127 28 1 1 NIL SLIDER 36 213 174 246 auto-play-speed auto-play-speed 1 10 1 1 1 NIL @#$#@#$#@ WHAT IS IT? ----------- A half-completed block-clicking game. HOW TO USE IT ------------- Click New Game to reset the field and score. Click Play to activate the game. Click on blocks to try to bust them. Only groups of 3 or more of the same color will break. If you can't find any to break, click TUMBLE! If you tumble 5 times in a row, GAME-OVER! EXTENDING THE MODEL ------------------- Add more rules. Make it so that levels advance! Make it so that auto-tumble is possible (same rules the auto-play rules use to detect auto-tumble. Make the auto-player smarter--clicking larger groups first, or planning ahead to create larger groups. Add "special" blocks (use turtles for special block shapes), like one that removes an entire row or column, or a "wild-card" block, or a block that matches all the blocks around it, when it is clicked... NETLOGO FEATURES ---------------- For the blocks, just patches and patch variables are used. The Mouse features are used (of course). The sparks that occur when a block is removed are turtles! This game uses the "every" command to control game timing. The floating scores are also turtles... the number is converted to a series of turtles that look like numbers. they have an "index" variable that tells them what order to appear in. There are sound features in this model, but they are disabled for posting to the web. Remove comments from PLAY-NOTE and __extensions commands! @#$#@#$#@ default true 0 Polygon -7500403 true true 150 5 40 250 150 205 260 250 0 false 0 Polygon -16777216 true false 60 45 75 30 90 15 105 15 120 30 210 30 255 75 255 240 270 270 240 300 75 300 45 270 30 165 45 60 Polygon -7500403 true true 60 77 93 76 93 242 119 257 185 255 193 282 120 285 64 260 Polygon -7500403 true true 74 41 213 281 243 262 96 25 Polygon -7500403 true true 127 59 182 60 200 76 204 185 226 218 229 77 201 36 111 35 1 false 0 Polygon -16777216 true false 45 60 105 0 195 0 195 210 225 210 240 285 210 300 75 300 45 270 60 210 75 210 75 90 Polygon -7500403 true true 76 272 78 237 119 236 121 59 73 61 116 15 167 15 166 243 216 237 206 287 10 false 0 Polygon -7500403 true true 41 88 62 109 98 72 95 255 47 254 50 282 150 285 159 253 129 249 135 53 109 26 Polygon -7500403 true true 168 77 191 52 264 50 293 82 290 241 265 275 229 279 228 243 265 235 267 88 210 88 195 233 215 246 214 279 179 269 164 240 2 false 0 Polygon -16777216 true false 45 135 15 75 60 15 105 0 150 0 225 0 270 75 270 135 195 195 270 195 285 285 150 300 15 285 30 210 105 150 Rectangle -7500403 true true 223 223 223 225 Polygon -7500403 true true 254 242 229 277 53 268 63 226 146 152 177 116 174 37 127 35 122 91 103 117 59 106 53 73 100 22 151 9 218 27 237 82 233 118 145 192 97 228 230 208 3 false 0 Polygon -16777216 true false 90 105 30 60 60 0 150 0 225 0 255 60 240 135 270 225 240 300 150 300 60 300 15 240 75 180 Polygon -7500403 true true 108 87 132 53 176 57 191 88 160 125 113 130 112 169 163 171 191 209 190 227 152 257 124 254 91 212 53 228 91 282 150 297 217 275 244 216 228 162 191 147 229 115 231 68 207 30 163 9 107 7 56 50 4 false 0 Polygon -16777216 true false 15 135 105 0 255 0 225 105 270 120 285 195 210 210 255 255 255 300 60 300 60 255 90 225 15 195 Polygon -7500403 true true 139 16 47 142 49 176 144 176 137 253 108 255 106 285 226 283 232 249 181 248 189 178 250 177 256 135 193 141 213 13 176 12 144 148 91 140 162 13 5 false 0 Polygon -16777216 true false 15 180 60 15 120 0 270 15 225 90 120 60 120 105 210 105 270 165 255 255 210 300 75 300 0 225 30 180 Polygon -7500403 true true 245 24 213 70 106 36 91 135 137 121 189 122 226 161 233 196 225 246 174 282 105 288 54 242 29 220 75 196 115 268 161 259 178 206 173 144 127 148 85 173 39 160 96 15 6 false 0 Polygon -16777216 true false 30 60 75 0 240 0 285 60 270 120 240 120 285 180 285 255 225 300 75 300 15 255 0 120 Polygon -7500403 true true 254 97 260 67 216 27 174 12 101 17 57 65 24 156 44 229 92 276 170 288 227 259 271 220 254 158 197 122 131 113 99 124 95 138 121 169 143 136 199 149 211 217 168 268 102 258 84 166 91 112 115 38 178 37 193 74 226 97 7 false 0 Polygon -16777216 true false 45 15 270 15 270 60 165 300 45 300 150 105 15 105 Polygon -7500403 true true 81 27 242 35 131 286 88 284 188 68 58 76 8 false 0 Polygon -16777216 true false 60 105 45 45 75 0 225 0 270 45 270 120 225 150 255 210 255 270 210 300 75 300 15 255 15 180 Polygon -7500403 true true 99 84 177 215 181 258 147 260 105 240 101 180 117 164 92 127 63 153 38 197 88 276 159 296 232 269 218 195 183 146 142 74 140 31 185 35 196 85 179 94 194 133 229 102 243 51 188 7 121 0 85 25 81 63 9 false 0 Polygon -16777216 true false 30 180 15 135 15 45 60 0 240 0 285 45 285 240 255 285 195 300 90 300 30 270 30 225 90 195 135 225 135 195 Polygon -7500403 true true 180 134 123 133 96 114 95 58 129 34 185 35 205 55 205 212 168 260 106 258 85 231 56 242 72 266 94 278 155 291 224 266 254 211 251 47 221 23 169 1 122 4 83 21 49 52 50 100 57 129 78 153 141 170 186 171 burst true 0 Line -7500403 true 146 16 150 36 Line -7500403 true 191 23 184 41 Line -7500403 true 240 52 215 73 Line -7500403 true 270 101 229 119 Line -7500403 true 259 152 276 147 Line -7500403 true 252 180 285 199 Line -7500403 true 239 211 250 219 Line -7500403 true 202 237 223 261 Line -7500403 true 184 255 184 260 Line -7500403 true 143 259 156 300 Line -7500403 true 118 247 89 285 Line -7500403 true 86 230 77 235 Line -7500403 true 72 207 34 220 Line -7500403 true 56 162 46 160 Line -7500403 true 58 134 3 130 Line -7500403 true 21 183 43 177 Line -7500403 true 61 195 57 198 Line -7500403 true 38 109 46 112 Line -7500403 true 24 77 62 93 Line -7500403 true 62 62 67 66 Line -7500403 true 62 28 117 66 Line -7500403 true 116 12 128 41 Line -7500403 true 124 93 126 125 Line -7500403 true 186 97 178 106 Line -7500403 true 107 194 124 181 Line -7500403 true 202 203 189 191 explosion true 0 Polygon -7500403 true true 105 164 73 151 104 139 85 110 133 127 128 88 148 105 170 90 174 117 206 119 179 140 209 155 157 158 178 179 148 175 148 206 127 181 84 200 86 173 1 165 56 136 26 83 96 89 105 15 145 63 204 14 196 79 281 70 245 105 296 129 223 143 295 175 210 184 244 262 196 209 182 285 167 209 100 283 115 224 31 234 spark false 5 Polygon -10899396 true true 150 15 180 105 285 105 195 165 225 255 150 195 75 255 105 165 30 105 120 105 square false 5 Rectangle -10899396 true true 0 0 300 300 star false 5 Polygon -10899396 true true 150 15 180 105 285 105 195 165 225 255 150 195 75 255 105 165 30 105 120 105 @#$#@#$#@ NetLogo 3.0.2 @#$#@#$#@ @#$#@#$#@ @#$#@#$#@ @#$#@#$#@