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.


The biggest plugin in space...