Resources

Programming Games with Shiny || Guess the Number || RStudio

00:00 Introduction 00:35 Setting up our app UI 06:19 Using observeEvent() 10:02 Writing an if else statement as part of our feedback mechanism 13:40 Testing our app and deciding which bugs to fix first 14:20 Check yourself before you req() yourself 17:10 Using tabset panels to control what the user sees You've most likely used Shiny to build a web app that displays data, but you can also use Shiny to build games! In this video series, Jesse and Barret pair program simply games in Shiny as a way to uncover and explore new features. Read up on tabset panels here: https://shiny.rstudio.com/reference/shiny/1.5.0/tabsetPanel.html Learn more about Shiny here: https://shiny.rstudio.com/ Got questions? The RStudio Community site is a great place to get assistance: https://community.rstudio.com/ Content: Barret Schloerke (@schloerke) and Jesse Mostipak (@kierisi) Animation, motion design, and editing: Jesse Mostipak (@kierisi) Theme song: Hakodate Line by Blue Dot Sessions (https://app.sessions.blue/browse/track/91291)

image: thumbnail.jpg

Transcript#

This transcript was generated automatically and may contain errors.

I'm thinking of a number and you have you have five guesses to get it. Is there a range? Oh yeah there's a range it's between 1 and 20. 16.4. It's a whole number it's an integer. 14. No. 15. No. 10. No. 11. No. 2. No. Do I get any more guesses? No.

Setting up the app UI

I almost want like a greeting and then instructions and then I want to basically it would be some kind of input guess and then we would want some kind of feedback mechanism. I like it. Perfect. That's it we're done. Call it a day. So we could do something as simple as um welcome to RStudio's guess the number game.

We need to tell them the the range eventually. I'm thinking of a number between a whole number. And you have a whole number between 1 and 20 inclusive. So I'm thinking of a whole number between 1 and 20 inclusive. You have I'm trying to think of the right number of guess. Let's well I think for us let's do three guesses just so we're not spending yeah forever testing. You have three guesses. Two. Three chances to guess the number.

Guess the number. Uh enter your guess in the box below. Enter your guess in the box below and hit the button to see how you did.

Okay we're gonna input a guess. So we need input action button. No. I think it's just action button. Is it? Okay. I like where you're going but yeah I believe it's just action button. Okay it didn't auto fill and I got a little nervous.

All right input id. Um so let's see the action button is going to be oh that's that's not the guess. Submit. Yeah. Submit. Submit. Submit. And then the label will be guess. Guess. Do it. Do it now. I'm gonna be very aggressive. All right so we've got the button but we didn't put in I say we as if I'm not responsible for all of this.

So text input. So we need a an input. It's a number though. Numeric input. All right so this is guess. Is there a label? Yeah. Uh enter your guess here. All right let's pull up the docs because I can never remember all the arguments.

So we can do our initial value is zero. We could do well no let's do it. Can I do null? Can I do null? Uh I think it I think you can maybe. Uh but min is one and oh yeah. Let's also add in just to be explicit step equals one. So if they hit like the up or down arrows it goes up by one. Um yeah let's see what happens. Great. And then if you click and hit like up arrow uh-oh then it like automatically starts. Why is it going back?

Uh this is a old standing IDE bug. If you were to run it in the browser your app works as expected but clicking that little button is actually a bug in the IDE. All right they're double submitting. Got it. So I can override it. Yeah.

Okay I mean oh and then our feedback mechanism. Um we will do something like your guess was and then we kind of have two we're gonna have three options right? Well four options because you're you're too low you guess the number you're too high or you're out of guesses. So we can just do like uh text output or yeah text output and just label it feedback.

Using observeEvent()

What we need to connect here is we need to connect so our guess at some point is going to need to be compared to the actual number and then I know that we're going to have some kind of reactive here because you want to so what seems logical to me is an observe event as in look for this button when this button is pushed perform this action and then based on that we're going to get a feedback mechanism.

So the way I thought of this was where we start with a number um and like we need our number assigned. So then we have the number there's like the the app has picked a number but then we also need to keep track of the number of guesses that our player is submitting and I believe we did that as a reactive val. Yes because this changes given the reactivity. So reactive val versus just a counter as a regular r value. Yes and we set that I remember we set that we gave it like an initial value of zero.

