Platforms to show: All Mac Windows Linux Cross-Platform
/Mac64bit/SceneKit/SceneKit Hanoi
Required plugins for this example: MBS Mac64bit Plugin, MBS MacBase Plugin, MBS MacCG Plugin, MBS Main Plugin
You find this example project in your Plugins Download as a Xojo project file within the examples folder: /Mac64bit/SceneKit/SceneKit Hanoi
This example is the version from Mon, 3rd Feb 2019.
Project "SceneKit Hanoi.xojo_binary_project"
Class App Inherits Application
Const kEditClear = "&Delete"
Const kFileQuit = "&Quit"
Const kFileQuitShortcut = ""
EventHandler Sub Open()
#if Target64Bit and TargetMacOS then
// okay
#else
MsgBox "Please switch project to 64-bit and run on MacOS."
#endif
End EventHandler
End Class
Class MainWindow Inherits Window
Control MyControl Inherits SCNControlMBS
ControlInstance MyControl Inherits SCNControlMBS
EventHandler Sub Open()
MyView = me.View
MyScene = new SCNSceneMBS
MyView.scene = MyScene
MyView.backgroundColor = NSColorMBS.blackColor
MyView.autoenablesDefaultLighting = true
Myview.allowsCameraControl = true
rootNode = MyScene.rootNode
createBoard
createPegs
createDisks
Solve
// set in in play mode, so animations don't stop
MyView.play
End EventHandler
End Control
Sub Solve()
solver = new HanoiSolver(numberOfDisks)
// make some variables accessible in solver
solver.pegsNodes = pegs
solver.disks = disks
solver.pegHeight = pegHeight
solver.boardHeight = boardHeight
solver.diskHeight = diskHeight
solver.computeMoves
solver.recursiveAnimation(0)
End Sub
Sub createBoard()
boardWidth = diskRadius * 6.0 + boardPadding
boardLength = diskRadius * 2.0 + boardPadding
dim boardColor as NSColorMBS = NSColorMBS.brownColor()
dim boardGeometry as new SCNBoxMBS( boardWidth, boardHeight, boardLength, 0.1)
boardGeometry.firstMaterial.diffuse.contents = NSColorMBS.brownColor()
dim boardNode as new SCNNodeMBS(boardGeometry)
rootNode.addChildNode(boardNode)
End Sub
Sub createDisks()
dim firstPeg as SCNNodeMBS = pegs(0)
dim y as double = (boardHeight / 2.0 + diskHeight / 2.0)
dim radius as double = diskRadius
for i as integer = 0 to numberOfDisks-1
dim tube as new SCNTubeMBS(pegRadius, radius, diskHeight)
dim hue as double = (i) / (numberOfDisks)
dim color as NSColorMBS = NSColorMBS.colorWithHSV(hue, 1.0, 1.0, 1.0)
tube.firstMaterial.diffuse.contents = color
dim tubeNode as new SCNNodeMBS(tube)
tubeNode.position = SCNVector3MBS.Vector( firstPeg.position.x, y, 0)
rootNode.addChildNode(tubeNode)
disks.append(tubeNode)
y = y + (diskHeight)
radius = radius - 0.1
next
End Sub
Sub createPegs()
// Create the 3 Pegs on the board
pegHeight = (numberOfDisks + 1) * diskHeight
dim x as double = (-boardWidth / 2.0 + boardPadding / 2.0 + diskRadius)
for i as integer = 0 to 2
dim cylinder as new SCNCylinderMBS(pegRadius, pegHeight)
dim cylinderNode as new SCNNodeMBS(cylinder)
cylinder.firstMaterial.diffuse.contents = NSColorMBS.brownColor()
cylinderNode.position = new SCNVector3MBS(x, (pegHeight / 2.0 + boardHeight / 2.0), 0.0)
rootNode.addChildNode(cylinderNode)
pegs.append(cylinderNode)
x = x + (diskRadius * 2)
next
End Sub
Note "Note"
Based on code found in the tutorial
Introduction To SceneKit – Part 3
https://www.weheartswift.com/introduction-scenekit-part-3/
Property MyScene As SCNSceneMBS
Property MyView As SCNViewMBS
Property boardHeight As Double = 0.2
Property boardLength As double
Property boardPadding As Double = 0.8
Property boardWidth As Double
Property diskHeight As Double = 0.2
Property diskRadius As double = 1.0
Property disks() As SCNNodeMBS
Property numberOfDisks As integer = 5
Property pegHeight As Double = 0.0
Property pegRadius As Double = 0.1
Property pegs() As SCNNodeMBS
Property rootNode As SCNNodeMBS
Property solver As HanoiSolver
End Class
MenuBar MainMenuBar
MenuItem FileMenu = "&File"
MenuItem FileQuit = "#App.kFileQuit"
MenuItem EditMenu = "&Edit"
MenuItem EditUndo = "&Undo"
MenuItem EditSeparator1 = "-"
MenuItem EditCut = "Cu&t"
MenuItem EditCopy = "&Copy"
MenuItem EditPaste = "&Paste"
MenuItem EditClear = "#App.kEditClear"
MenuItem EditSeparator2 = "-"
MenuItem EditSelectAll = "Select &All"
End MenuBar
Class HanoiMove
Sub Constructor(diskIndex as integer, destinationPegIndex as integer, destinationDiskCount as integer)
self.diskIndex = diskIndex
self.destinationDiskCount = destinationDiskCount
self.destinationPegIndex = destinationPegIndex
End Sub
Property destinationDiskCount As Integer
Property destinationPegIndex As Integer
Property diskIndex As Integer
End Class
Class HanoiSolver
Sub Constructor(numberOfDisks as integer)
self.numberOfDisks = numberOfDisks
for i as integer = 0 to numberOfDisks-1
self.leftPeg.append(i)
next
pegs.Append leftPeg
pegs.Append middlePeg
pegs.Append rightPeg
End Sub
Function animationFromMove(move as HanoiMove) As SCNActionMBS
dim duration as double = 0.3
dim node as SCNNodeMBS = disks(move.diskIndex)
dim destination as SCNNodeMBS = pegsNodes(move.destinationPegIndex)
// Move To Top
dim topPosition as SCNVector3MBS = node.position
topPosition.y = (pegHeight + diskHeight * 4.0)
duration = normalizedDuration(node.position, topPosition)
dim moveUp as SCNActionMBS = SCNActionMBS.moveTo(topPosition, duration)
// Move Sideways
dim sidePosition as SCNVector3MBS = destination.position
sidePosition.y = topPosition.y
duration = normalizedDuration(topPosition, sidePosition)
dim moveSide as SCNActionMBS = SCNActionMBS.moveTo(sidePosition, duration)
// Move To Bottom
dim bottomPosition as SCNVector3MBS = sidePosition
bottomPosition.y = (boardHeight / 2.0 + diskHeight / 2.0) + (move.destinationDiskCount) * (diskHeight)
duration = normalizedDuration(sidePosition, bottomPosition)
dim moveDown as SCNActionMBS = SCNActionMBS.moveTo(bottomPosition, duration)
dim sequence as SCNActionMBS = SCNActionMBS.sequence(array(moveUp, moveSide, moveDown))
return sequence
End Function
Sub computeMoves()
redim moves(-1)
hanoi(numberOfDisks, 0, 1, 2)
End Sub
Shared Function distanceBetweenVectors(v1 as SCNVector3MBS, v2 as SCNVector3MBS) As Double
return lengthOfVector(SCNVector3MBS.Vector( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z))
End Function
Sub hanoi(numberOfDisks as integer, from_ as integer, using_ as integer, to_ as integer)
if numberOfDisks = 1 then
move(from_, to_)
else
hanoi(numberOfDisks - 1, from_, to_, using_)
move(from_, to_)
hanoi(numberOfDisks - 1, using_, from_, to_)
end if
End Sub
Shared Function lengthOfVector(v as SCNVector3MBS) As double
return sqrt(pow(v.x,2.0) + pow(v.y,2.0) + pow(v.z,2.0))
End Function
Sub move(from_ as integer, to_ as integer)
dim disk as integer = popDisk(from_)
dim diskIndex as integer = disk
dim peg() as integer = pegs(to_)
dim destinationDiskCount as integer = peg.Ubound+1
pushDisk(disk, to_)
dim move as new HanoiMove(diskIndex, to_, destinationDiskCount)
moves.append(move)
End Sub
Function normalizedDuration(startPosition as SCNVector3MBS, endPosition as SCNVector3MBS) As Double
dim referenceLength as double = distanceBetweenVectors(pegsNodes(0).position, pegsNodes(2).position)
dim length as double = distanceBetweenVectors(startPosition, endPosition)
return 1 * (length / referenceLength)
End Function
Function popDisk(peg as integer) As integer
dim p() as integer = pegs(peg)
dim u as integer = p.Ubound
dim n as integer = p(u)
p.Remove u
return n
End Function
Sub pushDisk(disk as integer, peg as integer)
dim n() as integer = pegs(peg)
n.Append disk
End Sub
Sub recursiveAnimation(index as integer)
dim move as HanoiMove = moves(index)
dim node as SCNNodeMBS = disks(move.diskIndex)
dim animation as SCNActionMBS = animationFromMove(move)
dim tag as Variant = index
node.runAction(animation, WeakAddressOf runActionCompleted, tag)
End Sub
Sub runActionCompleted(node as SCNNodeMBS, action as SCNActionMBS, key as string, tag as variant)
dim index as integer = tag
if index < moves.Ubound then
self.recursiveAnimation(index + 1)
end if
End Sub
Property boardHeight As double
Property diskHeight As Double
Property disks() As SCNNodeMBS
Property leftPeg() As Integer
Property middlePeg() As Integer
Property moves() As HanoiMove
Property numberOfDisks As Integer
Property pegHeight As Double
Property pegs() As Variant
Property pegsNodes() As SCNNodeMBS
Property rightPeg() As Integer
End Class
End Project
See also:
The items on this page are in the following plugins: MBS Mac64bit Plugin.