<?xml version="1.0"?>

<st-source>
<!-- 
Name: TowersOfHanoi
Notice: All rights reserved
BundleName: TowersOfHanoi
Comment: Hanoi

Part of Seaside Bonus Pack version SeasideBonusPack 2.7b1.1.0   8 August 2007, 15:14:13 pm

Classical Towers of Hanoi

Demonstrates how to snapshot the state of a complex object
to provide effective use of the Browser back button.

Also demonstrates CSS and Javascript

By Michel Bany [mbany@cincom.com]
DevelopmentPrerequisites: #(#(#any 'SeasideBase' ''))
Parcel: #('TowersOfHanoi')
ParcelName: TowersOfHanoi
PrerequisiteParcels: #(#('SeasideBase' ''))
Version: 2.7b1.1.0
Date: 2:52:38 pm August 8, 2007
 -->
<time-stamp>From VisualWorks®, 7.5 of April 16, 2007 on August 8, 2007 at 2:52:38 pm</time-stamp>


<do-it>(Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned.  Choose terminate or close.']</do-it>

<class>
<name>HanoiGameViewer</name>
<environment>Smalltalk</environment>
<super>Seaside.WAComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>game poles gameSize unit disk width </inst-vars>
<class-inst-vars></class-inst-vars>
<imports>
			Seaside.*
			</imports>
<category>Hanoi</category>
<attributes>
<package>Hanoi</package>
</attributes>
</class>

<class>
<name>HanoiDisk</name>
<environment>Smalltalk</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>diameter </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Hanoi</category>
<attributes>
<package>Hanoi</package>
</attributes>
</class>

<class>
<name>HanoiPole</name>
<environment>Smalltalk</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>disks </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Hanoi</category>
<attributes>
<package>Hanoi</package>
</attributes>
</class>

<class>
<name>MoveNotification</name>
<environment>Smalltalk</environment>
<super>Core.Notification</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Hanoi</category>
<attributes>
<package>Hanoi</package>
</attributes>
</class>

<class>
<name>Hanoi</name>
<environment>Smalltalk</environment>
<super>Seaside.WAComponent</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>game solver moves automaticStepping automaticSteppingRequested viewer </inst-vars>
<class-inst-vars></class-inst-vars>
<imports>
			Seaside.*
			</imports>
<category>Hanoi</category>
<attributes>
<package>Hanoi</package>
</attributes>
</class>

<class>
<name>HanoiSolver</name>
<environment>Smalltalk</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>size </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Hanoi</category>
<attributes>
<package>Hanoi</package>
</attributes>
</class>

<class>
<name>HanoiGameSolver</name>
<environment>Smalltalk</environment>
<super>HanoiSolver</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>game </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Hanoi</category>
<attributes>
<package>Hanoi</package>
</attributes>
</class>

<class>
<name>HanoiContinuationSolver</name>
<environment>Smalltalk</environment>
<super>HanoiGameSolver</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>continuation </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Hanoi</category>
<attributes>
<package>Hanoi</package>
</attributes>
</class>

<class>
<name>HanoiGameLibrary</name>
<environment>Smalltalk</environment>
<super>Seaside.WAFileLibrary</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports>
			Seaside.*
			</imports>
<category>Hanoi</category>
<attributes>
<package>Hanoi</package>
</attributes>
</class>

<class>
<name>HanoiMove</name>
<environment>Smalltalk</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>from to </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Hanoi</category>
<attributes>
<package>Hanoi</package>
</attributes>
</class>

<class>
<name>HanoiGame</name>
<environment>Smalltalk</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>poles </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Hanoi</category>
<attributes>
<package>Hanoi</package>
</attributes>
</class>

<methods>
<class-id>HanoiGameViewer</class-id> <category>accessing</category>

<body package="Hanoi" selector="game">game
	^game</body>

<body package="Hanoi" selector="game:">game: anObject
	game := anObject</body>

<body package="Hanoi" selector="poles">poles
	^poles ifNil: [poles := self game poles]</body>
</methods>

<methods>
<class-id>HanoiGameViewer</class-id> <category>rendering</category>

<body package="Hanoi" selector="renderContentOn:">renderContentOn: html 
	gameSize := self game size.
	unit := (100 / gameSize) truncated.
	html table: 
			[1 to: gameSize
				do: 
					[:height | 
					html tableRow: 
							[self game polesDo: 
									[:pole | 
									self 
										renderPole: pole
										atHeight: height
										on: html]]]]</body>

<body package="Hanoi" selector="renderPole:atHeight:on:">renderPole: pole atHeight: height on: html 
	^html tableData: 
			[(html div)
				class: #nodisk;
				style: 'width: ' , (height * unit) printString , '%;';
				with: 
						[pole size &gt; (gameSize - height) 
							ifTrue: 
								[disk := pole diskAt: height - (gameSize - pole size).
								width := disk diameter / height.
								(html div)
									class: #disk;
									style: 'width: ' , (width * 100) asInteger printString , '%';
									with: disk diameter]]]</body>
</methods>

<methods>
<class-id>HanoiGameViewer class</class-id> <category>instance creation</category>

<body package="Hanoi" selector="on:">on: aGame
	^self new game: aGame</body>
</methods>

<methods>
<class-id>HanoiDisk</class-id> <category>accessing</category>

<body package="Hanoi" selector="diameter">diameter
	^diameter</body>

<body package="Hanoi" selector="diameter:">diameter: anObject
	diameter := anObject</body>
</methods>

<methods>
<class-id>HanoiDisk</class-id> <category>printing</category>

<body package="Hanoi" selector="printOn:">printOn: aStream

	aStream nextPutAll: 'Diameter'; space.
	self diameter printOn: aStream.</body>
</methods>

<methods>
<class-id>HanoiDisk class</class-id> <category>instance creation</category>

<body package="Hanoi" selector="diameter:">diameter: aNumber

	^ self new diameter: aNumber</body>
</methods>

<methods>
<class-id>HanoiPole</class-id> <category>integrity rule</category>

<body package="Hanoi" selector="canAccept:">canAccept: aDisk

	^ self isEmpty or: [self top diameter &gt; aDisk diameter].</body>

<body package="Hanoi" selector="canRemove">canRemove

	^ self isEmpty not</body>

<body package="Hanoi" selector="hasEnoughCapacity">hasEnoughCapacity

	^ self size &lt; self capacity</body>
</methods>

<methods>
<class-id>HanoiPole</class-id> <category>queryng</category>

<body package="Hanoi" selector="capacity">capacity

	^ disks capacity</body>

<body package="Hanoi" selector="diskAt:">diskAt: anInteger

	^ disks at: anInteger</body>

<body package="Hanoi" selector="size">size

	^ disks size</body>
</methods>

<methods>
<class-id>HanoiPole</class-id> <category>error checking</category>

<body package="Hanoi" selector="checkCanAccept:">checkCanAccept: aDisk

	(self canAccept: aDisk) ifFalse: [self error: 'This disk is too big !'].</body>

<body package="Hanoi" selector="checkCanRemove">checkCanRemove

	self canRemove ifFalse: [self error: 'This pole is empty'].</body>

<body package="Hanoi" selector="checkHasEnoughCapacity">checkHasEnoughCapacity

	self hasEnoughCapacity ifFalse: [self error: 'This pole is full !'].</body>
</methods>

<methods>
<class-id>HanoiPole</class-id> <category>initialize-release</category>

<body package="Hanoi" selector="initializeWithSize:">initializeWithSize: anInteger

	disks := OrderedCollection new: anInteger.</body>

<body package="Hanoi" selector="placeDisks">placeDisks

	self capacity to: 1 by: -1 do:
		[ :x |
		self push: (HanoiDisk diameter: x)].</body>
</methods>

<methods>
<class-id>HanoiPole</class-id> <category>testing</category>

<body package="Hanoi" selector="isEmpty">isEmpty

	^ disks isEmpty</body>
</methods>

<methods>
<class-id>HanoiPole</class-id> <category>operating</category>

<body package="Hanoi" selector="pop">pop

	self checkCanRemove.
	^ disks removeFirst</body>

<body package="Hanoi" selector="push:">push: aDisk

	self checkHasEnoughCapacity.
	self checkCanAccept: aDisk.
	^ disks addFirst: aDisk</body>

<body package="Hanoi" selector="top">top

	self checkCanRemove.
	^ disks first</body>
</methods>

<methods>
<class-id>HanoiPole</class-id> <category>printing</category>

<body package="Hanoi" selector="printOn:">printOn: aStream
	disks printOn: aStream</body>
</methods>

<methods>
<class-id>HanoiPole</class-id> <category>backtracking</category>

<body package="Hanoi" selector="snapshotCopy">snapshotCopy
	| copy |
	copy := self class new snapshotDisks: disks copy.
	^copy</body>

<body package="Hanoi" selector="snapshotDisks">snapshotDisks
	^ disks</body>

<body package="Hanoi" selector="snapshotDisks:">snapshotDisks: aCollection
	disks := aCollection</body>
</methods>

<methods>
<class-id>HanoiPole class</class-id> <category>instance creation</category>

<body package="Hanoi" selector="ofSize:">ofSize: anInteger

	^ self new initializeWithSize: anInteger</body>
</methods>

<methods>
<class-id>Hanoi</class-id> <category>actions</category>

<body package="Hanoi" selector="anyMoveLog">anyMoveLog

	^ moves ~~ nil.</body>

<body package="Hanoi" selector="automaticByStep">automaticByStep

	self beAutomatic.	
	self resume.
	self solveByStep.</body>

<body package="Hanoi" selector="clearMoveLog">clearMoveLog

	moves := OrderedCollection new</body>

<body package="Hanoi" selector="logMove:">logMove: aMove

	moves add: aMove.</body>

<body package="Hanoi" selector="logMovesDuring:">logMovesDuring: aBlock

	| save |
	save := moves.
	aBlock on: Error do:
		[:ex |
		moves := save.
		solver := nil.
		self beManual.
		^ self inform: ex errorString]</body>

<body package="Hanoi" selector="moveDiskFrom:to:">moveDiskFrom: from to: to

	| move |
	[move := game moveFrom: from to: to.
	game executeMove: move.
	self logMove: move.
	solver := nil]
	on: Error do:
		[:ex |
		^ self inform: ex errorString]</body>

<body package="Hanoi" selector="moveLogDo:">moveLogDo: aBlock

	moves do: aBlock</body>

<body package="Hanoi" selector="noGame">noGame

	game := nil.
	viewer := nil.</body>

<body package="Hanoi" selector="pause">pause
	self automaticStepping: false</body>

<body package="Hanoi" selector="resume">resume
	self automaticStepping: true</body>

<body package="Hanoi" selector="solve">solve

	self logMovesDuring:
		[
			[game solve] on: MoveNotification
				do: [:n | 
					self logMove: n parameter.
					n resume]
		]</body>

<body package="Hanoi" selector="solveByStep">solveByStep

	self logMovesDuring:
		[
			[solver isNil ifTrue:
				[solver := HanoiContinuationSolver onGame: game.
				self clearMoveLog.
				self automaticStepping: self isAutomatic.
				solver solve.
				self beManual.
				solver := nil] 
			ifFalse:
				[solver continue].
			]
			on: MoveNotification
				do: [:n | | move |
					move := n parameter.
					game executeMove: move.
					self logMove: move]
		]</body>

<body package="Hanoi" selector="startNewGameOfSize:">startNewGameOfSize: size

	game := HanoiGame newSize: size.
	viewer := HanoiGameViewer on: game.
	self session registerObjectForBacktracking: game.
	self beManual.
	solver := nil.
	self clearMoveLog.
	self session registerObjectForBacktracking: moves.</body>
</methods>

<methods>
<class-id>Hanoi</class-id> <category>accessing</category>

<body package="Hanoi" selector="automaticStepping">automaticStepping
	automaticStepping isNil ifTrue:
		[self automaticStepping: false]. 
	^automaticStepping</body>

<body package="Hanoi" selector="automaticStepping:">automaticStepping: anObject
	automaticStepping := anObject</body>

<body package="Hanoi" selector="automaticSteppingRequested">automaticSteppingRequested
	^automaticSteppingRequested</body>

<body package="Hanoi" selector="automaticSteppingRequested:">automaticSteppingRequested: anObject
	automaticSteppingRequested := anObject</body>

<body package="Hanoi" selector="beAutomatic">beAutomatic
	^self automaticSteppingRequested: true</body>

<body package="Hanoi" selector="beManual">beManual
	^self automaticSteppingRequested: false</body>

<body package="Hanoi" selector="children">children
	^viewer isNil ifTrue: [#()] ifFalse: [Array with: viewer]</body>

<body package="Hanoi" selector="isAutomatic">isAutomatic
	^self automaticSteppingRequested</body>

<body package="Hanoi" selector="isManual">isManual
	^self isAutomatic not</body>
</methods>

<methods>
<class-id>Hanoi</class-id> <category>initialization</category>

<body package="Hanoi" selector="initialize">initialize

	self beManual.</body>
</methods>

<methods>
<class-id>Hanoi</class-id> <category>rendering</category>

<body package="Hanoi" selector="renderBasicControlsOn:">renderBasicControlsOn: html 
	(html submitButton)
		callback: [self noGame];
		text: 'New game'.
	(html submitButton)
		callback: [self solve];
		text: 'Solve'.
	(html submitButton)
		callback: [self solveByStep];
		text: 'Step'</body>

<body package="Hanoi" selector="renderContentOn:">renderContentOn: html

	html heading: 'Towers of Hanoï'.
	game isNil
		ifTrue:
			[self renderNoGameOn: html]
		ifFalse:
			[self renderGameOn: html].</body>

<body package="Hanoi" selector="renderControlsOn:">renderControlsOn: html 
	html form: 
			[(html div)
				id: #buttonControls;
				with: 
						[self renderBasicControlsOn: html.
						self renderSolverControlsOn: html].
			self renderManualControlsOn: html]</body>

<body package="Hanoi" selector="renderGameOn:">renderGameOn: html 
	html render: viewer.
	(html div)
		id: #controls;
		with: [self renderControlsOn: html].
	self renderMoveLogOn: html</body>

<body package="Hanoi" selector="renderManualControlsOn:">renderManualControlsOn: html 
	| from to |
	html fieldSet: 
			[html legend: 'Explicitely move a disk'.
			html div: 
					[html text: 'from pole number'.
					(html select)
						list: #(1 2 3);
						selected: nil;
						callback: [:x | from := x].
					html text: 'to pole number'.
					(html select)
						list: #(1 2 3);
						selected: nil;
						callback: [:x | to := x].
					(html submitButton)
						callback: [self moveDiskFrom: from to: to];
						text: 'Move'].
			html paragraph: 
					[html strong: 'Note: '.
					html text: 'Moves can be undone by hitting the back button']]</body>

<body package="Hanoi" selector="renderMoveLogOn:">renderMoveLogOn: html 
	self anyMoveLog 
		ifTrue: 
			[(html heading)
				level: 3;
				with: 'Moves'.
			self moveLogDo: [:each | html div: each]]</body>

<body package="Hanoi" selector="renderNoGameOn:">renderNoGameOn: html 
	| size |
	size := 5.
	html form: 
			[html span
				class: #inputField;
				with:
					[html text: 'How many disks ?'.
					(html textInput)
						size: 2;
						value: size;
					callback: [:x | size := x asNumber asInteger]].
			(html submitButton)
				callback: [self startNewGameOfSize: size];
				text: 'Start game']</body>

<body package="Hanoi" selector="renderSolverControlsOn:">renderSolverControlsOn: html 
	solver notNil 
		ifTrue: 
			[self automaticStepping 
				ifTrue: 
					[(html submitButton)
						callback: [self pause];
						text: 'Pause'.
					html script: 'setTimeout(''clickStep()'',1000);']
				ifFalse: 
					[self isAutomatic 
						ifTrue: 
							[(html submitButton)
								callback: [self resume];
								text: 'Resume']
						ifFalse: 
							[(html submitButton)
								callback: [self automaticByStep];
								text: 'Continue auto']]]
		ifFalse: 
			[(html submitButton)
				callback: [self automaticByStep];
				text: 'Auto']</body>
</methods>

<methods>
<class-id>Hanoi class</class-id> <category>initialize-release</category>

<body package="Hanoi" selector="canBeRoot">canBeRoot

	^ true</body>

<body package="Hanoi" selector="description">description
	^'Towers of Hanoi (backtracking demo)'</body>

<body package="Hanoi" selector="initialize">initialize

	(self registerAsApplication: 'games/towersofhanoi')
		addLibrary: HanoiGameLibrary</body>
</methods>

<methods>
<class-id>HanoiSolver</class-id> <category>solving</category>

<body package="Hanoi" selector="moveDiskFrom:to:">moveDiskFrom: from to: to

	self notifyMoveDiskFrom: from to: to</body>

<body package="Hanoi" selector="moveFrom:to:">moveFrom: from to: to

	^ HanoiMove from: from to: to.</body>

<body package="Hanoi" selector="movePileOfSize:from:to:work:">movePileOfSize: n from: from to: to work: work

	n &gt; 1 ifTrue: [self movePileOfSize: n - 1 from: from to: work work: to].
	self moveDiskFrom: from to: to.
	n &gt; 1 ifTrue: [self movePileOfSize: n - 1 from: work to: to work: from].</body>

<body package="Hanoi" selector="notifyMoveDiskFrom:to:">notifyMoveDiskFrom: from to: to

	MoveNotification signalWith: (self moveFrom: from to: to).</body>

<body package="Hanoi" selector="solve">solve

	self movePileOfSize: self size from: 1 to: 3 work: 2.</body>
</methods>

<methods>
<class-id>HanoiSolver</class-id> <category>accessing</category>

<body package="Hanoi" selector="size">size
	^size</body>

<body package="Hanoi" selector="size:">size: anObject
	size := anObject</body>
</methods>

<methods>
<class-id>HanoiSolver class</class-id> <category>testing</category>

<body package="Hanoi" selector="test1">test1
	| solver |
	solver := HanoiSolver new size: 6.
	Transcript clear.
	[solver solve]
		on: MoveNotification
		do: [:notification | 
			Transcript cr; print: notification parameter.
			notification resume].
	Transcript flush.</body>

<body package="Hanoi" selector="test2">test2
	| game solver |
	game := HanoiGame newSize: 6.
	solver := HanoiSolver new size: game size.
	[solver solve]
		on: MoveNotification
		do: [:notification | | move |
			move := notification parameter.
			game executeMove: move.
			notification resume].</body>
</methods>

<methods>
<class-id>HanoiGameSolver</class-id> <category>initialize-release</category>

<body package="Hanoi" selector="initializeWithGame:">initializeWithGame: aGame

	game := aGame.</body>
</methods>

<methods>
<class-id>HanoiGameSolver</class-id> <category>solving</category>

<body package="Hanoi" selector="moveDiskFrom:to:">moveDiskFrom: from to: to

	game executeMove: (self moveFrom: from to: to).
	super moveDiskFrom: from to: to</body>

<body package="Hanoi" selector="solve">solve

	| startPile otherPiles |
	game howManyDisks withIndexDo:
		[:count :x |
		count = game size ifTrue: [startPile := x]].
	startPile isNil ifTrue: [self error: 'I do not know how to finish an already started problem !'].
	otherPiles := (OrderedCollection with: 1 with: 2 with: 3) remove: startPile; yourself.
	self movePileOfSize: self size from: startPile to: otherPiles last work: otherPiles first.</body>
</methods>

<methods>
<class-id>HanoiGameSolver</class-id> <category>accessing</category>

<body package="Hanoi" selector="size">size
	^game size</body>
</methods>

<methods>
<class-id>HanoiGameSolver class</class-id> <category>instance creation</category>

<body package="Hanoi" selector="onGame:">onGame: aGame

	^ self new initializeWithGame: aGame</body>
</methods>

<methods>
<class-id>HanoiGameSolver class</class-id> <category>testing</category>

<body package="Hanoi" selector="test1">test1
	| game solver |
	game := HanoiGame newSize: 6.
	solver := HanoiGameSolver onGame: game.
	solver solve.
	^game</body>

<body package="Hanoi" selector="test2">test2
	| game solver |
	game := HanoiGame newSize: 6.
	solver := game solver.
	solver solve.
	^ game</body>

<body package="Hanoi" selector="test3">test3
	(HanoiGame newSize: 6) solve</body>

<body package="Hanoi" selector="test4">test4
	(HanoiGame newSize: 6)
		solve;
		solve</body>

<body package="Hanoi" selector="test5">test5
	(HanoiGame newSize: 6)
		solve;
		reset;
		solve</body>
</methods>

<methods>
<class-id>HanoiContinuationSolver</class-id> <category>solving</category>

<body package="Hanoi" selector="continue">continue

	continuation value.</body>

<body package="Hanoi" selector="moveDiskFrom:to:">moveDiskFrom: from to: to

	self notifyMoveDiskFrom: from to: to</body>

<body package="Hanoi" selector="movePileOfSize:from:to:work:">movePileOfSize: n from: from to: to work: work

	| saveContinuation |
	saveContinuation := continuation.
	n &gt; 1 ifTrue: [self movePileOfSize: n - 1 from: from to: work work: to].
	Seaside.Continuation currentDo:
		[:cc |
		continuation := cc.
		self moveDiskFrom: from to: to].
	n &gt; 1 ifTrue: [self movePileOfSize: n - 1 from: work to: to work: from].
	continuation := saveContinuation.</body>
</methods>

<methods>
<class-id>HanoiGameLibrary</class-id> <category>accessing</category>

<body package="Hanoi" selector="selectorsToInclude">selectorsToInclude
	^#( hanoiCss hanoiJs )</body>
</methods>

<methods>
<class-id>HanoiGameLibrary</class-id> <category>javascripts</category>

<body package="Hanoi" selector="hanoiJs">hanoiJs

	^'
// Locate any button with text "Step" and click it
// Note. Enumerator class is not available with Mozilla and Firefox

	var nav;
	if (navigator.userAgent.indexOf("Safari") &gt; 0)
			nav = "Safari";
	else if (navigator.product == "Gecko")
			nav = "Gecko";
	else
			nav = "IE";

function clickStep ()
	{
	if (nav == "Gecko")
		return clickStepForGecko ()
	else
		return clickStepForMostBrowsers ();
	}

function clickStepForMostBrowsers ()
	{
	var formEnum = new Enumerator (document.forms);
	for (;!formEnum.atEnd();formEnum.moveNext())
		{
		var aForm = formEnum.item();
		var elemEnum = new Enumerator(aForm.elements);
		for (;!elemEnum.atEnd();elemEnum.moveNext())
			{
			var anElement = elemEnum.item();
			if (anElement.value == "Step")
				{
				anElement.click();
				return false;
				};
			}
		}
	return true;
	}

function clickStepForGecko ()
	{
	var forms = document.forms;
	for (i=0;i&lt;forms.length;i++)
		{
		var aForm = forms[i];
		var elems = aForm.elements;
		for (j=0;j&lt;elems.length;j++)
			{
			var anElement = elems[j];
			if (anElement.value == "Step")
				{
				anElement.click();
				return false;
				};
			}
		}
	return true;
	}
'</body>
</methods>

<methods>
<class-id>HanoiGameLibrary</class-id> <category>stylesheets</category>

<body package="Hanoi" selector="hanoiCss">hanoiCss
	^ '
body  {
	font-family: Verdana,Arial,Helvetica,Sans-serif;
	font-size: 80%;
}
.disk {
	height: 15px;
	background-color: green;
	margin-left: auto;
	margin-right: auto;
	border: none;
	color: white;
	font-weight: bold;
	text-align: center;
 }
.nodisk {
	height: 15px;
	background-color: white;
	margin-left: auto;
	margin-right: auto;
	border: 1px gray dotted;
	text-align: center;
 }
tr, table {
	width: 100%;
	border: none;
}
td {
	width: 30%;
	text-align: center;
}
form input.submit {
	padding: 2px;
	border: 2px solid #69c;
	border-color: #69c #369 #369 #69c;
	background: #ccc;
	color: #000;
	font: bold 80% Verdana,Arial,Sans-serif;
	cursor: pointer;
}
form input.submit:hover {
	color: #c00;
	background: #eee;
	cursor: pointer;
}
form input.submit:active {
	border-color: #369 #69c #69c #369;
	background: #ccc;
	color: #000;
}
#buttonControls input.submit {
	margin: 1em 1em 1em 0;
}
.inputField {
	display: block;
	margin-bottom: 2em;
} 
.inputField input.text {
	margin-left: 2em;
} 
fieldset {
	margin: 1em 0 1em 0;
	padding: 1em;
}
legend {
	font-weight: bold;
}
fieldset select  {
	margin: 0 1em 0 1em;
}	
'</body>
</methods>

<methods>
<class-id>HanoiMove</class-id> <category>accessing</category>

<body package="Hanoi" selector="from">from
	^from</body>

<body package="Hanoi" selector="from:">from: anObject
	from := anObject</body>

<body package="Hanoi" selector="to">to
	^to</body>

<body package="Hanoi" selector="to:">to: anObject
	to := anObject</body>
</methods>

<methods>
<class-id>HanoiMove</class-id> <category>printing</category>

<body package="Hanoi" selector="printOn:">printOn: aStream

	aStream nextPutAll: 'Move from'; space.
	self from printOn: aStream.
	aStream space; nextPutAll: 'to'; space.
	self to printOn: aStream.</body>
</methods>

<methods>
<class-id>HanoiMove class</class-id> <category>instance creation</category>

<body package="Hanoi" selector="from:to:">from: from to: to

	^ self new from: from; to: to</body>
</methods>

<methods>
<class-id>HanoiGame</class-id> <category>moving</category>

<body package="Hanoi" selector="executeMove:">executeMove: aMove

	self moveDiskFrom: aMove from to: aMove to.</body>

<body package="Hanoi" selector="moveFrom:to:">moveFrom: from to: to

	"Answers a HanoiMove instance"
	^ HanoiMove from: from to: to.</body>
</methods>

<methods>
<class-id>HanoiGame</class-id> <category>querying</category>

<body package="Hanoi" selector="howManyDisks">howManyDisks

	^ poles collect: [:each | each size].</body>

<body package="Hanoi" selector="size">size

	^ poles inject: 0 into: [:sum :eachPole | sum + eachPole size ].</body>
</methods>

<methods>
<class-id>HanoiGame</class-id> <category>initialize-release</category>

<body package="Hanoi" selector="initializeWithSize:">initializeWithSize: anInteger

	poles := Array new: 3.
	self newGame: anInteger.</body>

<body package="Hanoi" selector="newGame:">newGame: anInteger

	1 to: poles size do: [ :x | poles at: x put: (HanoiPole ofSize: anInteger)].
	(poles at: 1) placeDisks.</body>

<body package="Hanoi" selector="reset">reset

	self newGame: self size.</body>
</methods>

<methods>
<class-id>HanoiGame</class-id> <category>backtracking</category>

<body package="Hanoi" selector="isIdenticalToSnapshot:">isIdenticalToSnapshot: anObject
	^ super isIdenticalToSnapshot: anObject</body>

<body package="Hanoi" selector="restoreFromSnapshot:">restoreFromSnapshot: anObject
	poles := anObject snapshotPoles collect: [:eachPole | eachPole snapshotCopy].</body>

<body package="Hanoi" selector="snapshotCopy">snapshotCopy
	| copy |
	copy := self class new 
		snapshotPoles: (poles collect: [:eachPole | eachPole snapshotCopy]);
		yourself.
	^ copy</body>

<body package="Hanoi" selector="snapshotPoles">snapshotPoles
	^ poles</body>

<body package="Hanoi" selector="snapshotPoles:">snapshotPoles: aCollection
	poles := aCollection.</body>
</methods>

<methods>
<class-id>HanoiGame</class-id> <category>private - moving</category>

<body package="Hanoi" selector="moveDiskFrom:to:">moveDiskFrom: from to: to

	| disk |
	(from between: 1 and: poles size) ifFalse: [self error: 'From pole is wrong !'].
	(to between: 1 and: poles size) ifFalse: [self error: 'To pole is wrong !'].
	from = to ifTrue: [self error: 'From pole and to pole are the same pole !'].
	disk := (poles at: from) pop.
	[(poles at: to) push: disk] on: Error do: [:ex | (poles at: from) push: disk. ex pass].</body>
</methods>

<methods>
<class-id>HanoiGame</class-id> <category>printing</category>

<body package="Hanoi" selector="printOn:">printOn: aStream
	poles printOn: aStream</body>
</methods>

<methods>
<class-id>HanoiGame</class-id> <category>solving</category>

<body package="Hanoi" selector="solve">solve

	self solver solve.</body>

<body package="Hanoi" selector="solver">solver

	^ HanoiGameSolver onGame: self</body>
</methods>

<methods>
<class-id>HanoiGame</class-id> <category>enumerating</category>

<body package="Hanoi" selector="polesDo:">polesDo: aBlock
	poles do: aBlock</body>
</methods>

<methods>
<class-id>HanoiGame class</class-id> <category>instance creation</category>

<body package="Hanoi" selector="newSize:">newSize: anInteger

	anInteger = 0 ifTrue: [self error: 'A game with do disk does not make sense !'].
	^ self new initializeWithSize: anInteger</body>
</methods>

<methods>
<class-id>HanoiGame class</class-id> <category>tests</category>

<body package="Hanoi" selector="test1">test1
	| game |
	game := HanoiGame newSize: 2.
	game moveDiskFrom: 1 to: 2.
	game moveDiskFrom: 1 to: 3.
	game moveDiskFrom: 2 to: 3.
	game moveDiskFrom: 1 to: 2. "Pile 1 is empty"</body>

<body package="Hanoi" selector="test2">test2
	| game |
	game := HanoiGame newSize: 2.
	game moveDiskFrom: 1 to: 2.
	game moveDiskFrom: 1 to: 2. "Disk is too big"</body>

<body package="Hanoi" selector="test3">test3
	| game |
	game := HanoiGame newSize: 2.
	game moveDiskFrom: 1 to: 4. "Wrong pole number"</body>

<body package="Hanoi" selector="test4">test4
	| game |
	game := HanoiGame newSize: 2.
	game moveDiskFrom: 4 to: 2. "Wrong pole number"</body>

<body package="Hanoi" selector="test5">test5
	| game |
	game := HanoiGame newSize: 2.
	game moveDiskFrom: 2 to: 1. "Pile is empty"</body>

<body package="Hanoi" selector="test6">test6
	| game |
	game := HanoiGame newSize: 0.
	game moveDiskFrom: 1 to: 2. "No disk"</body>

<body package="Hanoi" selector="test7">test7
	| game |
	game := HanoiGame newSize: 2.
	game moveDiskFrom: 1 to: 2.
	game moveDiskFrom: 1 to: 3.
	game moveDiskFrom: 2 to: 3.
	game reset.
	game moveDiskFrom: 1 to: 2.
	game moveDiskFrom: 1 to: 3.
	game moveDiskFrom: 2 to: 3.
	game moveDiskFrom: 1 to: 2. "Pile is empty"</body>
</methods>

<initialize>
<class-id>Hanoi</class-id>
</initialize>

<do-it>"Imported Classes:"</do-it>

<do-it>self error: 'Attempting to file-in parcel imports.  Choose terminate or close'</do-it>

<class>
<name>Object</name>
<environment>Core</environment>
<super></super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Kernel-Objects</category>
<attributes>
<package>Kernel-Objects</package>
</attributes>
</class>

<class>
<name>WAFileLibrary</name>
<environment>Seaside</environment>
<super>Seaside.WALibrary</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars>default </class-inst-vars>
<imports></imports>
<category>Seaside-Libraries</category>
<attributes>
<package>Seaside-Libraries</package>
</attributes>
</class>

<class>
<name>Notification</name>
<environment>Core</environment>
<super>Core.Exception</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Kernel-Exception Handling</category>
<attributes>
<package>Kernel-Exception Handling</package>
</attributes>
</class>

<class>
<name>WAComponent</name>
<environment>Seaside</environment>
<super>Seaside.WAPresenter</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>decoration </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Seaside-Component</category>
<attributes>
<package>Seaside-Component</package>
</attributes>
</class>

</st-source>