I mean I kind of want to go right into the observe event. Does that works? Yeah. We don't assign this guy to a variable. Let's see if I remember how to type here. So what we're observing is our submit button. So input submit and then yes yeah sorry input submit. All right. Great. Perfect. Rainbow parentheses for the win.

All right. So we're observing basically what we're saying here is like we're keeping an eye on the input submit button. This guy labeled guess and then when that is done the guess needs to increase the counter. Yes. So we have a counter and I look I'm not gonna lie I did not remember this. I had to look this up. We had done so there's like the counter and then because your counter is a reactive you put in your counter with your open parents and then we increment it by one. Yep add one and then to update the counter value we submit it to the counter function and so we've done both the getter and the setter in the same line. Great. So the counter has been incremented.

Cool. So it makes sense to go into like restricting the counter now or to go in. I think it maybe after 31 we add in like the guess because we don't want all of our code to be changing as the user changes the guest their their guess. So we need like a resolved guess but I like guess here so it's also a reactive val. And then after 36 after we've updated the counter we can set guess to be the input guess. So on submit we update the counter yeah and we update um the guess yeah input dollar uh is it yes guess guess all right we're not gonna oh should we name these different no they're fine it's fine and then that's the so the beginning of 37 will be guess parentheses of input dollar guess at uh yeah.

Writing the if else feedback mechanism

Great and now we want to basically we need a way to compare the guests to number and include our counter let's yeah let's just work on all the feedback because that's something that's replaced all right so we're going to get into our little if else statements here which i'm super excited about we call it counter right so if our counter is greater than three so that's when you've run out of guesses.

All right so that's one condition and before we go farther on this this counter stuff let's put it either as uh the body of our render text for our tech our feedback or a reactive of some kind or a reactive of some kind because counter is reactive and then our render text oh i'm going to be so mad about this formatting this is where it's going to go off the rails all right right yeah and close friends yep all right and our render text is going to be our feedback so yep the output output dollar feedback.

Great so now the counter is executing in a reactive context so it's not it's not bad to write it as you currently have where we have if with an else and then inside the else section we have an if with an else and then you keep going because maybe they're they're longer than just an if else um but if they kind of like tail off from one to another then you can kind of just merge the first if with the last elf else and um but it's clear if you write it separately like we're doing right now so let's go through like our numbers so if guess we can do if gas is less than number then we're going to want to give some feedback and the feedback whoops is going to be your guess is too low and then we would do an else if because we have three conditions here right your we have your gas can be too low we can have your guess is going to be greater than the number and then that's when we would want to print your guess is too high and then we would have a remaining else yeah winner winner chicken dinner.

Testing the app

All right so we've done a bunch of code so let's run it and perfect i have an argument length of zero so my guess is i'm getting that because there is no i haven't given it a guess. Uh most likely yep so let's see what happens yeah stop.

Okay let's double check okay hey he just happened to have received it hey. What are the odds that like well 1 and 20 yeah what so i so there are two things that i'm noticing that i'd like to fix let's just reload this guy right so this error argument is of length zero is that something i'm so i want to fix that and then i would actually really like to fix um if you guess the number like the game exits out the guess the number exit let's hold that for a little bit because we'll just worry about the feedback mechanism for now argument of length zero so you said because you didn't have a guess right so what is the trick that we use to prevent render methods from erring but like reactivity is still there what method do we use i really hope the answer is wreck because that is

Check yourself before you req() yourself

mostly because i want to say you have to check yourself before you wreck yourself.

mostly because i want to say you have to check yourself before you wreck yourself.

All right so what we want here is we want input guess uh not necessarily we want eight no uh guess itself because uh you can type all you want but i don't want it to you don't want to submit feedback until oh okay so actually it's the input submit button but input or sorry guess parentheses is not updated until input submit is updated so at this point uh if we wreck guess they're on line 41 then we know the counter is okay because it's defaulted to zero but on 45 um it is like that's where it's actually required yeah so this is good um and guess and counter both get updated on submit so we don't necessarily need to do we i mean to be safe we could also do a rec counter in the same like you can do it in the same line or or uh multiple lines um i do this mm-hmm yes yeah and uh it's i mean that's that's good then that way all your reactives have true must have truthy values meaning that your counter is at least one and your guess is not like missing.

