Simple tutorial to help with the basics
(post 1 of 4)
Due to the relevant absence of English-language tutorials for this app, I thought I'd write up a simple program and explain things as I go in order to provide examples for syntax, logic trees, etc. I'm going to assume some knowledge of basic programming knowledge such as variables, but this should hopefully be pretty easy to follow. Feel free to ask for clarification on any point, I wrote this to help after all =)
What we're going to make is an inversion of the included number-guessing game. Instead of the player guessing the computer's number, the computer is going to guess the player's number (between 1 and 100). The player, after each guess, will provide a clue to the computer by pressing A for "higher", B for "lower", or START for "correct".
The first thing we want to do is set some variables. Like most modern programming languages, SmileBASIC uses a single equals sign (=) for variable assignment. For this game, we'll need to keep track of three things. Open up a fresh editing screen and type these three lines:
LOWEST = 1
HIGHEST = 100
GUESSES = 0
The LOWEST variable will store the lowest possible target number based on the player's clues. HIGHER, likewise, stores the highest possible target number. Because we'll be asking for a number between 1 and 100, for now the player's number could be anywhere in that range. The GUESSES variable will keep track of how many guesses the computer has used.
Now that we've finished setting up, we want to greet the player an explain what they have to do. To do this, we display text on the screen using the PRINT command. Add these three lines:
PRINT "Think of a number between 1 and 100."
PRINT "When you're done, press A."
The first command, CLS, simply clears the console of any previous text so we have a fresh slate. The PRINT commands take whatever's inside the quotes and displays it on the screen. Try running the program to see how it looks.
Next, we need a way of stopping the program until the user presses the A button. What we're actually going to is set up a loop that will repeatedly check if the user pressed A, and only moving on if he/she has. Here's the next batch of code:
IF BTRIG() != 16 THEN GOTO @STARTLOOP
The first line, @STARTLOOP, is what's called a "label". It doesn't do anything by itself, it just names that line "@STARTLOOP" so we can refer to it later. Label names have to start with "@". If it helps, you can think of it as that line's Twitter handle =)
The next line is a "conditional" or "branch" statement, IF. The syntax here is IF [condition] THEN [action], or in other words: if the condition BTRIG() != 16 is true, then execute the command GOTO @STARTLOOP.
First, the condition. BTRIG() is a function that checks what buttons the user has pressed since the last frame (a frame is roughly 1/60 of a second). It returns a number code representing what buttons have been pressed. We check the manual and find that the code for the A button is 16. != means "does not equal", so what this is saying is: "if BTRIG() does not return 16..." or in other words "if the user did NOT press A since the last frame..."
The action is a lot simpler. GOTO @STARTLOOP means that the program immediately skips, backward or forward, to the line labeled @STARTLOOP. So what this whole line of code is saying is: "if the user did not press A during the last frame, go to the line labeled @STARTLOOP". Because this is the line before it, we're just going to check the button presses again. And again. And again.
(post 2 of 4)
What happens when the A button is finally pressed? Well, when that happens, BTRIG() will return 16, the code for the A button. In that case, the condition BTRIG() != 16 is false, because BTRIG() will be equal to 16. Thus the action GOTO @STARTLOOP will be ignored, and the program will continue on its merry way. In essence what we're doing is asking the system "Did he press A yet? Did he press A yet? Did he press A yet?" until the user finally does so, at which point we move on.
Now add this line:
All this does is make the program wait for one frame before moving on. Even though the pause will be indistinguishable to the user, this is important because without it, button input might "leak" from one prompt to the next.
Try running the program again if you like - the program should ask you to press A, then pause. When you press A, the program should immediately exit (the text "OK" will appear).
Now we're going to do a little planning. This game is going to repeat the same set of actions over and over until the end of the game, so we'll want to set up a gameplay loop.
Start game -> make guess -> if guess was correct, end game, otherwise move on -> check player clue -> back to start
We begin implementing this by making another label. Add this line of code:
This will represent the beginning of our gameplay loop.
Our next step is to implement the "make guess" part of the loop. Our computer's strategy will be this: given that we know the lowest and highest possible numbers, guess the number directly in the middle of the two (so the first guess should be 50), or in other words, the average. We can use the formula (LOWEST + HIGHEST)/2 for this. One thing to consider, though: what if the average isn't a whole number? We only want to deal with whole numbers here, so we should round our guesses down to the nearest integer. We can do this with the FLOOR() command. Our guessing formula is then FLOOR((LOWEST + HIGHEST)/2).
Here's the code to display our guess to the user:
LOCATE 0, 11
PRINT "Is your number " FLOOR((LOWEST + HIGHEST)/2) "?"
PRINT "A: Higher B: Lower"
PRINT "START: That's correct"
GUESSES = GUESSES + 1
We've seen CLS before; it wipes the screen of text. LOCATE is a command that changes where the next line of text is to be PRINTed, in this case the 0th column, 11th row. This will put the text closer to the middle of the screen, which looks cooler. The next lines of text will be printed right below the first one, as usual.
Take a look at that first PRINT command. We're actually printing three things here:
-The string "Is your number "
-The result of our guessing formula FLOOR((LOWEST + HIGHEST)/2)
-The string "?"
When you list things like this one after the other on a PRINT command, they'll all be printed on the same line. So for our first guess, this should print "Is your number 50?". You may have noticed that I didn't put quotes around the guessing formula. This is because we want the program to print the result of the formula, not the formula itself. Anything with quotes around it is considered a text string, so if we put quotes around the formula, we'd be printing the line "Is your number FLOOR((LOWEST + HIGHEST)/2)?", which makes no sense to the user. This is an important point, so make sure to keep it in mind.
The next line of code, GUESSES = GUESSES + 1, is incrementing the value of the GUESSES variable because we just made a guess. (In general, if you want to increase the value of a variable X by an amount Y, you type X = X + Y)
Finally, WAIT 1 is inserted in order to stop input leaking, as before.
(post 3 of 4)
Next thing we need to do is check the player's response. Because we're looking for three different buttons (A, B, and START), this will be a little more complicated than last time, but the basic principle is the same: keep checking the buttons until the player has pressed one of the ones we're looking for.
First, we should get the button codes for the three buttons. From the manual we find the codes are 16 for A, 32 for B, and 1024 for START. Add these lines of code to setup our loop:
IF BTRIG() == 16 THEN GOTO @ABUTTON
IF BTRIG() == 32 THEN GOTO @BBUTTON
IF BTRIG() == 1024 THEN GOTO @ENDGAME
Let's take this line by line. @INPUTLOOP simply labels the beginning of the loop, as before. Next we have another IF conditional. Recall that BTRIG() checks the button presses and returns a number code for the button(s) that were pressed. The double equals sign (==) means "equal to", so here we're checking if BTRIG() is equal to 16, which means that the A button was pressed. If that's the case, we go to the @ABUTTON label, and continue from there. (We haven't made the @ABUTTON label yet, but don't worry, that's the next step.) If BTRIG() is not equal to 16, we move on to the next line, which is another IF. Here we're checking if BTRIG() is equal to 32, which means the B button was pressed. If so, we move on to the (currently nonexistent) @BBUTTON label. If not, we move on to the next line, which is checking BTRIG() for 1024, or the START button. If START was pressed, the game is over, so we go to the @ENDGAME label, where we'll display the results. If START wasn't pressed, we move on to the next line, GOTO @INPUTLOOP, which will take us back to the beginning of the input loop to check again, and again, and again, and again...
Now that we're detecting button presses, we need to do something about them. We just wired the A button to go to a label called @ABUTTON, so we better set that label up. Enter the following code to handle the A button behavior:
LOWEST = FLOOR((LOWEST + HIGHEST)/2) + 1
As we know, if the user presses the A button in response to a guess, that means that the user's number is higher than the computer's guess. Think about it - if we guess 50, and the user says "Higher!", what numbers are ruled out? 1, 2, 3, 4, 5, ... all the way up to 50. So now the lowest possible number is 51, one greater than the guess. So when the user says "Higher!" by pressing A, we set the new LOWEST number to our guessing formula + 1. After we've readjusted the bounds, the line GOTO @GAMELOOP kicks us all the way back to the @GAMELOOP label, where the computer will guess again given its new bounds. Because we've raised the lower bound, the computer's guess will be higher than last time - just the effect we want.
Now we need to set up something similar for the B button. It's just as easy. Add this code:
HIGHEST = FLOOR((LOWEST + HIGHEST)/2) - 1
The logic is the same here. If the user says "Lower!" by pressing B, that rules out the guess and all numbers greater than it. So the the HIGHEST possible number must be adjusted downward to the guess minus 1. This will result in a lower guess once GOTO @GAMELOOP kicks us back to the beginning of the loop.
Now all we need to do is handle what happens when the user ends the game by pressing START. All we need to do is display the number of guesses the computer used, but for fun, we're going to display it in an interesting way. For each guess, we'll print a heart character (<3) to the screen, one by one, with a beep sound accompanying each heart. Here's the code:
LOCATE 0, 11
PRINT "I got it!"
PRINT "Guesses: ";
FOR I = 1 TO GUESSES
(post 4 of 4)
Again, let's take this line by line.
CLS we know. It clears all text from the screen.
LOCATE 0, 11 we've also seen before; it sets the location for printing text to the 0th column, 11th row.
The PRINT statements are easy, but note the semicolon at the end of the second one. This means that you don't want a line break after the text, i.e. the next PRINT statement will begin on the same line.
Now, the fun part. FOR is a looping statement. For now, think of it as way to repeat a set of instructions a specified number of times. The syntax is this:
FOR [counter variable] = [start value] TO [end value]
[stuff to repeat]
[stuff to repeat]
[stuff to repeat]
What happens is, when we first reach the FOR statement, the counter variable (named I in our case) is created and given its start value (1). Then everything between the FOR and the NEXT commands gets executed. Next, the value of the counter is increased by one and the statements are executed again. When the counter variable reaches a value greater than the end value (in our case GUESSES, the number of guesses used by the computer), the looping stops an the program moves on. In our case, everything between the FOR an the NEXT will be repeated once for every guess used by the computer.
So what, exactly will be repeated?
PRINT "<3"; will print a heart to the screen. Again, the semicolon means "no line break".
BEEP will simply produce a beep sound.
WAIT 20 will cause the program to pause for 1/3 of a second, for dramatic effect.
Finally, once the looping is done, only two statements remain:
WAIT 120 causes the program to wait for 120 frames (2 seconds) in order to let the player observe the result before the program ends.
END ends the program. (This isn't strictly necessary, as a program will automatically end when it reaches its last line.)
Alright, that's all! Try running it; you should have a (mostly) working guessing game. =)
If there's something wrong, double-check the code. Either you made a typo or I did ^^; Let me know if I messed something up.
In any case, if this tutorial helped (or even if it didn't), comment with your feedback. I'll keep it in mind if I write any more tutorials =)
And finally, here's a QR code with the complete source for this tutorial. Feel free to experiment and play around with it if it helps your understanding.
(Note: As presented, there is a minor bug in the program due to rounding. It's not a big deal though, and I'm way too tired to think about how to fix it at the moment)
Great job on this. These are good basics to understand, and should give you a starting point to experiment with the other commands.
How do I break this to you...if I never reward you with attention, I may see you as a troll.
Buy these: Ace Mathician, Xenoblade, Solatorobo
Genres I'm interested in developing games for: JRPG, WRPG, SRPG, FPS, and platformer.
One man's junk is another woman's treasure.
Very, very helpful. I haven't used basic in years and this really helped refresh my memory, thanks. Sticky Requested.
Work is for people who don't know how to fish!
3DS Friend Code: 1289-8728-7299
Here's a translated quick reference for commands.
how do you request a sticky? i'd like to request one
3DS FC: 1676-3725-4140 (msg me if you add me)
So I have a question, and idk if anyone in this topic can really answer it but it's related so I guess I'll give it a shot!
I made some slight edits to this program as I was taking it down in order to try and make it a little more complex. My first attempt at this was to make the number guessed truly random instead of the result of a formula. An example of this is NUM= RND(100). Of course I need this in terms of the Lowest and Highest variable though, so I replaced that with the equation NUM=RND(NUM>=LOWEST AND NUM <= HIGHEST).
Now, the only number the computer will guess is 0 and I'm not entirely sure what's wrong with my equation. I'm fairly new to this so any help is appreciated.
Work is for people who don't know how to fish!
3DS Friend Code: 1289-8728-7299