'From Squeak3.6 of ''6 October 2003'' [latest update: #5424] on 30 November 2003 at 11:08:33 am'! "Change Set: Ns Game Date: 25 October 2003 Author: Stephan B. Wessels Updated 30-Nov-2003 sbw Modified game board layout code to use explicit frames and offsets. Cosmetic changes to buttons and colors. Modified tile mix ratios. Trimmed possible game board sizes. Embedded colors control panel in main game morph. Updated 15-Nov-2003 sbw Colors customization support. Updated 8-Nov-2003 sbw Better instructions and comments added to all game classes. NsGame began as a Squeak port of the Shockwave Flash game by Pavils Jurjans. See http://www.jurjans.lv/stuff/net/freenet.htm. To begin the game perform: NsGame new openInWorld "! RectangleMorph subclass: #NsGame instanceVariableNames: 'gameModel board status count max moves ' classVariableNames: 'Rules ' poolDictionaries: '' category: 'NsTileGame'! !NsGame commentStamp: 'sbw 11/8/2003 09:28' prior: 0! This is the main game morph for playing the game NsGame. To open the morph do NsGame new openInWorld A game board will be presented. There is an Instructions button which provides a number of details on how the game operates. The instructions are created using a GeeMailMorph. To update the instructions, open them via the instructions button, extract the GeeMailMorph from the opened window and then edit the GeeMailMorph in the usual manner. Once you have completed your changes to the GeeMailMorph, use the debug menu and save the morph in a file. There were some issues with saving stand-alone GeeMailMorphs in Squeak 3.6 at the time this game was created so the change set includes 2 patches to support that operation. After the morph is saved in a file, use the FileList and compress the morph file. Once you have the file compressed, use the FileList and select the file and then choose to copy the name of the file to the Clipboard. Perform the following line of Squeak code in a workspace with that full file name path. The file path shown here is an example of course. NsGame convertSavedMorphFile: 'Meine Welt:Users:steve:Develop:squeak:3.6:my GeeMailMorph.morph.gz'. A workspace window will be opened showing the hex converted ascii for binary contained in the compressed morph. Copy the contents of that text window into the NsGame class>>compressedEncodedInstructions method. You can test your new instructions after completing this step.! Object subclass: #NsGameTile instanceVariableNames: 'form orientation active ' classVariableNames: 'Colors ' poolDictionaries: '' category: 'NsTileGame'! !NsGameTile commentStamp: 'sbw 11/8/2003 08:24' prior: 0! This is the top of the NsGame tiles hierarchy. The hierarchy is divided into the kinds of tiles, those having no connections, one connection, two connections, three connections or four. The game uses Forms for drawing the game pieces. There are 2 states for each game piece (active or idle). Each game piece also has forms to represent the tile in each of the 4 possible positions. Note that for some (blank and cross) there is only one rotation position. Forms for each rotated position were used to account for possible errors in drawing symmetry. All forms are actually stored on class instance variables in the hierarchy. Note that a class instance variable exists for each instance of a class and is not the same object as a class variable. The subclasses of this hierarchy contain an elegant model for defining only what is different between the game tile pieces. ! NsGameTile subclass: #NsFourConnectionsGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsFourConnectionsGameTile commentStamp: 'sbw 11/8/2003 08:25' prior: 0! This tile piece abstract class is the super class of all game pieces that have 4 connections. Pieces in this hierarchy do not rotate. ! NsFourConnectionsGameTile subclass: #NsCrossGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsCrossGameTile commentStamp: 'sbw 11/8/2003 08:25' prior: 0! The Cross game tile piece.! NsGameTile class instanceVariableNames: 'ActiveCachedForms IdleCachedForms '! Object subclass: #NsModel instanceVariableNames: 'initialPositions pieces extent maxConnected currentCount destinationAddresses sourceAddress moves gameMorph ' classVariableNames: 'RandomNumberGenerator ' poolDictionaries: '' category: 'NsTileGame'! !NsModel commentStamp: 'sbw 11/8/2003 08:30' prior: 0! The model contains the logic to the game. It also contains each game piece and the state of all the counters.! NsGameTile subclass: #NsNoConnectionsGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsNoConnectionsGameTile commentStamp: 'sbw 11/8/2003 08:25' prior: 0! This tile piece abstract class is the super class of all game pieces that have no connections. Pieces in this hierarchy do not rotate. ! NsNoConnectionsGameTile subclass: #NsBlankGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsBlankGameTile commentStamp: 'sbw 11/8/2003 08:26' prior: 0! The Blank tile game piece.! NsGameTile subclass: #NsOneConnectionGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsOneConnectionGameTile commentStamp: 'sbw 11/8/2003 08:26' prior: 0! This hierarchy includes only the game pieces having one connection. Each piece can have 4 rotated positions. ! NsOneConnectionGameTile subclass: #NsDestinationGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsDestinationGameTile commentStamp: 'sbw 11/8/2003 08:27' prior: 0! An instance of this game piece is an end point for the power grid. There may be more than one destination piece on a game board, depending on the size of the board. ! NsOneConnectionGameTile subclass: #NsSourceGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsSourceGameTile commentStamp: 'sbw 11/8/2003 08:27' prior: 0! This is the power source for the game board or grid. There is only one on any game board. ! NsGameTile subclass: #NsThreeConnectionsGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsThreeConnectionsGameTile commentStamp: 'sbw 11/8/2003 08:28' prior: 0! This hierarchy includes only the game pieces having three connections. Each piece can have 4 rotated positions. ! NsThreeConnectionsGameTile subclass: #NsTeeGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsTeeGameTile commentStamp: 'sbw 11/8/2003 08:28' prior: 0! The Tee shaped game piece.! NsGameTile subclass: #NsTwoConnectionsGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsTwoConnectionsGameTile commentStamp: 'sbw 11/8/2003 08:29' prior: 0! This hierarchy includes only the game pieces having two connections. Each piece can have 4 rotated positions because of possible errors in piece drawing symmetry.! NsTwoConnectionsGameTile subclass: #NsCornerGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsCornerGameTile commentStamp: 'sbw 11/8/2003 08:29' prior: 0! The corner piece.! NsTwoConnectionsGameTile subclass: #NsLineGameTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NsTileGame'! !NsLineGameTile commentStamp: 'sbw 11/8/2003 08:29' prior: 0! The horizontal or vertical game tile.! !HandMorph methodsFor: '*nsTileGame-objects from disk' stamp: 'sbw 11/8/2003 07:06'! objectForDataStream: refStrm "I am about to be written on an object file. Write a path to me in the other system instead." | dp | refStrm project isNil ifFalse: [(refStrm project world hands includes: self) ifTrue: [^ self]]. "owned by the project" dp _ DiskProxy global: #World selector: #primaryHand args: #(). refStrm replace: self with: dp. ^ dp"Note, when this file is loaded in an MVC project, this will return nil. The MenuItemMorph that has this in a field will have that item not work. Maybe warn the user at load time?"! ! !NsGame methodsFor: 'events' stamp: 'sbw 11/27/2003 10:09'! click: evt forMorph: aSketchMorph | selectedCell | selectedCell _ self selectedCellClicked: evt forMorph: aSketchMorph. selectedCell isNil ifFalse: [Sensor shiftPressed ifTrue: [self gameModel rotateCellRight: selectedCell forMorph: aSketchMorph] ifFalse: [self gameModel rotateCellLeft: selectedCell forMorph: aSketchMorph]. self gameModel updateMoves. self gameModel update. self gameModel renderCellsOn: aSketchMorph form. aSketchMorph layoutChanged]! ! !NsGame methodsFor: 'events' stamp: 'sbw 11/25/2003 06:27'! help ^ NsGame helpWindow! ! !NsGame methodsFor: 'events' stamp: 'sbw 11/25/2003 06:29'! newGame self newGameOfSize: self gameModel extent! ! !NsGame methodsFor: 'events' stamp: 'sbw 11/25/2003 06:29'! newGameOfSize: aPoint self gameModel: (NsModel new: aPoint gameMorph: self). board newForm: self gameModel renderCells. self registerSelectedBoardEvents! ! !NsGame methodsFor: 'events' stamp: 'sbw 11/30/2003 11:04'! newSize | choices index point initial choiceStrings reply | initial _ {7. 8. 9. 10. 11. 12. 13}. choices _ OrderedCollection new. choices add: 'enter value'. initial do: [:x | choices add: x @ x. x < 9 ifTrue: [choices add: x @ (x + 1); add: x @ (x + 2); add: x @ (x + 3); add: x @ (x + 4)]]. choiceStrings _ choices collect: [:x | x isPoint ifTrue: [x = self defaultGameSize ifTrue: [x printString , ' DEFAULT'] ifFalse: [x printString]] ifFalse: [x]]. reply _ (EmphasizedMenu selections: choiceStrings emphases: (choices collect: [:it | it = self gameModel extent ifTrue: [#bold] ifFalse: [#plain]])) startUpWithCaption: 'Choose new game size'. reply isNil ifFalse: [index _ choiceStrings indexOf: reply. index = 1 ifTrue: [point _ self promptForNewSize. point isNil ifTrue: [^ self]] ifFalse: [point _ choices at: index]. self newGameOfSize: point. self extent: self calculatedExtent]! ! !NsGame methodsFor: 'events' stamp: 'sbw 11/25/2003 06:29'! promptForNewSize | prompt array x y | prompt _ FillInTheBlank request: 'Enter x@y dimensions'. prompt isEmpty ifTrue: [^ nil]. array _ prompt findTokens: $@. x _ array first asNumber. y _ array second asNumber. ^ x @ y! ! !NsGame methodsFor: 'events' stamp: 'sbw 11/27/2003 10:07'! registerSelectedBoardEvents board on: #mouseUp send: #click:forMorph: to: self! ! !NsGame methodsFor: 'events' stamp: 'sbw 11/25/2003 06:29'! restart self gameModel restartWith: board! ! !NsGame methodsFor: 'events' stamp: 'sbw 11/27/2003 10:27'! selectedCellClicked: evt forMorph: aSketchMorph | clickPosn cellSize selectedCell guess1 guess2 guess3 tolerance | clickPosn _ evt cursorPoint - aSketchMorph position. cellSize _ aSketchMorph extent // self gameModel extent. tolerance _ 1. guess1 _ clickPosn // cellSize. guess1 _ guess1 + 1. guess2 _ clickPosn - tolerance // cellSize. guess2 _ guess2 + 1. guess3 _ clickPosn + tolerance // cellSize. guess3 _ guess3 + 1. selectedCell _ nil. (guess1 = guess2 and: [guess1 = guess3]) ifTrue: [((guess1 x > 0 and: [guess1 x <= self gameModel extent x]) and: [guess1 y > 0 and: [guess1 y <= self gameModel extent y]]) ifTrue: [ selectedCell _ guess1]]. ^ selectedCell ! ! !NsGame methodsFor: 'events' stamp: 'sbw 11/25/2003 06:30'! updateCounters count isNil ifFalse: [count value: self gameModel currentCount. count highlighted: self gameModel circuitComplete]. max isNil ifFalse: [max value: self gameModel maxConnected. max highlighted: self gameModel allTilesActive]. moves isNil ifFalse: [moves value: self gameModel moves]. ^ self gameModel circuitComplete! ! !NsGame methodsFor: 'widgets - counters' stamp: 'sbw 11/27/2003 10:52'! addPanelsToColumn: column panelHeight: countPanelHeight offset: offset | vOffset top bottom | vOffset _ 5. top _ offset copy. bottom _ top + countPanelHeight. self addControl: self makeMovesMorph to: column fractions: (0 @ 0 corner: 1 @ 0) offsets: (self windowPadding x @ top corner: self windowPadding x negated @ bottom). top _ bottom + vOffset. bottom _ top + countPanelHeight. self addControl: self makeCountMorph to: column fractions: (0 @ 0 corner: 1 @ 0) offsets: (self windowPadding x @ top corner: self windowPadding x negated @ bottom). top _ bottom + vOffset. bottom _ top + countPanelHeight. self addControl: self makeMaxMorph to: column fractions: (0 @ 0 corner: 1 @ 0) offsets: (self windowPadding x @ top corner: self windowPadding x negated @ bottom). ^ bottom + vOffset! ! !NsGame methodsFor: 'widgets - counters' stamp: 'sbw 11/25/2003 06:32'! makeCountMorph count _ LedMorph new digits: 3; extent: 3 * 10 @ 15; setBalloonText: (NsGame helpFor: 'ConnectedCounter'). count color: NsGameTile ledColor. ^ self wrapPanel: count label: 'Connected:'! ! !NsGame methodsFor: 'widgets - counters' stamp: 'sbw 11/25/2003 06:32'! makeMaxMorph max _ LedMorph new digits: 3; extent: 3 * 10 @ 15; setBalloonText: (NsGame helpFor: 'MaxCounter'). max color: NsGameTile ledColor. ^ self wrapPanel: max label: 'Max:'! ! !NsGame methodsFor: 'widgets - counters' stamp: 'sbw 11/25/2003 06:32'! makeMovesMorph moves _ LedMorph new digits: 3; extent: 3 * 10 @ 15; setBalloonText: (NsGame helpFor: 'TurnsCounter'). moves color: NsGameTile ledColor. ^ self wrapPanel: moves label: 'Turns:'! ! !NsGame methodsFor: 'widgets - counters' stamp: 'sbw 11/25/2003 06:30'! wrapPanel: anLedPanel label: aLabel "wrap an LED panel in an alignmentMorph with a label above it" | a | a _ AlignmentMorph newColumn wrapCentering: #topLeft; cellPositioning: #topLeft; hResizing: #spaceFill; vResizing: #shrinkWrap; borderWidth: 2; layoutInset: 5; color: Color transparent; useRoundedCorners; borderStyle: (BorderStyle complexAltInset width: 2). a addMorph: anLedPanel. a addMorph: (StringMorph contents: aLabel). ^ a! ! !NsGame methodsFor: 'widgets - buttons' stamp: 'sbw 11/28/2003 16:27'! addButtonToColumn: column buttonHeight: buttonHeight vOffset: vOffset selector: selector top: top | bottom | bottom _ top + buttonHeight. selector = #NONE ifFalse: [self addControl: (self perform: selector) to: column fractions: (0 @ 0 corner: 1 @ 0) offsets: (self windowPadding x @ top corner: self windowPadding x negated @ bottom)]. ^ bottom + vOffset! ! !NsGame methodsFor: 'widgets - buttons' stamp: 'sbw 11/28/2003 16:27'! addButtonsToColumn: column buttonHeight: buttonHeight offset: offset | vOffset top selectors | top _ offset copy. vOffset _ 5. selectors _ #(#makeRestartButton #makeNewGameButton #makeNewSizeButton #makeEditColorsButton #makeHelpButton #NONE #makeCloseGameButton ). selectors do: [:selector | top _ self addButtonToColumn: column buttonHeight: buttonHeight vOffset: vOffset selector: selector top: top]. ^ top! ! !NsGame methodsFor: 'widgets - buttons' stamp: 'sbw 11/28/2003 16:20'! makeButtonNamed: label action: actionSymbol helpKey: helpKey | btn labelMorph | btn _ PluggableButtonMorph on: self getState: nil action: actionSymbol. labelMorph _ StringMorph contents: label. btn label: labelMorph; setBalloonText: (NsGame helpFor: helpKey). self setButtonAttributes: btn. ^ btn! ! !NsGame methodsFor: 'widgets - buttons' stamp: 'sbw 11/28/2003 16:21'! makeCloseGameButton ^self makeButtonNamed: 'End Game' action: #delete helpKey: 'EndGame'! ! !NsGame methodsFor: 'widgets - buttons' stamp: 'sbw 11/28/2003 16:21'! makeEditColorsButton ^ self makeButtonNamed: 'Colors' action: #editColors helpKey: 'Colors'! ! !NsGame methodsFor: 'widgets - buttons' stamp: 'sbw 11/28/2003 16:22'! makeHelpButton ^ self makeButtonNamed: 'Instructions' action: #help helpKey: 'Help'! ! !NsGame methodsFor: 'widgets - buttons' stamp: 'sbw 11/28/2003 16:22'! makeNewGameButton ^ self makeButtonNamed: 'New Game' action: #newGame helpKey: 'NewGame' ! ! !NsGame methodsFor: 'widgets - buttons' stamp: 'sbw 11/28/2003 16:23'! makeNewSizeButton ^ self makeButtonNamed: 'New Size' action: #newSize helpKey: 'NewSize' ! ! !NsGame methodsFor: 'widgets - buttons' stamp: 'sbw 11/28/2003 16:23'! makeRestartButton ^ self makeButtonNamed: 'Restart' action: #restart helpKey: 'Restart' ! ! !NsGame methodsFor: 'widgets - buttons' stamp: 'sbw 11/25/2003 06:29'! setButtonAttributes: btn btn useRoundedCorners; hResizing: #spaceFill; onColor: Color transparent offColor: Color transparent; borderWidth: 2; borderColor: #raised; fillWithRamp: self windowColorRamp oriented: 0.1 @ 0.8. btn label color: Color white! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/25/2003 06:54'! addControl: aMorph to: column fractions: fractions offsets: offsets aMorph isNil ifFalse: [column addMorph: aMorph fullFrame: (LayoutFrame fractions: (fractions) offsets: (offsets))]! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/29/2003 20:05'! addMorphs self addMorph: self makeControls fullFrame: (LayoutFrame fractions: (0 @ 0 corner: 0 @ 1) offsets: (0 @ 0 corner: self controlPanelWidth @ 0)). self addMorph: self makeGameBoardMorph fullFrame: (self boardMorphLayoutFrame)! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/29/2003 20:04'! boardMorphLayoutFrame ^LayoutFrame fractions: (0 @ 0 corner: 1 @ 1) offsets: (self controlPanelWidth @ self windowPadding y corner: self windowPadding negated)! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/25/2003 06:26'! calculatedExtent | pt | pt _ self gameModel renderFormSize + self windowExtra. ^ pt x @ (pt y max: 380)! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/26/2003 17:42'! controlPanelWidth ^ 100! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/25/2003 06:26'! defaultBounds "answer the default bounds for the receiver" ^ 0 @ 0 corner: self calculatedExtent! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/27/2003 11:03'! makeControls | column countPanelHeight buttonHeight top | column _ RectangleMorph new borderWidth: 0; color: Color transparent; layoutPolicy: ProportionalLayout new. column name: 'controls'. countPanelHeight _ 40. buttonHeight _ 24. top _ self addPanelsToColumn: column panelHeight: countPanelHeight offset: self windowPadding y. top _ self addButtonsToColumn: column buttonHeight: buttonHeight offset: top. ^ column ! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/25/2003 06:28'! makeGameBoardMorph board _ SketchMorph withForm: self gameModel renderCells. board name: 'board'. self registerSelectedBoardEvents. ^ board! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/28/2003 17:09'! setWindowColors self setWindowColorsOn: self! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/28/2003 17:09'! setWindowColorsOn: target target borderWidth: 4; borderColor: (Color r: 0.369 g: 0.369 b: 0.505); useRoundedCorners. target fillWithRamp: self windowColorRamp oriented: 0.4 @ 0.35! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/25/2003 06:25'! windowColorRamp ^ {0.0 -> (Color r: 0.7 g: 0.7 b: 1.0). 1.0 -> (Color r: 0.3 g: 0.3 b: 0.4)}! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/26/2003 17:23'! windowExtra ^ self controlPanelWidth @ 0 + ((self windowPadding) * 2)! ! !NsGame methodsFor: 'widgets' stamp: 'sbw 11/26/2003 17:22'! windowPadding ^ 10 @ 10! ! !NsGame methodsFor: 'initialization' stamp: 'sbw 11/28/2003 13:40'! initialize self gameModel: (NsModel new: (self defaultGameSize) gameMorph: self). super initialize. self layoutPolicy: ProportionalLayout new. self setWindowColors. self addMorphs! ! !NsGame methodsFor: 'accessing' stamp: 'sbw 11/28/2003 13:40'! defaultGameSize ^7 @ 11 ! ! !NsGame methodsFor: 'accessing' stamp: 'sbw 11/25/2003 06:24'! gameModel ^ gameModel! ! !NsGame methodsFor: 'accessing' stamp: 'sbw 11/25/2003 06:24'! gameModel: anNsModel gameModel _ anNsModel! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/29/2003 20:10'! buildColorsMorph | colorsMorph buttonMorph colorsTableMorph | colorsTableMorph _ self editColorsControlMorph. buttonMorph _ self resetColorsButtonMorph. colorsMorph _ AlignmentMorph newColumn beTransparent. colorsMorph addMorphBack: colorsTableMorph; addMorphBack: buttonMorph. buttonMorph color: Color transparent. ^ colorsMorph! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/25/2003 06:26'! currentColor: key ^ NsGameTile colors at: key! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/25/2003 06:26'! currentColor: key new: newColor NsGameTile colors at: key put: newColor. self updateColors! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/29/2003 20:19'! editColors true ifTrue: [self editColorsInternalPane] ifFalse: [self editColorsUseExternalWindow]! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/28/2003 16:57'! editColorsControlMorph | tags tag tableMorph row swatch stringMorph | tags _ NsGameTile colorTags. tableMorph _ AlignmentMorph newColumn beTransparent. NsGameTile editableColorKeys do: [:key | tag _ tags at: key. row _ AlignmentMorph newRow beTransparent. swatch _ ColorSwatch new target: self; getSelector: #currentColor:; putSelector: #currentColor:new:; argument: key; extent: 40 @ 20; setBalloonText: 'click here to change the color'; yourself. row addTransparentSpacerOfSize: 4 @ 0. row addMorphBack: swatch. row addTransparentSpacerOfSize: 6 @ 0. stringMorph _ StringMorph contents: tag. row addMorphBack: stringMorph. row addTransparentSpacerOfSize: 4 @ 0. tableMorph addMorphBack: row]. ^ tableMorph! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/29/2003 20:18'! editColorsInternalPane "Borrow the status instance variable for now." status == nil ifTrue: [status _ true. self hideBoard. self showColors] ifFalse: [status _ nil. self hideColors. self showBoard]! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/29/2003 20:18'! editColorsUseExternalWindow | topView colorsMorph | topView _ SystemWindow labelled: 'NsGame Colors'. topView model: self. self class customizeSystemWindow: topView. colorsMorph _ self buildColorsMorph. topView addMorph: colorsMorph fullFrame: (LayoutFrame fractions: (0 @ 0 corner: 1 @ 1) offsets: (0 @ 0 corner: 0 @ 0)). topView openInWorld. colorsMorph useGradientFill ! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/29/2003 20:01'! experiment status == nil ifTrue: [status _ true. self hideBoard. self showColors] ifFalse: [status _ nil. self hideColors. self showBoard]! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/25/2003 06:27'! hideBoard (self submorphNamed: 'board') hide! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/29/2003 20:01'! hideColors | m | m _ self submorphNamed: 'colors'. m isNil ifFalse: [m hide]! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/25/2003 06:27'! hideControls (self submorphNamed: 'controls') hide! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/25/2003 06:27'! initialExtent "Extent used for colors window." ^ 250 @ 200! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/25/2003 06:29'! resetColors NsGameTile initializeColors. self updateColors! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/28/2003 16:54'! resetColorsButtonMorph | btn labelMorph am | btn _ PluggableButtonMorph on: self getState: nil action: #resetColors. labelMorph _ StringMorph contents: 'Reset to default colors'. btn label: labelMorph; setBalloonText: 'Reset to using default colors'. self setButtonAttributes: btn. am _ AlignmentMorph newRow wrapCentering: #topLeft; cellPositioning: #topLeft; hResizing: #shrinkWrap; vResizing: #spaceFill; borderWidth: 0; layoutInset: 5; color: Color white. am addMorphBack: btn. ^ am! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/25/2003 06:30'! showBoard (self submorphNamed: 'board') show! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/29/2003 20:23'! showColors | m | m _ self submorphNamed: 'colors'. m isNil ifTrue: [m _ self wrapPanel: self buildColorsMorph label: 'Colors'. m name: 'colors'. m color: (Color r: 1 g: 1 b: 1 alpha: 0.3). self addMorph: m fullFrame: self boardMorphLayoutFrame]. m show! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/25/2003 06:30'! showControls (self submorphNamed: 'controls') show! ! !NsGame methodsFor: 'colors mods' stamp: 'sbw 11/25/2003 06:30'! updateColors NsGameTile updateColors. (self submorphNamed: 'board') newForm: gameModel renderCells! ! !NsGame class methodsFor: 'instructions' stamp: 'sbw 11/29/2003 20:47'! compressedEncodedInstructions ^ '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 +LPwCvt58+YKm7sSb2vT5v8DRS0okODOAQA='! ! !NsGame class methodsFor: 'instructions' stamp: 'sbw 10/28/2003 13:46'! convertSavedMorphFile: fileName "Save the GeeMail morph, compress it in FileList and then copy the file name (path) for this method. Copy the ASCII text into the #compressedEncodedInstructions method." | fileStream encoded | fileStream _ FileStream oldFileNamed: fileName. encoded _ Base64MimeConverter mimeEncode: fileStream. fileStream close. encoded contents openInWorkspaceWithTitle: 'Copy this to #compressedEncodedInstructions'! ! !NsGame class methodsFor: 'instructions' stamp: 'sbw 11/15/2003 07:45'! customizeSystemWindow: topView topView setWindowColor: (Color r: 0.603 g: 0.603 b: 0.85). topView removeMenuBox; removeExpandBox; removeCollapseBox. ! ! !NsGame class methodsFor: 'instructions' stamp: 'sbw 11/15/2003 07:46'! helpWindow "NsGame helpWindow" | topView morph | topView _ SystemWindow labelled: 'NsGame Instructions'. morph _ NsGame instructions. topView addMorph: morph frame: (0 @ 0 corner: 1 @ 1). self customizeSystemWindow: topView. morph borderColor: Color transparent; borderWidth: 0; scrollBarOnLeft: false; showScrollBar; retractable: false. topView openInWorld! ! !NsGame class methodsFor: 'instructions' stamp: 'sbw 10/28/2003 13:29'! instructions | encodedTutorial zippedString data rwStream | encodedTutorial _ self compressedEncodedInstructions. zippedString _ Base64MimeConverter mimeDecode: encodedTutorial as: String. data _ zippedString unzipped. rwStream _ RWBinaryOrTextStream with: data. rwStream reset; fileIn. ^SmartRefStream scannedObject.! ! !NsGame class methodsFor: 'as yet unclassified' stamp: 'sbw 10/19/2003 17:04'! helpFor: aKey ^ self rules at: aKey ifAbsent: ['?']! ! !NsGame class methodsFor: 'as yet unclassified' stamp: 'sbw 11/30/2003 11:06'! initializeHelp "NsGame initializeHelp" | dict | dict _ Dictionary new. dict at: 'EndGame' put: 'Ends game and closes window.'; at: 'ConnectedCounter' put: 'Shows how many powered cells you have. Counter turns yellow when all destination cells are powered.'; at: 'MaxCounter' put: 'Shows the highest number of connected cells for this game.'; at: 'TurnsCounter' put: 'Shows how many turns you have taken.'; at: 'Help' put: 'Opens up help window'; at: 'NewGame' put: 'Start a new game using the same size board.'; at: 'NewSize' put: 'Starts a new game where you choose the grid size.'; at: 'Restart' put: 'Start the existing game over again. The Max counter is not reset when a game is restarted.'; at: 'Colors' put: 'Edit the colors used by the game. This button toggles the display between the game board and the colors control panel.'. self rules: dict! ! !NsGame class methodsFor: 'as yet unclassified' stamp: 'sbw 11/28/2003 16:32'! postLoadOperation "NsGame postLoadOperation" NsGame initializeHelp. NsGameTile initializeForms. NsGameTile initializeColors! ! !NsGame class methodsFor: 'as yet unclassified' stamp: 'sbw 10/19/2003 16:51'! rules Rules == nil ifTrue: [self initializeHelp]. ^Rules! ! !NsGame class methodsFor: 'as yet unclassified' stamp: 'sbw 10/19/2003 15:04'! rules: aDictionary Rules _ aDictionary! ! !NsGame class methodsFor: 'parts bin' stamp: 'sbw 11/10/2003 22:00'! descriptionForPartsBin ^ self partName: 'NsGame' categories: #('Games' ) documentation: 'A power-circuit tile game.'! ! !NsGameTile methodsFor: 'events' stamp: 'sbw 10/17/2003 13:56'! rotateLeft | value | value _ self orientation. value _ value + 1. value > self class maxOrientations ifTrue: [value _ 1]. self orientation: value! ! !NsGameTile methodsFor: 'events' stamp: 'sbw 10/17/2003 13:56'! rotateRight | value | value _ self orientation. value _ value - 1. value < 1 ifTrue: [value _ self class maxOrientations]. self orientation: value! ! !NsGameTile methodsFor: 'accessing' stamp: 'sbw 10/16/2003 14:23'! active active isNil ifTrue: [self active: false]. ^active! ! !NsGameTile methodsFor: 'accessing' stamp: 'sbw 10/16/2003 14:23'! active: aBoolean active _ aBoolean! ! !NsGameTile methodsFor: 'accessing' stamp: 'sbw 10/16/2003 15:03'! form ^self active ifTrue: [self class activeCachedForms at: self orientation] ifFalse: [self class idleCachedForms at: self orientation] ! ! !NsGameTile methodsFor: 'accessing' stamp: 'sbw 10/16/2003 09:18'! form: aForm form _ aForm! ! !NsGameTile methodsFor: 'accessing' stamp: 'sbw 10/16/2003 14:22'! orientation orientation isNil ifTrue: [self orientation: 1]. ^orientation! ! !NsGameTile methodsFor: 'accessing' stamp: 'sbw 10/16/2003 14:22'! orientation: int orientation _ int! ! !NsGameTile methodsFor: 'neighbors' stamp: 'sbw 10/17/2003 15:20'! neighborDeltas ^ OrderedCollection new! ! !NsGameTile methodsFor: 'testing' stamp: 'sbw 10/26/2003 08:04'! canBeActive ^true! ! !NsGameTile methodsFor: 'testing' stamp: 'sbw 10/17/2003 14:05'! isSource ^false! ! !NsGameTile methodsFor: 'printing' stamp: 'sbw 10/18/2003 13:20'! printOn: aStream super printOn: aStream. aStream cr; nextPutAll: ' ' , self class tileName; cr; nextPutAll: ' Active: ', self active printString; cr; nextPutAll: ' Orientation: ', self orientation printString! ! !NsFourConnectionsGameTile methodsFor: 'neighbors' stamp: 'sbw 10/17/2003 14:15'! neighborDeltas ^OrderedCollection with: -1@0 with: 0@-1 with: 1@0 with: 0@1! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 04:54'! activeLineColor ^self colors at: 'activeLineColor'! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 21:49'! activeLineColorString ^ 'Active Line Color'! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 04:55'! backgroundColor ^ self colors at: 'backgroundColor'! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 21:49'! backgroundColorString ^ 'Background Color'! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 04:56'! borderColor ^ self colors at: 'borderColor'! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 21:50'! borderColorString ^ 'Border Color'! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 04:57'! boxColor ^ self colors at: 'boxColor'! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 21:50'! boxColorString ^'Box Color'! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/15/2003 06:40'! colorTags | dict selector value | dict _ Dictionary new. self editableColorKeys do: [:key | selector _ (key , 'String') asSymbol. value _ self perform: selector. dict at: key put: value]. ^ dict! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/15/2003 06:40'! editableColorKeys ^(OrderedCollection new) add: 'activeLineColor'; add: 'backgroundColor'; add: 'borderColor'; add: 'boxColor'; add: 'idleLineColor'; yourself ! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 04:57'! idleLineColor ^ self colors at: 'idleLineColor' ! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 21:50'! idleLineColorString ^'Idle Line Color'! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/28/2003 17:01'! initializeColors "NsGameTile initializeColors" | dict | dict _ Dictionary new. dict at: 'activeLineColor' put: (Color r: 0.972 g: 0.595 b: 0.349); at: 'backgroundColor' put: (Color r: 0.8 g: 0.8 b: 0.8); at: 'borderColor' put: Color white; at: 'boxColor' put: Color blue; at: 'idleLineColor' put: (Color r: 0.297 g: 0.297 b: 0.4); at: 'ledColor' put: (Color r: 0.674 g: 0.674 b: 0.96). self colors: dict! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 04:58'! ledColor ^self colors at: 'ledColor'! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 21:51'! ledColorString ^'LED Color'! ! !NsGameTile class methodsFor: 'colors' stamp: 'sbw 11/13/2003 05:01'! updateColors self initializeForms! ! !NsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:15'! borderWidth ^ 2! ! !NsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:16'! extent ^ 30 @ 30! ! !NsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:16'! formDepth ^ 16! ! !NsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:18'! lineWidth ^ 2! ! !NsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:18'! maxConnections ^ self subclassResponsibility! ! !NsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:18'! maxOrientations ^ self subclassResponsibility! ! !NsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:38'! tileName ^ self subclassResponsibility! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 09:22'! activeCachedForms ^ActiveCachedForms! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:05'! activeCachedForms: aDictionary ActiveCachedForms _ aDictionary! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:50'! displayForms "NsGameTile displayForms" | xPos yPos form maxPos | yPos _ 10. maxPos _ 0. (self allSubclasses select: [:cls | cls hasForms]) do: [:subclass | xPos _ 10. 1 to: subclass maxOrientations do: [:index | form _ subclass activeCachedForms at: index. form displayAt: xPos @ yPos. xPos + form extent x > maxPos ifTrue: [maxPos _ xPos + form extent x]. xPos _ xPos + 10 + self extent x]. yPos _ yPos + 10 + self extent y]. yPos _ 10. (self allSubclasses select: [:cls | cls hasForms]) do: [:subclass | xPos _ maxPos + 10. 1 to: subclass maxOrientations do: [:index | form _ subclass idleCachedForms at: index. form displayAt: xPos @ yPos. xPos _ xPos + 10 + self extent x]. yPos _ yPos + 10 + self extent y]! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:53'! eastLineSegment: beActive | line lineFillForm x1 y1 p1 x2 y2 p2 | line _ Line new. lineFillForm _ Form extent: self lineWidth @ self lineWidth depth: self formDepth. lineFillForm fillColor: (beActive ifTrue: [self activeLineColor] ifFalse: [self idleLineColor]). line form: lineFillForm. x1 _ self extent x // 2. y1 _ self extent y // 2 - (self lineWidth // 2). p1 _ x1 @ y1. line beginPoint: p1. x2 _ self extent x. y2 _ y1. p2 _ x2 @ y2. line endPoint: p2. ^ line! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:16'! fullHorizontalMiddleLine: beActive | line lineFillForm x1 y1 p1 x2 y2 p2 | line _ Line new. lineFillForm _ Form extent: self lineWidth @ self lineWidth depth: self formDepth. lineFillForm fillColor: (beActive ifTrue: [self activeLineColor] ifFalse: [self idleLineColor]). line form: lineFillForm. x1 _ 0. y1 _ self extent y // 2 - (self lineWidth // 2). p1 _ x1 @ y1. line beginPoint: p1. x2 _ self extent x. y2 _ y1. p2 _ x2 @ y2. line endPoint: p2. ^ line! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:17'! fullVerticalMiddleLine: beActive | line lineFillForm x1 y1 p1 x2 y2 p2 | line _ Line new. lineFillForm _ Form extent: self lineWidth @ self lineWidth depth: self formDepth. lineFillForm fillColor: (beActive ifTrue: [self activeLineColor] ifFalse: [self idleLineColor]). line form: lineFillForm. x1 _ self extent x // 2 - (self lineWidth // 2). y1 _ 0. p1 _ x1 @ y1. line beginPoint: p1. x2 _ x1. y2 _ self extent y. p2 _ x2 @ y2. line endPoint: p2. ^ line! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:08'! hasForms ^false! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 09:22'! idleCachedForms ^ IdleCachedForms! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:05'! idleCachedForms: aDictionary IdleCachedForms _ aDictionary! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:17'! initializeActiveForms ^ self subclassResponsibility! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:49'! initializeForms "NsGameTile initializeForms" (self allSubclasses select: [:cls | cls hasForms]) do: [:subclass | subclass initializeActiveForms. subclass initializeIdleForms]! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:17'! initializeIdleForms ^ self subclassResponsibility! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:56'! northLineSegment: beActive | line lineFillForm x1 y1 p1 x2 y2 p2 | line _ Line new. lineFillForm _ Form extent: self lineWidth @ self lineWidth depth: self formDepth. lineFillForm fillColor: (beActive ifTrue: [self activeLineColor] ifFalse: [self idleLineColor]). line form: lineFillForm. x1 _ self extent x // 2 - (self lineWidth // 2). y1 _ 0. p1 _ x1 @ y1. line beginPoint: p1. x2 _ x1. y2 _ self extent y // 2. p2 _ x2 @ y2. line endPoint: p2. ^ line! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:57'! southLineSegment: beActive | line lineFillForm x1 y1 p1 x2 y2 p2 | line _ Line new. lineFillForm _ Form extent: self lineWidth @ self lineWidth depth: self formDepth. lineFillForm fillColor: (beActive ifTrue: [self activeLineColor] ifFalse: [self idleLineColor]). line form: lineFillForm. x1 _ self extent x // 2 - (self lineWidth // 2). y1 _ self extent y // 2. p1 _ x1 @ y1. line beginPoint: p1. x2 _ x1. y2 _ self extent y. p2 _ x2 @ y2. line endPoint: p2. ^ line! ! !NsGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:54'! westLineSegment: beActive | line lineFillForm x1 y1 p1 x2 y2 p2 | line _ Line new. lineFillForm _ Form extent: self lineWidth @ self lineWidth depth: self formDepth. lineFillForm fillColor: (beActive ifTrue: [self activeLineColor] ifFalse: [self idleLineColor]). line form: lineFillForm. x1 _ 0. y1 _ self extent y // 2 - (self lineWidth // 2). p1 _ x1 @ y1. line beginPoint: p1. x2 _ self extent x // 2. y2 _ y1. p2 _ x2 @ y2. line endPoint: p2. ^ line! ! !NsGameTile class methodsFor: 'accessing' stamp: 'sbw 11/13/2003 04:52'! colors Colors == nil ifTrue: [self initializeColors]. ^ Colors! ! !NsGameTile class methodsFor: 'accessing' stamp: 'sbw 11/13/2003 04:51'! colors: dict Colors _ dict! ! !NsFourConnectionsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:18'! maxConnections ^ 4! ! !NsFourConnectionsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:19'! maxOrientations ^ 1! ! !NsCrossGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:09'! hasForms ^ true! ! !NsCrossGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:35'! initializeActiveForms | orientationForm line | self activeCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self fullHorizontalMiddleLine: true. line displayOn: orientationForm. line _ self fullVerticalMiddleLine: true. line displayOn: orientationForm. self activeCachedForms at: 1 put: orientationForm! ! !NsCrossGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:33'! initializeIdleForms | orientationForm line | self idleCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self fullHorizontalMiddleLine: false. line displayOn: orientationForm. line _ self fullVerticalMiddleLine: false. line displayOn: orientationForm. self idleCachedForms at: 1 put: orientationForm! ! !NsCrossGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:39'! tileName ^'Cross'! ! !NsModel methodsFor: 'logic' stamp: 'sbw 10/19/2003 10:37'! populateWithRandomCells | count | count _ self size // 50. count < 1 ifTrue: [count _ 1]. ^ self populateWithRandomCells: count! ! !NsModel methodsFor: 'logic' stamp: 'sbw 10/19/2003 09:51'! populateWithRandomCells: numberOfDestinations | howMany address cell | howMany _ self size. sourceAddress _ self randomCellAddress. self pieces at: sourceAddress put: NsSourceGameTile new. numberOfDestinations timesRepeat: [address _ self randomUnusedCellAddress. self destinationAddresses add: address. self pieces at: address put: NsDestinationGameTile new]. howMany _ howMany - 1 - numberOfDestinations. howMany timesRepeat: [address _ self randomUnusedCellAddress. cell _ self randomCell. self pieces at: address put: cell]. self initialPositions: Dictionary new. self pieces keysDo: [:addr | self initialPositions at: addr put: (self pieces at: addr) deepCopy]! ! !NsModel methodsFor: 'logic' stamp: 'sbw 11/28/2003 16:42'! randomCell "NsModel example:7@5" | random percentLine percentCorner percentTee percentCross | percentLine _ 32. percentCorner _ 20. percentTee _ 37. percentCross _ 10. random _ self class randomNumberGenerator nextInt: 100. random < percentLine ifTrue: [^ NsLineGameTile new]. random < (percentLine + percentCorner) ifTrue: [^ NsCornerGameTile new]. random < (percentLine + percentCorner + percentTee) ifTrue: [^ NsTeeGameTile new]. random < (percentLine + percentCorner + percentTee + percentCross) ifTrue: [^ NsCrossGameTile new]. ^ NsBlankGameTile new! ! !NsModel methodsFor: 'logic' stamp: 'sbw 10/19/2003 09:51'! size ^self extent x * self extent y! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 10:08'! currentCount ^currentCount! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 10:08'! currentCount: int currentCount _ int! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 10:12'! destinationAddresses ^destinationAddresses! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 10:12'! destinationAddresses: aColl destinationAddresses _ aColl! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/16/2003 14:12'! extent ^extent! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/16/2003 14:12'! extent: aPoint extent _ aPoint! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 10:29'! gameMorph ^gameMorph! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 10:29'! gameMorph: aMorph gameMorph _ aMorph! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 13:10'! initialPositions ^initialPositions! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 13:10'! initialPositions: aCollection initialPositions _ aCollection! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 10:08'! maxConnected ^maxConnected! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 10:06'! maxConnected: int maxConnected _ int! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 10:22'! moves ^moves! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/18/2003 10:22'! moves: int moves _ int! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/16/2003 14:20'! pieces pieces isNil ifTrue: [self initializePieces]. ^ pieces! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/16/2003 14:00'! pieces: aCollection pieces _ aCollection! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/16/2003 14:32'! randomCellAddress | xPos yPos | xPos _ self class randomNumberGenerator nextInt: self extent x. yPos _ self class randomNumberGenerator nextInt: self extent y. ^ xPos @ yPos! ! !NsModel methodsFor: 'accessing' stamp: 'sbw 10/16/2003 14:45'! randomUnusedCellAddress | random | [random _ self randomCellAddress. self pieces includesKey: random] whileTrue. ^ random! ! !NsModel methodsFor: 'events' stamp: 'sbw 11/15/2003 06:27'! restartWith: aMorph self. self initialPositions keysDo: [:addr | self pieces at: addr put: (self initialPositions at: addr) deepCopy]. self currentCount: 0. self moves: -1. self updateMoves. self update. self renderCellsOn: aMorph form. aMorph changed! ! !NsModel methodsFor: 'events' stamp: 'sbw 10/17/2003 14:00'! rotateCellLeft: aPoint forMorph: aSketchMorph (self pieces at: aPoint) rotateLeft. ! ! !NsModel methodsFor: 'events' stamp: 'sbw 10/17/2003 14:00'! rotateCellRight: aPoint forMorph: aSketchMorph (self pieces at: aPoint) rotateRight. ! ! !NsModel methodsFor: 'events' stamp: 'sbw 11/15/2003 06:26'! update self updateActiveStates. self currentCount: (self pieces select: [:each | each active]) size - 1. self currentCount > self maxConnected ifTrue: [self maxConnected: self currentCount]. self updateCounters! ! !NsModel methodsFor: 'events' stamp: 'sbw 10/17/2003 15:05'! updateActiveStates | sourcePieceAddress eachPiece | sourcePieceAddress _ self pieces keys detect: [:address | (self pieces at: address) isSource] ifNone: []. self pieces keys do: [:address | eachPiece _ self pieces at: address. eachPiece active: false]. "The source will always answer true to active." self updateActiveStatesForNeighborsAt: sourcePieceAddress! ! !NsModel methodsFor: 'events' stamp: 'sbw 10/17/2003 14:57'! updateActiveStatesForNeighborsAt: address | rootPiece deltas nextAddress nextPiece | rootPiece _ self pieces at: address. rootPiece active ifFalse: [^ self]. deltas _ rootPiece neighborDeltas. deltas do: [:delta | nextAddress _ address + delta. (self isAddressValid: nextAddress) ifTrue: [nextPiece _ self pieces at: nextAddress. nextPiece active ifFalse: [(self doesNextAddress: nextAddress pointBackTo: address) ifTrue: [nextPiece active: true. self updateActiveStatesForNeighborsAt: nextAddress]]]]! ! !NsModel methodsFor: 'events' stamp: 'sbw 11/15/2003 06:23'! updateCounters self gameMorph isNil ifFalse: [self gameMorph updateCounters]! ! !NsModel methodsFor: 'events' stamp: 'sbw 11/15/2003 06:23'! updateMoves self moves: self moves + 1. self updateCounters! ! !NsModel methodsFor: 'drawing' stamp: 'sbw 10/16/2003 15:08'! renderBordersOn: aForm ! ! !NsModel methodsFor: 'drawing' stamp: 'sbw 10/16/2003 21:03'! renderCells | renderForm | renderForm _ Form extent: self renderFormSize depth: NsGameTile formDepth. renderForm fillColor: NsGameTile borderColor. self renderCellsOn: renderForm. ^ renderForm! ! !NsModel methodsFor: 'drawing' stamp: 'sbw 10/18/2003 10:07'! renderCellsOn: aForm | standardExtent offset location piece | self update. standardExtent _ NsGameTile extent. self pieces keysDo: [:address | offset _ address - 1. location _ offset * standardExtent. location _ location + (address * NsGameTile borderWidth). piece _ self pieces at: address. piece form displayOn: aForm at: location]! ! !NsModel methodsFor: 'drawing' stamp: 'sbw 10/16/2003 15:11'! renderFormSize | basic addX addY | basic _ self extent * NsGameTile extent. addX _ (self extent x + 1) * (NsGameTile borderWidth). addY _ (self extent y + 1) * (NsGameTile borderWidth). ^basic + (addX@addY)! ! !NsModel methodsFor: 'testing' stamp: 'sbw 10/26/2003 08:05'! allTilesActive ^ (self pieces select: [:each | each active]) size = (self pieces select: [:each | each canBeActive]) size! ! !NsModel methodsFor: 'testing' stamp: 'sbw 10/18/2003 10:17'! circuitComplete ^(self destinationAddresses reject: [:addr | (self pieces at: addr) active]) isEmpty! ! !NsModel methodsFor: 'testing' stamp: 'sbw 10/17/2003 15:02'! doesNextAddress: nextAddress pointBackTo: currentAddress | piece deltas goodDeltas calculatedAddress | piece _ self pieces at: nextAddress. deltas _ piece neighborDeltas. goodDeltas _ deltas select: [:delta | calculatedAddress _ nextAddress + delta. (self isAddressValid: calculatedAddress) and: [calculatedAddress = currentAddress]]. ^ goodDeltas notEmpty! ! !NsModel methodsFor: 'testing' stamp: 'sbw 10/17/2003 14:39'! isAddressValid: aPoint aPoint x = 0 ifTrue: [^false]. aPoint y = 0 ifTrue: [^false]. aPoint x > self extent x ifTrue: [^false]. aPoint y > self extent y ifTrue: [^false]. ^true! ! !NsModel methodsFor: 'initialize' stamp: 'sbw 11/15/2003 06:27'! initialize: anExtent gameMorph: aMorph self gameMorph: aMorph. self extent: anExtent. self pieces: nil. self maxConnected: 0. self currentCount: 0. self moves: 0. self destinationAddresses: OrderedCollection new. self populateWithRandomCells! ! !NsModel methodsFor: 'initialize' stamp: 'sbw 10/16/2003 14:20'! initializePieces self pieces: Dictionary new! ! !NsModel class methodsFor: 'instance creation' stamp: 'sbw 10/18/2003 10:33'! new: anExtent "NsModel new: 5@5" | model | model _ self new. model initialize: anExtent. ^ model! ! !NsModel class methodsFor: 'instance creation' stamp: 'sbw 10/18/2003 10:31'! new: anExtent gameMorph: aMorph "NsModel new: 5@5" | model | model _ self new. model initialize: anExtent gameMorph: aMorph. ^ model! ! !NsModel class methodsFor: 'example' stamp: 'sbw 10/16/2003 21:55'! example: aPoint "NsModel example: 5@6" | model | model _ self new: aPoint. model renderCells displayAt: 10 @ 10! ! !NsModel class methodsFor: 'accessing' stamp: 'sbw 10/16/2003 14:32'! randomNumberGenerator RandomNumberGenerator isNil ifTrue: [ RandomNumberGenerator _ Random new. RandomNumberGenerator seed: Time totalSeconds]. ^RandomNumberGenerator! ! !NsBlankGameTile methodsFor: 'testing' stamp: 'sbw 10/26/2003 08:04'! canBeActive ^ false! ! !NsNoConnectionsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:19'! maxConnections ^ 0! ! !NsNoConnectionsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:20'! maxOrientations ^ 1! ! !NsBlankGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:09'! hasForms ^ true! ! !NsBlankGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:35'! initializeActiveForms | orientationForm | self activeCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. self activeCachedForms at: 1 put: orientationForm! ! !NsBlankGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:34'! initializeIdleForms | orientationForm | self idleCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. self idleCachedForms at: 1 put: orientationForm! ! !NsBlankGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:40'! tileName ^ 'Empty'! ! !NsOneConnectionGameTile methodsFor: 'neighbors' stamp: 'sbw 10/17/2003 14:33'! neighborDeltas | delta | delta _ 1 @ 0. self orientation = 2 ifTrue: [delta _ 0 @ -1]. self orientation = 3 ifTrue: [delta _ -1 @ 0]. self orientation = 4 ifTrue: [delta _ 0 @ 1]. ^ OrderedCollection with: delta! ! !NsOneConnectionGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 21:07'! fillBoxesOn: aForm outerColor: outerColor innerColor: innerColor | rect | rect _ (0 @ 0 extent: aForm extent) insetBy: 7. aForm fill: rect fillColor: outerColor. rect _ (0 @ 0 extent: aForm extent) insetBy: 11. aForm fill: rect fillColor: innerColor! ! !NsOneConnectionGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:21'! maxConnections ^ 1! ! !NsOneConnectionGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:21'! maxOrientations ^ 4! ! !NsDestinationGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:10'! hasForms ^ true! ! !NsDestinationGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:35'! initializeActiveForms | orientationForm line | self activeCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self eastLineSegment: true. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self boxColor innerColor: self activeLineColor. self activeCachedForms at: 1 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self northLineSegment: true. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self boxColor innerColor: self activeLineColor. self activeCachedForms at: 2 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self westLineSegment: true. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self boxColor innerColor: self activeLineColor. self activeCachedForms at: 3 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self southLineSegment: true. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self boxColor innerColor: self activeLineColor. self activeCachedForms at: 4 put: orientationForm! ! !NsDestinationGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:34'! initializeIdleForms | orientationForm line | self idleCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self eastLineSegment: false. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self boxColor innerColor: self idleLineColor. self idleCachedForms at: 1 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self northLineSegment: false. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self boxColor innerColor: self idleLineColor. self idleCachedForms at: 2 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self westLineSegment: false. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self boxColor innerColor: self idleLineColor. self idleCachedForms at: 3 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self southLineSegment: false. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self boxColor innerColor: self idleLineColor. self idleCachedForms at: 4 put: orientationForm! ! !NsDestinationGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:40'! tileName ^ 'Destination'! ! !NsSourceGameTile methodsFor: 'testing' stamp: 'sbw 10/17/2003 14:04'! isSource ^true! ! !NsSourceGameTile methodsFor: 'accessing' stamp: 'sbw 10/16/2003 21:06'! active ^true! ! !NsSourceGameTile methodsFor: 'accessing' stamp: 'sbw 10/17/2003 14:12'! active: aBoolean "ignored" active _ true! ! !NsSourceGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:09'! hasForms ^ true! ! !NsSourceGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:35'! initializeActiveForms | orientationForm line | self activeCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self eastLineSegment: true. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self activeLineColor innerColor: self boxColor. self activeCachedForms at: 1 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self northLineSegment: true. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self activeLineColor innerColor: self boxColor. self activeCachedForms at: 2 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self westLineSegment: true. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self activeLineColor innerColor: self boxColor. self activeCachedForms at: 3 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self southLineSegment: true. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self activeLineColor innerColor: self boxColor. self activeCachedForms at: 4 put: orientationForm! ! !NsSourceGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:34'! initializeIdleForms | orientationForm line | self idleCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self eastLineSegment: false. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self idleLineColor innerColor: self boxColor. self idleCachedForms at: 1 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self northLineSegment: false. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self idleLineColor innerColor: self boxColor. self idleCachedForms at: 2 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self westLineSegment: false. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self idleLineColor innerColor: self boxColor. self idleCachedForms at: 3 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self southLineSegment: false. line displayOn: orientationForm. self fillBoxesOn: orientationForm outerColor: self idleLineColor innerColor: self boxColor. self idleCachedForms at: 4 put: orientationForm! ! !NsSourceGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:41'! tileName ^ 'Source'! ! !NsTeeGameTile methodsFor: 'neighbors' stamp: 'sbw 10/17/2003 14:35'! neighborDeltas | delta1 delta2 delta3 | delta1 _ 0 @ 1. delta2 _ 1 @ 0. delta3 _ 0 @ -1. self orientation = 2 ifTrue: [delta1 _ 1 @ 0. delta2 _ 0 @ -1. delta3 _ -1 @ 0]. self orientation = 3 ifTrue: [delta1 _ 0 @ -1. delta2 _ -1 @ 0. delta3 _ 0 @ 1]. self orientation = 4 ifTrue: [delta1 _ 0 @ 1. delta2 _ 1 @ 0. delta3 _ -1@ 0]. ^ OrderedCollection with: delta1 with: delta2 with: delta3! ! !NsThreeConnectionsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:21'! maxConnections ^ 3! ! !NsThreeConnectionsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:22'! maxOrientations ^ 4! ! !NsTeeGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:41'! tileName ^ 'Tee'! ! !NsTeeGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:10'! hasForms ^ true! ! !NsTeeGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:36'! initializeActiveForms | orientationForm line | self activeCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self eastLineSegment: true. line displayOn: orientationForm. line _ self northLineSegment: true. line displayOn: orientationForm. line _ self southLineSegment: true. line displayOn: orientationForm. self activeCachedForms at: 1 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self northLineSegment: true. line displayOn: orientationForm. line _ self westLineSegment: true. line displayOn: orientationForm. line _ self eastLineSegment: true. line displayOn: orientationForm. self activeCachedForms at: 2 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self westLineSegment: true. line displayOn: orientationForm. line _ self southLineSegment: true. line displayOn: orientationForm. line _ self northLineSegment: true. line displayOn: orientationForm. self activeCachedForms at: 3 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self southLineSegment: true. line displayOn: orientationForm. line _ self eastLineSegment: true. line displayOn: orientationForm. line _ self westLineSegment: true. line displayOn: orientationForm. self activeCachedForms at: 4 put: orientationForm! ! !NsTeeGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:34'! initializeIdleForms | orientationForm line | self idleCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self eastLineSegment: false. line displayOn: orientationForm. line _ self northLineSegment: false. line displayOn: orientationForm. line _ self southLineSegment: false. line displayOn: orientationForm. self idleCachedForms at: 1 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self northLineSegment: false. line displayOn: orientationForm. line _ self westLineSegment: false. line displayOn: orientationForm. line _ self eastLineSegment: false. line displayOn: orientationForm. self idleCachedForms at: 2 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self westLineSegment: false. line displayOn: orientationForm. line _ self southLineSegment: false. line displayOn: orientationForm. line _ self northLineSegment: false. line displayOn: orientationForm. self idleCachedForms at: 3 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self southLineSegment: false. line displayOn: orientationForm. line _ self eastLineSegment: false. line displayOn: orientationForm. line _ self westLineSegment: false. line displayOn: orientationForm. self idleCachedForms at: 4 put: orientationForm! ! !NsCornerGameTile methodsFor: 'neighbors' stamp: 'sbw 10/17/2003 15:11'! neighborDeltas | delta1 delta2 | delta1 _ 1 @ 0. delta2 _ 0 @ -1. self orientation = 2 ifTrue: [delta1 _ -1 @ 0. delta2 _ 0 @ -1]. self orientation = 3 ifTrue: [delta1 _ 0 @ 1. delta2 _ -1 @ 0]. self orientation = 4 ifTrue: [delta1 _ 0 @ 1. delta2 _ 1 @ 0]. ^ OrderedCollection with: delta1 with: delta2! ! !NsLineGameTile methodsFor: 'neighbors' stamp: 'sbw 10/17/2003 14:33'! neighborDeltas | delta1 delta2 | delta1 _ 1 @ 0. delta2 _ -1 @ 0. self orientation = 2 ifTrue: [delta1 _ 0 @ -1. delta2 _ 0 @ 1]. ^ OrderedCollection with: delta1 with: delta2! ! !NsTwoConnectionsGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:22'! maxConnections ^ 2! ! !NsCornerGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 11:46'! maxOrientations ^ 4! ! !NsCornerGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:41'! tileName ^ 'Corner'! ! !NsCornerGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:10'! hasForms ^ true! ! !NsCornerGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:36'! initializeActiveForms | orientationForm line | self activeCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self eastLineSegment: true. line displayOn: orientationForm. line _ self northLineSegment: true. line displayOn: orientationForm. self activeCachedForms at: 1 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self northLineSegment: true. line displayOn: orientationForm. line _ self westLineSegment: true. line displayOn: orientationForm. self activeCachedForms at: 2 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self westLineSegment: true. line displayOn: orientationForm. line _ self southLineSegment: true. line displayOn: orientationForm. self activeCachedForms at: 3 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self southLineSegment: true. line displayOn: orientationForm. line _ self eastLineSegment: true. line displayOn: orientationForm. self activeCachedForms at: 4 put: orientationForm! ! !NsCornerGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:35'! initializeIdleForms | orientationForm line | self idleCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self eastLineSegment: false. line displayOn: orientationForm. line _ self northLineSegment: false. line displayOn: orientationForm. self idleCachedForms at: 1 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self northLineSegment: false. line displayOn: orientationForm. line _ self westLineSegment: false. line displayOn: orientationForm. self idleCachedForms at: 2 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self westLineSegment: false. line displayOn: orientationForm. line _ self southLineSegment: false. line displayOn: orientationForm. self idleCachedForms at: 3 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self southLineSegment: false. line displayOn: orientationForm. line _ self eastLineSegment: false. line displayOn: orientationForm. self idleCachedForms at: 4 put: orientationForm! ! !NsLineGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 10:10'! hasForms ^ true! ! !NsLineGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:36'! initializeActiveForms | orientationForm line | self activeCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self fullHorizontalMiddleLine: true. line displayOn: orientationForm. self activeCachedForms at: 1 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self fullVerticalMiddleLine: true. line displayOn: orientationForm. self activeCachedForms at: 2 put: orientationForm! ! !NsLineGameTile class methodsFor: 'cached forms' stamp: 'sbw 10/16/2003 11:35'! initializeIdleForms | orientationForm line | self idleCachedForms: Dictionary new. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self fullHorizontalMiddleLine: false. line displayOn: orientationForm. self idleCachedForms at: 1 put: orientationForm. orientationForm _ Form extent: self extent depth: self formDepth. orientationForm fillColor: self backgroundColor. line _ self fullVerticalMiddleLine: false. line displayOn: orientationForm. self idleCachedForms at: 2 put: orientationForm! ! !NsLineGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 11:46'! maxOrientations ^ 2! ! !NsLineGameTile class methodsFor: 'constants' stamp: 'sbw 10/16/2003 10:41'! tileName ^ 'Line'! ! !SystemWindow methodsFor: '*nsTileGame-geometry' stamp: 'sbw 11/10/2003 21:15'! removeCollapseBox collapseBox ifNotNil: [collapseBox delete. collapseBox _ nil]! ! !SystemWindow methodsFor: '*nsTileGame-geometry' stamp: 'sbw 11/10/2003 21:14'! removeExpandBox expandBox ifNotNil: [expandBox delete. expandBox _ nil]! ! !TextStream methodsFor: '*nsTileGame' stamp: 'sbw 10/28/2003 14:02'! nextPutAll: aCollection "Optimized access to get around Text at:Put: overhead" | n | n _ aCollection size. position + n > writeLimit ifTrue: [ super nextPutAll: aCollection. self skip: 0 - aCollection size. ^self nextPutAll: aCollection]. (aCollection isMemberOf: String) ifFalse: [^super nextPutAll: aCollection]. collection string replaceFrom: position + 1 to: position + n with: aCollection startingAt: 1. position _ position + n! ! NsModel removeSelector: #click:forMorph:! NsModel removeSelector: #selectedCellClicked:forMorph:! NsGameTile class removeSelector: #editColors! NsGameTile class removeSelector: #editColors:! NsGameTile class removeSelector: #hideSelectedPartsOf:! NsGameTile class removeSelector: #showSelectedPartsOf:! !NsGameTile class reorganize! ('colors' activeLineColor activeLineColorString backgroundColor backgroundColorString borderColor borderColorString boxColor boxColorString colorTags editableColorKeys idleLineColor idleLineColorString initializeColors ledColor ledColorString updateColors) ('constants' borderWidth extent formDepth lineWidth maxConnections maxOrientations tileName) ('cached forms' activeCachedForms activeCachedForms: displayForms eastLineSegment: fullHorizontalMiddleLine: fullVerticalMiddleLine: hasForms idleCachedForms idleCachedForms: initializeActiveForms initializeForms initializeIdleForms northLineSegment: southLineSegment: westLineSegment:) ('accessing' colors colors:) ! !NsGame class reorganize! ('instructions' compressedEncodedInstructions convertSavedMorphFile: customizeSystemWindow: helpWindow instructions) ('as yet unclassified' helpFor: initializeHelp postLoadOperation rules rules:) ('parts bin' descriptionForPartsBin) ! NsGame removeSelector: #addButtonsToColumn:buttonHeight:vOffset:selector:top:! NsGame removeSelector: #addControl:to:! NsGame removeSelector: #addPanelsToColumn:panelHeight:! !HandMorph reorganize! ('accessing' colorForInsets lastEvent mouseOverHandler targetOffset userInitials userPicture userPicture:) ('balloon help' balloonHelp balloonHelp: deleteBalloonTarget: removePendingBalloonFor: spawnBalloonFor: triggerBalloonFor:after:) ('caching' releaseCachedState) ('change reporting' invalidRect:from:) ('classification' isHandMorph) ('copying' veryDeepCopyWith:) ('cursor' cursorBounds showTemporaryCursor: showTemporaryCursor:hotSpotOffset:) ('double click support' resetClickState waitForClicksOrDrag:event: waitForClicksOrDrag:event:selectors:threshold:) ('drawing' drawOn: fullDrawOn: hasChanged hasUserInformation needsToBeDrawn nonCachingFullDrawOn: restoreSavedPatchOn: savePatchFrom: shadowForm updateCacheCanvas:) ('drop shadows' shadowOffset) ('event handling' checkForMoreKeyboard cursorPoint flushEvents noticeMouseOver:event: pauseEventRecorderIn: processEvents) ('events-processing' handleEvent:) ('focus handling' keyboardFocus keyboardFocus: mouseFocus mouseFocus: newKeyboardFocus: newMouseFocus: newMouseFocus:event: releaseAllFoci releaseKeyboardFocus releaseKeyboardFocus: releaseMouseFocus releaseMouseFocus:) ('genie' allowsGestureStart:target: disableGenie disableGenieFocus: enableGenie ensureGenieGestureProcessor genieGestureProcessor gestureStart:target: giveGenieChanceToEscape handleEventWithGenieEscaped: isGenieEnabled isGenieRecognizing prepareMouseFocusChangeFrom:to: resetGenie switchGenieEnabled switchGenieFocus: temporaryCursor) ('geometry' position position: userInitials:andPicture:) ('grabbing/dropping' attachMorph: dropMorph:event: dropMorphs dropMorphs: grabMorph:from: targetOffset:) ('halo handling' halo: obtainHalo: releaseHalo: removeHaloFromClick:on: removePendingHaloFor: spawnMagicHaloFor: triggerHaloFor:after:) ('halos and balloon help' halo) ('initialization' initForEvents initialize interrupted resourceJustLoaded) ('layout' fullBounds) ('listeners' addEventListener: addKeyboardListener: addListener:to: addMouseListener: eventListeners eventListeners: keyboardListeners keyboardListeners: mouseListeners mouseListeners: removeEventListener: removeKeyboardListener: removeListener:from: removeMouseListener:) ('meta-actions' copyToPasteBuffer: grabMorph:) ('*nsTileGame-objects from disk' objectForDataStream:) ('paste buffer' objectToPaste pasteBuffer pasteBuffer: pasteMorph) ('pen' trailMorph) ('scripting' adaptedToWorld:) ('updating' changed) ('private events' generateDropFilesEvent: generateKeyboardEvent: generateMouseEvent: mouseTrailFrom: moveToEvent: sendEvent:focus: sendEvent:focus:clear: sendFocusEvent:to:clear: sendKeyboardEvent: sendListenEvent:to: sendMouseEvent:) ! "Postscript: Setup forms and other class variables." NsGame postLoadOperation. !