So let's see if this fixes the bug wreck to the rescue perfect love it and wreck is a silent exit and so it just means don't do anything and so there's no feedback displayed which is what we want everything seems to be working what would you say is next is it handling the exit yeah let's do that.

Using tabset panels to control what the user sees

Okay handling the exit trying to think of a quick one here because there's nothing like stop um i mean we can kill the Shiny app i know that though we could kill the Shiny app and then there's an animation that's like confetti you know and and all of that but i feel like that's maybe next call i mean we could have the tab panels here where we just we we remove input guess and just hide it and say refresh the page or something like that so would i just put my whole input section inside of a tab set panel.

Yeah okay so my input section is here so inside taps the panel we need a tab panel body yes but we'll have the h1 inside it have a body just do a little copy paste job here it'll be fine and yeah and all of that as well yep.

And then the first argument to the tab panel body is its uh name so we can call it uh guess module i don't want to use the word module yet how about we'll do a guest panel yeah and the let's for the tab set panel let's also add an id equals so this is going to be like our um guessing area i don't know something like that yeah i appreciate you not wanting to use modules because that is a very specific thing in Shiny uh so even though i'm thinking of this like a module i think yeah guessing area seems a little vague but i don't you're right we should not call it a guessing module uh oh yeah the tab set panel we need to say because there you ran the app and there's like a pill at the top um so we want to say type equals hidden yeah it's a programmatic way so then we got rid of that horizontal rule we got rid of the tab you don't know it's there.

Oh and are you thinking of putting the feedback in a tab set panel that we can also hide um so that it only pops up after you guess or am i completely misreading that uh maybe so maybe i was trying to go too too small with the idea maybe we we go with your original approach where the whole screen goes you guessed it awesome or you ran out of guesses we're done and that's it so it's like the whole game and then that way when you go back to the beginning then we can kind of reset everything like you don't need a greeting and instructions when you can't do anything yeah yeah so you're so what i do i can just put the feedback mechanism in its own tab panel body correct or would it go in a whole new tab set panel uh no let's just put it in the um in like right after 2028 so it's just like our we're gonna put the whole former ui into one panel so let's actually grab the greeting and the instructions from above and put this inside.

I love how this is suddenly become like it's now integrated what we did in the previous let's move um 9 to 13 inside the tab panel body right beneath it oh yeah.

Great and this should work just as is because we've essentially taken our whole previous application and put it in a tab with a hidden nav bar and like everything will work just fine um yeah just nothing is really going to happen here so observe event part um let's let's go ahead and add the this idea and here's where we can since we're familiar with this we can take a stab in the dark on what it should be and we may not see it until we connect the wire okay um so let's go back up to the ui and let's just add in two more tab panel bodies okay um and you can do them here or above either one um maybe we do it as the uh maybe we do it above so that we can at least see it like in line eight and then we might move it below um or add in a parameter later so this one is going to be like uh so guest panel like correct panel and incorrect panel would be the two names.

Uh so we had i'm sorry you literally just said that like correct panel don't listen to any of that yeah i heard it i did not ingest anything so we had guest panel and correct panel uh incorrect panel maybe or wrong panel.

Great and then because we already have guest panel on on 17 and then equals hidden too right uh the type hidden is already done on seven so it's uh this is now just like the body of it so let's just add in an h1 of like your number's wrong and that's it like or are you guessed incorrectly uh yeah chicken dinner and not chicken dinner.

Okay perfect put it in quotes hang on hang on. There we go great um so this is now we can update the panel when our um tab panel body value must be a single non-empty string um let's not title it id on 10 and 15 because i think the correct key is like value or something weird that's not not what makes sense great when we automatically win yes and if we just for fun if we switch correct panel and incorrect panel or we say let's just go ahead and do this one how about after line seven say selected equals incorrect panel wrong and just to make sure guest panel is still there we can just add that in for selected.

Oh yeah i love that so this is we wanted to avoid this in the last one because it would have been a bunch of debugging but now we're kind of figuring out placement so this is fun to work on yeah and our game is still here i love that this is this is our starting screen as well so we can actually leave the selected there so it's not just a debugging ourselves let's go back to that observe event my favorite i actually really like observe event for some reason that one just clicks with me.

So it it really does um this is a so observe is wonderful for side effects um we can do this all in one observe event but mentally i kind of think of this as like when do we go to these final screens right so to me it's an extra observe event okay um so what are we observing in this case uh the counter is too big right so if the counter is too big uh uh yeah so uh counters so we'll say if counters greater than three then we want to do what is it update tab set panel um with the session is fine input id equals and we'll have to label it yeah input id equals what is it guess area what did we call it at the top between the two of us we're gonna get this uh i guess panel guess the top top top top guessing area guessing area c guessing area and the new value is um we could we could send them to wrong right and this is the value i can't remember value equals um incorrect incorrect panel panel so let's try this see what happens.

Oh okay cool um so observe event this is expert is missing observe event needs a listen to this and then perform that yeah so we just said hey go do this thing but that's not what observe event wants so we should listen to counter yeah uh but yeah keep going.

Then restart curly oh yes thank you i was like it's it's somewhere. There we go great so this uh yeah kill and restart yeah.

Okay so now if i just do value is the incorrect name uh so let's look at update select the update oh selected not not value but selected all right okay so we'll give it a one all right okay so we'll give it a one and we'll guess three times one right well here i'll change it just just you know all right that was three guesses now when i it's yes when i do the fourth guess wrong i don't know why i like that so much but i love it all right that's great so would this now be a situation where i've got my first if and can i i don't want to be like just but would it just be else well would i want all three conditions in here uh no like so this isn't necessarily towards the guess we've actually handled the 73 and 74 because that will never be touched anymore as if you hit if you run out of guesses we now go to the wrong page.

Yeah so we can actually remove that if you want from the app so we can get rid of these.

It's practice on practice i love it so now i feel like we've made it we've added functionality we've made it a little more efficient we broke it i mean broke it.

All right so we have removed our because we're handling our counter we've removed it from our counter we've removed it from our if else statement so at this point do we add an else and then we would only need an else for um sending them to the correct answer.

Yeah so we could do i mean you could this is where it's like it comes down to a little bit of like style and how you want to do it uh so we can have the single observe event be like handling like sending you to the place uh the flip side is like this is a observing the counter and when the counter changes if it's bigger than three then we go somewhere but um maybe we want to do like observe event of guess and if guess is uh um yeah of the guess and given the guess we'll do another uh curly outside yep and we'll now say if um guess double equals number then update tab set panel correct.

Okay good i think i got some.

Maybe the close on 79 or 78 one of them great okay um so theoretically if we scroll down just a little bit the feedback of 88 will never be touched or it will it will be touched but it will never be displayed wouldn't it be displayed for if your guess is too low or your guess is too high correct but not 88 okay so we could get rid of this if correct and then this guy.

Uh-huh okay it is equivalent um yeah i love it all right uh oh but we still have the rule there on 85 so it needs to be an else if um or just plain else with no guesses greater than number that's right okay.

So if we say 10 it's too high five it's too high two and now there's there's a weird behavior here because at this point i'm entering a fourth guess and it's letting me guess.

So if that's the case then i think we should combine our observe events okay so these when you're talking about combining observe events you're talking about and 71 all right so if counter is greater than three okay so that the if logic is still good but maybe at 68 it's now an else if guess double equals number and you can just take your logic from 73 like verbatim.

Now we'll get rid of this guy need everybody to calm down on the formatting we're gonna figure it out maybe close parens after 71 add a close parent after 70 oh okay great.

Oh oh we have a if argument is of length zero oh i remember from before we needed to wreck guess yeah so we do perfectly oh go ahead oh perfectly fine to do in 63 if we want to do it there so wait you're saying it's like where in 63 would i put a rec guess inside the the curly brace uh before the if got it so i would do guess and then new line and then we're good all right new line.

Oh i broke everything there we go got it so i would do rec guess and then new line and then we're good all right.

Oh i broke everything. Perfect have we done it i think it's pretty close yeah it's too low so we'll do 15 it's too high i was wrong.