
Programming Games with Shiny || Roll the Dice || RStudio
00:00 Introduction 01:40 Rolling with eventReactive( ) 06:26 Reducing eventReactive( ) to reactive( ) + isolate( ) 16:23 Combining reactive( ) and bindEvent( ) 20:11 Reviewing our reactives 21:23 Writing a function to de-duplicate dice rolls 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/0.14/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/111291")
image: thumbnail.jpg
Transcript#
This transcript was generated automatically and may contain errors.
So what do you think should we do let's make a quick little app this isn't gonna do much for us right we just have our blank app but what do you think like an input and a button I think I think just a plain button and maybe some text output and it'll be like random dice roll okay and this is actually gonna lead up to one of the first couple weeks when I was working with Joe on like reactivity and it's like we're gonna get to this deduping random dice rolls so yeah okay so we're going back we're going back to the good old days
and then the text I put it you're thinking like verbatim text output just to have it look code like and then we'll add a label to the button oh yeah roll dice or something dice all right we're gonna do more than one is it singular wouldn't it be roll the die ah it just sounds so weird it does so again we're gonna skip over making this beautiful and go straight into the programming logic absolutely I like how you understand me
Rolling with eventReactive()
all right so this is a super fun game it's gonna roll the dice and it's gonna give us some kind of output and then we're gonna work in different ways to do this okay so we would traditionally in our server function we would want some kind of like output code like text and then what how do you want to approach this what do you want to do let's do render text and say like dice of dice Val like a reactive which is called dice Val so okay so you're saying dice Val yep and then let's make dice Val as a as a reactive outside of 14 somewhere before so we've got our reactive value so this is our this is the value of our dice aka single die it's fine that's fine mm-hmm and then that itself is dice Val open close and 17 mm-hmm and 14 we can set up a reactive Val we could probably shorten it to just a reactive okay that listens to it yeah
has a curly bracket on the inside and and it listens to like what input dollar button zero one yes so input okay wait I screwed up my formatting sorry oh right it's no it's all it can be multi-line I like multi-line yeah input dollar okay button one there we go so that's what we're listening we're listening to it but the actual thing that we're doing after line 15 inside the curly bracket because just a reactive oh sorry we're doing event reactive right event reactive we listen to the button right yeah okay so we're making my bed yeah my bed it's okay you were talking about a reactive my brain was thinking about an event reactive and between the two of us we had just it was good it was good
reactive reactivity is not necessarily the most intuitive thing all right separating yeah great so that's that's good and then comma curly and we'll do like random dice Val or something like that like we can either just do the logic here we can make the function somewhere else and are you just thinking of like sample one through six one yeah and then we can get rid of the assignment and just say sample one to six one oh yeah perfect and let's get rid of the curlies right where your your cursors at um because it's restoring it to the name dice Val not to the so dice Val open closed on 14 please get open close great okay we're used that yes whoo-hoo reactivity pre coffee so this this should work let's find out all right so when we click roll dice theoretically what should happen is we should get a print out of a number
let's just there we go I think we're getting all the numbers beautiful all right we've rolled our dice we get our number let's go to Vegas absolutely um so let's actually yes this works let's look at can we do in like after line 9 do like placeholder is true yes and so that's just gonna mean like when we restart up comma listen first of all great so there's just at least the box yep so there we're expecting as a user I'm expecting something to show up there I'm not just looking like what happens when I push the button theoretically I visual cue that something will pop out there I do like a little bit of UI yeah let's not go overboard today yeah let's not push it okay
Reducing eventReactive() to reactive() + isolate()
um all right so things work like this is awesome so let's try to rewrite event reactive without saying event reactive okay how could we do this and let's not use the newer bind event let's actually break it down to the primitives of what's happening we are essentially saying dice about and we want to do this without an event reactive so basically we're saying what happens when we run event reactive because event reactive is like a wrapper function for some other things that are happening under the hood and if I remember correctly it's a re it's not a reactive and an isolate is it it is yeah it is okay so let's see so dice Val is it reactive let's actually go back to our old app and update it just a little bit so that we can get some more reactiveness that the isolate will show off perfect um so let's add in after the action button like a slider or a numeric input that'll tell us like how many dice we're gonna roll or like what's the highest number on the dice oh okay I like the highest number does that let's do let's see select max yeah great
two of the diet of the dice and then we'll need a like a min max and selected value yeah min is one it'll be one max will equal ooh so max would I'm trying to think of this is like what the person is oh no nevermind we're setting up our input so what what is it is a 20 sided die yeah we can go and that 20 yeah it's step or no is it step or by step step is one and yeah value is six let's just start with the default small dice great and then we can listen to that in our sample down in 26 so sample will be I think we can can I do one two input oh I think sample dot int is that something ooh but it's the same thing same concept is where you're heading sample dot int it is of n right so up to n so instead of this we're gonna I'm just gonna comment it out so we can see what we're working with so you're saying sample dot int and we're gonna go let's see n is a positive the number of items to choose from so this would be our input yep okay no wait yeah yep what is an input here and then it is it's a descriptive name but it's long all right so that is the number that they've selected and then size is one yes giving the number of it so size will be one great yeah there I think we're good yeah so that should be equivalent you could do one colon input dollars select max number like that works fine as well
okay so you're saying here we could have rewritten this as sample one two input okay so if we were looking for something yeah we'll just keep that there if people people want to see it so great so this should okay so everything runs let's say instead of six and we do expect it this is a bug we talked about in our last video so we expect that you can override it so it is more than six which is good at least as an initial kind of unit test says to me great it's working mm-hmm nothing nothing's throwing up a red flag I suppose there are other cases we could still work on etc but this is a testing video yeah now it looks good
alright so now we have this event reactive now we have and it listens to a button and on the button click we sample a number for a new dice roll perfect the end result is dice Val is a reactive which we can then read later for the rendered text so okay now it's here great I love it so let's go down the route of deconstructing back to the primitives of just reactive and isolate okay and observe if we need it but I don't think so in this answer okay so we're gonna take this right here everything that I've just commented out and we're gonna break it up into an a reactive and an isolate yes okay so we're gonna call it the same thing and then when I'm thinking about a reactive and an isolate which one comes first does it matter can I do both like can I switch them or is like how would I approach this if I'm thinking about so the answer that you're getting back is a reactive and isolates occur in the reactive expression so it needs to be isolate needs to be inside the curly's
okay so if I'm getting ready to basically write my own event reactive this would be my starting place that's pretty good yep okay so isolate is inside my reactive and so I need to think about what I'm isolating and what I want to be reactive and we're talking about reactive we're talking about like responding to changes in the UI correct
so I would let me think about this so what we had here so there's the button and I'm guessing we want to isolate the button click okay we can read it out I feel like I just walked into a trap okay and then how are we handling 26 26 okay so oh wait a minute I would like to revise my answer because what I want is I want to isolate my sample int I want to basically say like once we have this value then pass it to a reactive okay can I change it yeah absolutely I mean like I know I can but if there's a lesson you've learned yeah it's you're seeing what's gonna happen so alright so we've handled 26 now how do we handle 23 yeah so what I put that's kind of what I put that in here so input so that would be like very similar code to event reactive yeah but reactive only has one like expression that it can take okay got it so reactive we put the curly is so that we can do multi-line yep and then does it oh okay so input I'm not sure that this does it does this this isn't quite right I feel like so the comma yeah the comma is not necessary because it's an expression from 28 to 31 and so input button will trigger reactivity but then we will isolate 30 and so we will use the value for select max number but we will not resample if the max number changes oh this is the answer this is great let's let's give it a shot see if it works
oh this is the answer this is great let's let's give it a shot see if it works
like wait what did I do wrong this makes no no everything's everything's spot-on all right so we have our initial value of 6 oh it did roll for us so that's one thing that's going on okay um we can adjust that afterwards that's a cool cool change that was unexpected so well I mean I guess some of you expected it I didn't and then let's see if we can get this guy we said we could go up to 20 great we're rolling above 20 or above 6 so I feel like our basic wiring is intact and the one thing is that if I reload it automatically rolls for me so that is something that we do need a little bit do you have a quick idea on how to address that I'm really hoping it's rack it is rack can I just wrap input button one in rack absolutely because the default value for input button one is falsy it's zero yeah so basically we're saying rack means require and so we're requiring that button to be pushed so because the button hasn't been pushed nothing is rolling but now we can make our changes and then when we push the button we get a value yay awesome
Combining reactive() and bindEvent()
all right so we've taken a bit reactive we've broken it down now which direction do you want to go let's go to the bind event so we're going to the other extreme and be like how can we rewrite event reactive to just use bind event and reactive okay so I don't think I've used bind event at all so I'm really looking forward to this
so where do we start how do I start thinking about bind event so let's let's look at the event reactive just because it's very explicit as to what's happening so event reactive has two situations it has a I listen to this situation and then I perform that as another expression and so the perform that returns a reactive so let's just make a reactive where we sample the end okay so we're talking about reactive and then oh my goodness sample int put select max number and size equals one okay so we've got that reactive awesome and we could just you know let's run this app just to see what it does love it okay so it works once right so when I read the app it rolls but the app is rolling for me and no matter how many times I click the button it will not reroll but if you change the max dice number it will all right so it's basically made my button useless it's like a redundant button because all I have to do is change the number and I get a reroll so we're short-circuiting something in here yes so we need to we want to listen to the button click and so we're going to bind to the event of the button click okay
I stopped mid-sentence but I was like I get to do a pipeable function I get it way to do things yeah I get you and then I'm just gonna trail off all right so I love the way that you explain this right we're gonna we're gonna do the sampling but we're gonna bind it to this clicking of the button so if I run this I'm in anticipating this will be fine this will say six and this will be blank let's hope oh we forgot to load should we go native pipe are you on you know I have never used it so let's let's do both to show that they're equivalent I'm so scared I've never this should work theoretically yes let me stop my app just because it crashed so look at that all right well the dice it works if I change it it's not changing on its own requires that that's great so this for everyone at home that is the the base our pipe you can definitely use that if we want to use our kind of more a tiny versatile pipe we could do library better and then you can swap out this guy for this these are all equipped these are all equivalent
Reviewing our reactives
right this right here is where we broke down into the primitive functions to get our dice roll and then this is using event reactive which accomplishes the same thing but people might be more familiar with and then this uses bind event so bind event is new or newish I mean in the history of Shiny it's new are there situations where I don't want to use bind event or like where bind event wouldn't be appropriate or is it just kind of always there is a good substitute or drop-in for my event reactive and my observe event it's a good substitute I'd say it's like the new school way because rather than having more and more arguments you can just have more and more decorators these extra functions cool um so this is like the end of this idea
Writing a function to de-duplicate dice rolls
but I would love to go down the route of how can we make a function of deduping and it kind of it might go towards closures it may not yeah we can get rid of those and the the idea is that I think we'll start the and we can talk about this but I want to start the random dice roll at like three the max max height is three and then that way it's like I want a random number that isn't so no that one's fine we can keep it there but but the value at three and the goal is like when you roll the dice you never get the same number that you had before like that's a requirement oh okay so to deconstruct this a little bit when I run sample I can set replace equals true or replace equals false right so I'm just running sample but even though I'm doing a version of flavor of sample here even if I said replace equals false because it's reactive that behavior is going to be overridden yeah reactive will always return a new it'll it'll send down saying please I can't think of the word brain fart it's like it's like a fresh start for sample yeah so for every single time yeah so even if I do let's see if we can so replace won't matter because it's size one yeah but you could sample you could call sample into like two of size one and in like the console and it will come with like the same answer multiple times
right we do sample int input oh no there's no input it's just like to do and then we said size equals one mm-hmm and so okay we get to great and do we do it again we get to again and the reactivity would actually say that that's a new value and it would redraw it again and that's fine but I don't want and now it finally goes to one yeah so the goal for me is to more like what if we had a deeper that said every time you click the button don't use a number that you've already seen or at least not the prior one okay so we're saying you can never roll okay so this is a great clarification we're saying you can reroll you can't reroll the number that you just ran so we just have to look back one yeah yep
okay so I thought it was like okay if we have a six-sided die we basically once we roll a number it's out and I think my approach to that I was like oh okay we'll just like store those numbers somewhere but now we're doing something a little different so okay I'm really excited to see how you would approach this let's let's do this so we did we're just like if we have if we roll two we can roll any number that isn't two yes okay so maybe we should bump our min to two on the numeric because a min of one wouldn't make sense we'd get forever true oh look at you thinking of edge cases right out of the box yeah
all right um awesome okay cool so how how like do you have any crazy ideas on how this might happen kind of what I'm thinking of is we need some way to store the number that we just rolled great right our needs some way to kind of catch that number so there's I'm thinking it almost needs to be like this temporary assignment of it can make it a reactive one because any any time we're doing a value that's according to user actions typically it's a reactive or reactive Val in this case okay so if you're doing a variable it's now a reactive Val yeah so last role exists and so now I'm thinking about there's like a timing component to this that is really interesting because if I just do reactive Val dice Val right those will be the same every time I do them so there's I need to stagger in some way so for example I think this will work because I haven't refreshed my code right so I've rolled a three now I want to store three and remove it from like my possible roles fair let's let's try to go through this a little bit more explicit but we could get smart with it later yes force it then clean it up
perfect so 25 inside 25 you were saying you want to know your previous value and so let's let's retrieve like current role or pre-prev role or something like that okay so I have last role and then when I set this equal to current role that's like new role okay I like that better okay and then so this is our new one and then we would be like while new role doesn't or eat double equals last role oh okay so well new role yeah so well our new role sorry hang on new role is equivalent to last role we want to keep rolling last roll open close because it's a reactive fabric this is such a great example of reactivity I mean I know you know that oh it's this one it let me know that you can really bank on rules and it was really neat yeah right so we're just gonna reroll until they're not equal yep so we'll need to on 28 we'll need to update your new role value that's right well new role is equivalent to last role and then yeah so then new role sampling and then at the end of the reactive expression we want to return the new role value so we'll say return or not return but um just new role at the end because it's the last value being yes yes this is this also gets me all the time but yeah I think it actually works when you say return but um it does but we don't need to we don't need to yes we could print we could message we could do all kinds of things there but we should be fine with just this mm-hmm
so the default dice roll is three so there's a high probability that you would get the same number so if we click it like five six times we should always the goals always see a new number all right so we loaded the app let's see what happens crash and burn so we need to maybe say set something for last role because what's happening is it's saying like while the new int equals null is what's happening on 27 so let's just default it to like what do we want to zero well do we want to default it to zero well zero is good because I was gonna say let it roll but I like zero better because zero is not actually within our realm of possibility it's like not in our number set so and it's much simpler than re-rolling yes I like your approach better so we you could also do like if not null last roll then do stuff so yeah yeah this will be faster than I mean marginally faster but we're not writing a big this is much clearer though with some abstraction all right so when we roll the dice we should never get the same number twice
oh this logically makes sense to me it does but what we're missing the final step so now that we have a new role we need to do what we need to replace the last roll there we go so let's make a new reactivity because that logic is solid so let's keep it there okay and we're gonna this is a side effect because we don't care about the actual answer so we're going to do instead of a reactive we're going to do a what for side effects oh yes observe event but we just learned about bind event so let's try to write this as an observe with iso okay oh okay so instead of observe event we're gonna do Barrett look at you just tie in everything together Barrett had the master plan I'm literally along for the ride all right so we should call do we want to call this updated last roll but we don't need the answer so it's just gonna be a plain observe oh that's right right you don't have to you don't have to assign your observers basically long and short of it
I still try though all right so we are going to observe would it be input button one now I think we can just observe the dice roll okay so new role or last role well let's let's go ahead and pipe to the bind event because then we can then talk about the two situations so let's take the observe and then pipe to bind event all right so what are we wanting to do we are wanting to update last roll when dice Val is updated all right so we basically want to say last roll equals new role great so let's do that on 36 that's the action that we're gonna do so last roll and then inside the parentheses we'll say new role that isn't accessible from here but that's the value of dice Val so let's capture dice Val I really wish I had done dice Val with anyway underscore but that's okay we can switch it's not too much but real quick if you're following along at home we've just added an underscore and then yeah so on 36 new role does not exist here and dice Val would be underscored and executed all right it doesn't exist would I super assign it nope so we'll just remove it because we can't retrieve new role we can only retrieve dice Val so let's execute dice Val because dice Val right now is is a function but if we execute it then we're retrieving the reactive value okay great so this will update last role with the value of dice Val so real quick question is that equivalent to saying last role no because that's so that's the urge to do because we are very familiar with variables where we can say like a is five but to update a reactive Val you need to submit it to the function so the update method is inside last role and yeah so I kind of think of reactive vowels as a getter and a setter you get the value you don't send anything to set the value you send in something okay it's overloaded I like the idea of an arrow but yeah it doesn't work because this is not today like where we're passing functions to functions this is like a quirk of our that we yes yes okay yeah so it should work now right but we need something in 40 oh shoot that's right what are we gonna bind it to um right otherwise it's just gonna like do its thing I'm guessing we're just gonna bind it to input button one so it may work because we're performing both actions when input button executes but there's a theoretical edge case of what if 35 runs before 25 right because we have to remember that Shiny scripts don't run line one to line whatever they don't run an order they're more like dynamic right yeah so it may just because they happen but yeah so if observe runs first now we're stuck um yeah so if 35 were to run before 25 then that would be bad can I bind this to the dice Val function like yes Val has to be called yes dice Val awesome
because we have to remember that Shiny scripts don't run line one to line whatever they don't run an order they're more like dynamic right
I think this will work I'm gonna stop it since I think I crashed it last time we'll get a clean start okay so we expect when we hit roll dice that we're going to get not three we're gonna just get like new numbers here it should not be so one so I shouldn't see one got a two three all right look at that that's so cool I would have never this is such a great example too because I was like oh bind event would naturally bind to almost what I would think of is like a physical event like I'm clicking a button or I'm seeing a physical change but I can bind the event to a function call to any reactive value any any set of reactivity okay um and you can have I think you can have rec statements in there like it's just think of it as what would we do in the beginning of that reactive expression you can do lots of logic you can hit lots of reactivity all right okay I want to see what people do with this I want to see I want to see all kinds of things I want to see what you can do with bind event

