
Winston Chang || Part II: Handling Duplicate Letters in a Shiny Wordle App || RStudio
00:00 Introduction 00:52 Setting up the problem with duplicate letters 02:08 Coding the first pass for exact matches in the correct position 06:29 Re-evaluating how to approach the problem 12:28 Removing only one instance of a letter 13:56 Testing our code 14:54 Setting up the second pass 19:08 Scoping with a double arrow 19:52 Debugging with a browser() statement 21:28 Checking our code In Part II of this four-part series, Winston walks through how to handle duplicate letters when building your Shiny Wordle app. Code + word list: https://github.com/wch/shiny-wordle Check out the full Shiny app here: https://winston.shinyapps.io/wordle/ You can 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: Developer (@winston_chang) Animation, design, and editing: Jesse Mostipak (@kierisi) Wordle: https://www.powerlanguage.co.uk/wordle/
image: thumbnail.jpg
Transcript#
This transcript was generated automatically and may contain errors.
We have it checking words we have it well first we have it limiting the input to five letter words and those are five letter words that actually are in the list so that's good and then we have it checking the correctness of each letter which is also good although there is one thing that isn't quite right let's see the target word is oh yeah good
so like let's let's see what's a five letter word what with two two letters that are in the target word so we that if we have this word saves that's that's my guess so these are all in the right position the last three letters because the target word is gives but it's also saying that s there's an s here that's in the wrong position and in actual the actual wordle game it would not say that this s is in the wrong position because that was already sort of used up that in the target that s in the target word is used up by this one that was in the correct position
Setting up the problem with duplicate letters
I think what we need to do is we need to take two passes comparing the target word and the guess and the first pass will just look for the exact matches where they're in the right place and this will sort of use up those letters in the target word so if the target is gives we take one pass we find these three match and then the only the only remaining letters are g and i and then we take another pass and we'll check you know we'll check whether these letters in the guess are in those remaining letters g and i so yes if the guess these remaining guess letters s and a are in the remaining target letters okay so let's do that
I think what we need to do is we need to take two passes comparing the target word and the guess and the first pass will just look for the exact matches where they're in the right place and this will sort of use up those letters in the target word so if the target is gives we take one pass we find these three match and then the only the only remaining letters are g and i and then we take another pass
Coding the first pass for exact matches
all right so first we'll take one pass over the word over the words and just look for the correct or the result or the whether we just look for places where their exact matches in the correct position all right and if they're not or sorry if it is in the correct position then we should mark that that letter is sort of used up okay so there's two ways we could do that we could we could mark the letters that in the target word is being used up or we can actually just keep track of the remaining letters so that are not used up so let's let's do it that way I think in this case it'll be a little bit simpler so so there's the target letters there's the guess there's also remaining let's call these remaining letters
and uh your director of length zero okay so so if it's correct great else um remaining and uh well we can grow the vector this way remaining and we'll just that target letter we'll add it to the remaining the sort of a list of remaining letters okay so that's our first pass over the word and then we'll take another a second pass over the word and I guess let's do the same thing actually this looks a little bit better like that iterating over the letters in the guess even though it's effectively the same it sort of feels more correct that way
all right so um so if you can actually reuse this code here so if the guess is not or if it's not already a correct result so we can say okay if the guess does not match the target letter here and the guess is in the set of not target letters but remaining letters then then we'll say the result is in the word okay um and let me think about this we also need to in this case we actually need to remove that remaining letter uh from we need to remove that letter from the set of remaining letters so let's uh we can we can try this here so if we say oops let's run this function okay compare words uh target is gives and we're making a guess saves
that totally did not work this logic is messed up here
oh you know what we can do actually let's let's start the um the results instead of an empty character vector let's start it with a character vector where the starting value is like it's just not in the word and then if we find matches or if we find yeah if we find correct letters or in word letters then we'll replace that entry so let's say we'll do a rep not in word five okay so that will that creates a character vector with at length five with all the same value not in word and that'll be um that'll be our starting value for result and then we'll replace those entries as we iterate so let's try this again um pair words pair word gives and saves okay that's right so previously the problem with saves that was the first s it said was in the word and now um now it's saying it's not in the word because that's used it by that the last s there
Re-evaluating how to approach the problem
um but there could be a problem let's see yeah all right this is not an actual word so this would not be accepted by the whole app but um but we can test this out by comparing like we want one of these g's to indicate oh actually that's that's actually not helpful so sorry um this is a total nonsense set of characters but what we're trying to figure out here is um we know that this s will sort of be marked as correct and it'll consume it'll use up uh the s and the target word so that this first s will not be marked as in word but will the same thing happen for the g um when it's just in the word like one of them should be marked as in the word but in the wrong place but not not both of them
but what's happening is that they're both being marked as in word so we actually need to uh if we have this match here we need to remove that guess letter from um the set of remaining letters
i always get i always have to try this out so let's say match match function what does this do match it returns okay this is okay good that's got a little lucky here
so the match function always sort of i always have to test it out and uh i think this is the right this is the right order of arguments um so i'm saying like hey given this letter and this vector with a bunch of letters um what's what is the first position where this letter shows up in the second in this the first thing shows up in the second thing i think that's right let me make sure the vector positions of the first and the second um i think that's right let me just
so if i if these are all g actually yeah one okay great
all right so i can say um remaining and give it this index here so i say match where uh okay so this is a way to remove things from a vector so i can say um and actually why don't we why don't we just try this out this is uh this is a good good way to test things out uh in r so if i say um say remaining i'll just i'll just actually create some variables locally and we'll we'll test them out in the console remaining letters are g and i
and uh let's say guess is just g so it's a little bit different here because from what we have here because here we're using guess bracket i but let's just take this code and remove that so so here we're we're gonna try to remove g from the remaining uh remaining vector oops
that did not work oh you know what sorry there's a much easier way to do this so um oh yeah there's a much easier way to do this okay sorry this would have worked if it was a list but it doesn't work for character vectors or for for like atomic vectors what we can say is remaining is uh let's just take all the letters that are not equal to that guess all right um
Removing only one instance of a letter
um okay so you know let's here let's try this again let's with some just example code here so remaining is g i guess is g oops and we can actually just print this out with this without assigning it so oh yeah sorry gotta get rid of that i
so false and true so um yes it does match this one so that's false and it does not match this one so that's true so we say remaining our guess is not equal for meaning and that gives us just i and that is what we want oh no that's actually not true because we only want to remove one at a time right so let's see but this will remove all of the g's if there's one
um if the guess has one so let me okay i gotta think about this again no no okay here it is here it is so x minus three is there okay all right all right all right character let's see so we're gonna we're gonna go back to the match thing so let's say remaining let's see how did we do that what did we do before um right the index was okay okay we did so let me just do this we'll do match guess comma remaining okay
so let me just just g and g just we want to make sure that we just get one of them that's position two that's the first match there so great so then we want we want to say is remaining bracket minus that okay so that removed that one entry that's what we want all right so let's do minus match minus match guess okay
Testing our code
all right let's try pair words let's see we can say that we did that one that looks correct uh and then we also did if we put a couple g's in there we just want the first one to say that it's in the word and that's right okay um all right so now we've fixed up our word comparison algorithm by taking two passes and let's uh let's try it out okay so again we still know the target word is gives and when we said aisle that looks right and if we say um saves great it's not marking this s as being in the word because we already used it up all right excellent
Setting up the second pass
okay now uh now we need to give it we need to have it keep track like accumulate all the previous results and keep printing that out so um let's see let's just make sure if we type in give great they're all right okay cool so um let's see i think the way that we can that we should do this is we can actually just store the results um the previous results in a uh in a vector or sorry sorry in a list so let's say um let's create a list called all guesses and we don't have to do anything uh fancy with reactivity here uh there may be cases where that's useful but right now we don't need it if we find that we need it then we can we can make that change but let's say all guesses is a list and every time that somebody makes a guess that makes it past here then um we will add that to the all guesses list
let's see we could store the whole all that information yeah let's do that yeah so let's say all guesses and input dollar guess okay and this is going to be a string so actually this is uh this is just gonna be a character vector for right now yeah that's that's fine okay and then what we want to do is okay well this is not the most efficient way but that's how we're going to do it so
we can do a uh so sorry right now this is going to store all the guesses but it's not going to do anything with them it's still just going to print out the most recent one but we also we wanted to update this text box with all of the previous results um or all the previous guesses so there's a number of ways we can do that um you know again i'm just going to try to keep things simple so let's we're going to append this most recent guess to all the all the guesses and then um let's just iterate over each of them and um and do the check uh every sorry we'll check each word and that's going to happen every time somebody enters in a new guess so again this is not super efficient but it's it's fine for what we're doing right now so uh this time i'm going to use uh i'm going to use vapply so this is like applying a function over many items so the items are all guesses a function that takes in that particular guess and does something with it so um oh let me just say you have to specify the return type for vapply so format the result and then this will this will return a character a vector
so each each guess will get this this treatment where it you know returns a string that looks like this and then we're going to get that vector back and then we should do something with it so but let's just say um oh string that and then let's see if that works so um let's guess aisle again and saves oh that's replacing it that's not what we want
Scoping with a double arrow
oh you know what you'd use a double arrow here because i was using a single arrow it was just scoping this assignment within this uh this render text block here so it wasn't actually modifying this copy of all guesses it was just modifying a local copy of it so i need to use a double arrow to make sure that i'm modifying this um this copy of all guesses out here let's try it again i'll saves okay well that's sort of right it's just sort of sticking them next to each other
Debugging with a browser() statement
um and remember this is a character vector and what we want to do with it is um well actually why don't we let's take a look at it this is this can be handy a handy tip here so you can stick in a browser statement here which will take it to the it'll go into the r debugging console every time it hits that line of code so let's reload the app let's say again let's do the same guesses i'll go okay now it hasn't printed anything out here but we are in a console in our console that's stopped right here so we can say what is this out string thing okay it's actually it's this uh it's a character vector looks like it's a named vector which doesn't matter for our purposes um and that's the that's the content okay great that looks like that now if we make another guess saves
let's say out string and uh it's a character vector with two items in it and we actually want that to them to be printed one on top of each other so let's just let's say um paste out string uh collapse equals backslash n so that's what we want there's a backslash n new line right there um if we want to see what it would look like we can use cat on that string so that's that's what we want to come up here all right so let's do uh
Checking our code
let's take this and put it in here save that i'm going to quit this debugging console you can do it by clicking stop or capital q and we'll delete that browser statement there so we don't keep doing that and let's run the app all right file saves oops gives pretty good at this

