Tower of Hanoi Link 1 Tower of Hanoi Link 1 Tower of Hanoi Link 2 Tower of Hanoi Link 2.
Tutorial - The Tower of Hanoi - App Inventor for...
-
Upload
doannguyet -
Category
Documents
-
view
226 -
download
2
Transcript of Tutorial - The Tower of Hanoi - App Inventor for...
THE TOWN OF HANOI TUTORIAL
Author: Khoi Nguyen Tran Minh / Tony Nguyen
[email protected] / [email protected]
Link to source code (.aia) and the images.
ACKNOWLEDGMENTS
I would like to thank Karen Lang, David Wolber and Josh Sheldon for their encouragement, feedback and
support. My special thank go to Karen Lang for her time correcting the English grammar for the tutorial.
OVERVIEW
This tutorial is for advanced learners who want to explore the power of MIT App Inventor to create a complex
and complicated Android game app, the Town Of Hanoi.
The Town Of Hanoi, also the Tower of Brahma or Lucas' Tower, is considered a classical strategy game to
demonstrate how algorithms work for computer science students as well as the general public. It is explained
below:
• There are 3 poles.
• Bars are put onto the first pole in their size order, which means that the widest bar should be on the
bottom of the pole. Here is an example:
BEFORE
• The number of bars on the pole can be chosen by the players.
• Players have to move all of the bars from the first pole on the left to the third pole in the right using
the second bar in the middle, with the following rules:
o Only one bar can be moved at one time.
o You cannot place a wider bar on top of a smaller bar.
AFTER
LEARNING OBJECTIVES
After completing this tutorial, learners will achieve the following skills and knowledge:
• Computational thinking skills: Decomposition, Pattern Recognition, Abstraction and Evaluating
Solutions
• Application of computational thinking skills to solve problems
• Ability to use Button, Canvas, HorizontalArrangement, VerticalArrangement Image, ImageSprite, Label,
Notifier components
• Use of virtual screens
• Understanding of local and global variables
• Use of procedures with and without parameters
STEP-BY-STEP INSTRUCTIONS
Part I: set up the Graphical User Interface
1. Screen1: change ScreenOrientation to Landscape and Title to Tower of Hanoi
2. Drag and drop a Canvas component onto Screen1, change its name to gameScreen, which means the
first virtual screen, and set its Height and Width to Fill Parent.
3. Upload pole.png from the images folder into App Inventor.
This tutorial assumes you are very competent with App Inventor and have created several apps. If you are
not familiar with some of the terminology in the learning objectives section above, please do NOT attempt
to do this tutorial because it may do more harm than good. You may consider these basic tutorials
We are going to use several virtual screens, which are layout components that act like App Inventor Screens,
but are more flexible and easier to control than their counterparts.
All images can be downloaded from here
4. Drag and drop three ImageSprite components into the gameScreen Canvas component, and change
their details as follows:
• Pole1: height = 155, width = 25, x = 75, y = 40, picture = pole.png
• Pole2: height = 155, width = 25, x = 250, y = 40, picture = pole.png
• Pole3: height = 155, width = 25, x = 410, y = 40, picture = pole.png
5. Upload bar1.png, bar2.png, bar3.png, bar4.png, bar5.png from the images folder into App Inventor
6. Drag and drop five ImageSprite components into the gameScreen Canvas component, and change their
details as follows:
• bar1: height = 80, width = 80, x = 50, y = 70, picture = bar1.png
• bar2: height = 80, width = 100, x = 40, y = 95, picture = bar2.png
• bar3: height = 80, width = 120, x = 30, y = 120, picture = bar3.png
• bar4: height = 80, width = 140, x = 20, y = 145, picture = bar4.png
• bar5: height = 80, width = 160, x = 10, y = 170, picture = bar5.png
7. Upload touchIcon.png, and questionIcon.png from the images folder into App Inventor
8. Drag and drop four ImageSprite components into the gameScreen Canvas component, and change
their details as follows:
• touchIcon: height = 38, width = 28, x = 75, y = 200, picture = touchIcon.png, visible = true
• questionIcon1: height = 38, width = 75, x = 40, y = 200, picture = questionIcon.png, visible = false
• questionIcon2: height = 38, width = 28, x = 250, y = 200, picture = questionIcon.png, visible = false
• questionIcon3: height = 38, width = 28, x = 410, y = 200, picture = questionIcon.png, visible = false
9. Drag and drop three ImageSprite components into the gameScreen Canvas component, and change
details as follows:
• poleTouch1: height = 200, width = 125, x = 25, y = 40
• poleTouch2: height = 200, width = 125, x = 200, y = 40
• poleTouch3: height = 200, width = 125, x = 360, y = 40
10. Drag and drop one HorizontalArrangement component into the Screen1, and change its name, size,
background color as follows:
• messageResetAndExitHorizontalArrangement: height = 10 percent, width = Fill parent,
background color = pink, alignVertical = center
11. Drag and drop four Label components, and three HorizontalArrangement components into the
messageResetAndExit component, in the following order and change their name, size, background
color as follows:
• space1HorizontalArrangement: width = 6, BackgroundColor = none
• yourMovesLabel: text = “Your Moves:”, FontBold = true
• playerMovesLabel: text = “0“, FontBold = true, BackgroundColor = Orrange
• space2HorizontalArrangement: width = 6, BackgroundColor = none
• minimumMovesLabel; text = “Minimum Moves: “, FontBold = true
• minimumMoves: text = “31“, FontBold = true, BackgroundColor = Orrange
Part II: Coding
1. When the app starts, the 5 bars, the 3 poles, and the 3 question icons are put into 3 lists respectively as
follows:
2. addBarsIntoListofBarsInPole1 procedure adds all bars into listofBarsInPole1 list
3. A global variable name “isGameStarted” is initialized to find out whether the game has started:
4. The game starts when poleTouch1 is touched, and the isGameStarted is set to true:
5. Considering the Computational Thinking concepts of decomposition and abstraction, the code below
implements a very high level of abstraction by separating complicated tasks into several small tasks
when a poleTouch is touched:
• Get the touched pole
• Get a list of bars in the touched pole to find the top bar in the touched pole
• If there is NO moved-out bar, move the top bar in the touched pole out the pole
• If there is moved-out bar, move the moved-out bar to the touched pole
This approach makes changing and maintaining code an easier task. When there are changes, the
procedure blocks are changed and will reflect in all three poles, which means that we do not need to
change code in each event handler.
6. Because we need to access touchedPole and listOfBarsInTouchedPole many times during game play,
they have been made as global variables:
It is noticeable that poleTouch1, poleTouch2, and poleTouch3 have the same code blocks inside event
handler, with an exception of a code block checking if the game has started in poleTouch1.
7. In the moveTopBarOutTheTouchedPole procedure, there are a few tasks:
• Count the number of bars in the touched Pole
• When there is a bar in the touched Pole, (number of bar is not 0)
o Get the top bar in the touched Pole
o Move the top bar into new position, with Y as its current one, X as 10 (outside the Pole)
o Remove the top bar from the touched Pole
o Create a global movedOutBar variable and set it to topBarInTouchedPole, we will use
movedOutBar when moving movedOutBar to the new pole
o Show and hide appropriate questions Icon
o Tell the app that one bar is ready to be moved to another pole
8. Here is the code block for the tasks of the moveTopBarOutTheTouchedPole procedure
9. Here is the code block for “Show and hide question Icon” task in the pole Touched event handler at
step 5. With Pattern Recognition in mind, it is important to note that touchedPole has the same index
in listOfTouchedPole as questionIcon index in listOfQuestionIcons
10. There are many steps in the moveMovedOutBarIntoTouchedPole procedure:
• Calculate the width of the top bar in touched Pole
• Calculate the width of moved-out bar
• Compare the width of moved-out bar and the width of the top bar in touched Pole
As a game rule, the moved-in bar MUST NOT be wider than the top bar in touched Pole
• If the moved-in bar is smaller than the top bar in touched Pole, do the following tasks:
o Add the moved-out bar into the list of bars in touched pole
o Calculate x position of moved-in bar
o Calculate y position of moved-in bar
o Change the position of moved-out bar to the calculated x and y position
o Update playerMoves label
o Show and Hide appropriate icons
o Tell the app that one bar is ready to be moved to another pole
• If the moved-in bar is wider than the top bar in touched Pole, show a reminder message
• Check to end the game when certain requirements are met.
11. Here are the calculateWidthOfTopBarInTouchedPole and calculateWidthOfMovedOutBarblock blocks:
At this stage, when pole 1 is touch, its top bar should move out and question icons should display below the
Pole 2 and Pole 3.
12. Before calculating the X and Y position of moved-in bar, it is worthwhile to have a look at the X and Y
position of five bars of all three poles:
Pole 1:
• bar1: height = 80, width = 80, x = 50, y = 70, picture = bar1.png
• bar2: height = 80, width = 100, x = 40, y = 95, picture = bar2.png
• bar3: height = 80, width = 120, x = 30, y = 120, picture = bar3.png
• bar4: height = 80, width = 140, x = 20, y = 145, picture = bar4.png
• bar5: height = 80, width = 160, x = 10, y = 170, picture = bar5.png
Pole 2:
• bar1: height = 80, width = 80, x = 225, y = 70, picture = bar1.png
• bar2: height = 80, width = 100, x = 215, y = 95, picture = bar2.png
• bar3: height = 80, width = 120, x = 205, y = 120, picture = bar3.png
• bar4: height = 80, width = 140, x = 195, y = 145, picture = bar4.png
• bar5: height = 80, width = 160, x = 185, y = 170, picture = bar5.png
Pole 3:
• bar1: height = 80, width = 80, x = 385, y = 70, picture = bar1.png
• bar2: height = 80, width = 100, x = 375, y = 95, picture = bar2.png
• bar3: height = 80, width = 120, x = 365, y = 120, picture = bar3.png
• bar4: height = 80, width = 140, x = 355, y = 145, picture = bar4.png
• bar5: height = 80, width = 160, x = 345, y = 170, picture = bar5.png
13. Here is the calculateYPositionOfMovedInBar procedure:
Using abstraction and pattern recognition skills, we found that the Y position of any bar in any pole can be
calculated with the formula as below:
170 – ((number of bars in touched pole - 1) * space between each bar)
Space between each bar is 25
Using abstraction and pattern recognition skills, we found that the X position of any bar in any pole can be
calculated with the formula below:
Maximum X Position of each pole – ((Bar ID of moved-out bar - 1) * width difference between each bar)
Maximum X Position of each pole could be found in the position of five bars in all three poles
Bar ID is the number after the name of bar
Width difference between each bar is 10
14. Calculating the X position of moved-in bar is more complicated and has the following steps:
• Calculate the X position of touched pole, so that Maximum X Position of this pole can be
identified. Afterward, this position is compared with the X position of poleTouch in step 5:
o poleTouch1: height = 200, width = 125, x = 25, y = 40
o poleTouch2: height = 200, width = 125, x = 200, y = 40
o poleTouch3: height = 200, width = 125, x = 360, y = 40
• Get bar ID, which is the number after the name of the bar. The width of moved-out bar can be
used to identify the bar ID.
• Calculate the X position of moved-in bar based on the formula above
15. calculateXPositionOfTouched block and getBarID are as follows:
16. Below is the updatePlayerMoves procedure:
17. checkEndGame procedure will check if there are 5 bars in the current touched Pole and where they are
in Pole 3
18. Drag and drop two buttons and one HorizontalArrangement components into the
messageResetAndExit component, just after After minimumMoves label, in the following order and
change their name, size, background color as follows:
• spaceHorizontalArrangement3: width = 180, BackgroundColor = none
• resetButton: height = 22, width = 22, picture = reset.png
• spaceHorizontalArrangement4: width = 30, BackgroundColor = none
• homeButton: height = 22, width = 22, picture = home.png
19. When the resetGame button is clicked, the following actions will take place:
• Set listOfBarsInPole1, listOfBarsInPole2, listOfBarsInPole3 to an empty list
• Set global resetGame variable to true
• Call addBarsIntoListofBarsInPole1 procedure.
20. The five bars are to be moved back to their original position in Pole 1; therefore
addBarsIntoListofBarsInPole1 procedure is changed to simulate the move-out and move-in process
when resetGame variable is True:
21. To prevent a player from accidentally resetting the game, make changes to the
addBarsIntoListofBarsInPole1 procedure as follows:
22. Add an event handler for homeButton click as follows:
Part III: Add virtual screen
1. Set the visibility of messageResetAndExitHorizontalArrangement and gameScreen to false.
2. Add a Canvas component, change its name to excellentScreen, details as per the image below:
3. Drag and drop 3 ImageSprite components and change their properties as follows:
• excellentImage: height = 230, width = 500, x = 0, y = 0
• playAgainButton: height = 30, width = 100, x = 100, y = 200
• exitButton: height = 30, width = 100, x = 300, y = 200
4. Add exitButton touch event handler as follows:
5. Edit the checkEndGame procedure as follows:
6. Set the visibility of messageResetAndExitHorizontalArrangement and gameScreen and excellentScreen to
false.
7. Add a Canvas and name it homeScreen, upload an image named background.png from the Images folder,
set the homeScreen BackGroundImage to background.png, and set its height and width to “Fill parent”.
8. Drag and drop 4 ImageSprites, and change their details as follows:
• easy: height = 150, width = 120, x = 25, y = 110, picture = easy.png
• medium: height = 150, width = 130, x = 190, y = 110, picture = medium.png
• hard: height = 150, width = 145, x = 355, y = 120, picture = hard.png
• about: height = 20, width = 60, x = 225, y = 60, picture = about.png
9. Add an event handler for About ImageSprite as follows:
10. We have a homeScreen now, so add an event handler for the playAgain ImageSprite in the excellentScreen.
11. Set the visibility of homeScreen to false. Add a Canvas and name it aboutScreen, upload an image named
Aboutbackground.png from the Images folder, set the homeScreen BackGroundImage to
Aboutbackground.png, and set its height and width to “Fill parent”.
12. Drag and drop an ImageSprite, and change its details as below:
• homeButton2: height = 30, width = 30, x = 455, y = 5, picture = home2.png
13. Add an event handler for homeButton2 ImageSprite as follows:
14. Add an event handler for easy, medium and hard ImageSprites:
15. Add startGameWithLevel block as below:
16. Add setMinimumMovesBasedOnLevel procedure.
17. Make changes to addBarsIntoListOfBarsInPole1 as follows:
Part IV: Room for improvement
1. Add a timer so that the player has to complete the game in a certain time.
2. Add local storage to save the player’s name, number of moves, and their completed time.
3. Add TinyWebDB to backup the player’s name, number of moves, and their completed time when there
is a network connection.
4. Allow players to set their own number of bars (max 10) and create the new game with that number.
CONGRATULATIONS!
You have completed a very advanced AppInventor tutorial and can be proud of yourself.
If you have any difficulties in completing the tutorial, I am more than happy to be reached at: