Construye tu propio juego de buscaminas en Java | Alvin Wan | Skillshare
Drawer
Search

Playback Speed


  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

Build Your Own Minesweeper Game in Java

teacher avatar Alvin Wan, Research Scientist

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Introduction

      1:34

    • 2.

      About You and Me

      3:27

    • 3.

      Project Introduction

      7:05

    • 4.

      Inheritance Illustration

      3:09

    • 5.

      Inheritance Examples

      3:31

    • 6.

      Super Examples

      2:24

    • 7.

      Subtype Polymorphism

      4:40

    • 8.

      Abstract Illustration

      3:53

    • 9.

      Abstract Examples

      7:09

    • 10.

      Minesweeper Walkthrough 1

      10:57

    • 11.

      Interfaces

      4:20

    • 12.

      Enums

      4:39

    • 13.

      Switch

      3:47

    • 14.

      Minesweeper Walkthrough 2

      9:14

    • 15.

      Exceptions

      2:57

    • 16.

      HashMap

      3:14

    • 17.

      Map Addendum

      1:48

    • 18.

      HashSet

      3:22

    • 19.

      Minesweeper Walkthrough 3

      7:11

    • 20.

      Minesweeper Walkthrough 4

      5:19

    • 21.

      Module 2 Conclusion

      1:15

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

93

Students

--

Projects

About This Class

This course is taught by guest teacher Derek Wan (link to Skillshare profile page)

[The topics discussed build upon those presented in my other course https://skl.sh/445M6ks. Although not a strict prerequisite, I recommend you visit my earlier course if you find yourself getting lost in these videos]

This class covers foundational Java concepts and teaches you everything you need to know to build a Minesweeper game capable of generating more than 17 trillion game configurations. These course will equip you with the requisite skills to tackle large coding projects and scale your programs with increasing complexity.

What You'll Learn

  • Inheritance
  • Super
  • Polymorphism
  • Abstract Classes
  • Interfaces
  • Enums
  • Switch
  • Exceptions
  • HashMaps
  • HashSets
  • Replit

No specialized hardware or setup is required to learn Java with me! All code will be run through a sandboxed environment in your browser that has all dependencies already installed and configured for you. You can focus all your energy on just Java, instead of haggling with your computer's quirks. All you need for this course is Internet, your device, and some free time.

Slides can be found here: https://drive.google.com/drive/folders/1ZmmSP7P82_LJZ9OXhg5kWbYei2e5UIPu?usp=sharing

Meet Your Teacher

Teacher Profile Image

Alvin Wan

Research Scientist

Top Teacher

Hi, I'm Alvin. I was formerly a computer science lecturer at UC Berkeley, where I served on various course staffs for 5 years. I'm now a research scientist at a large tech company, working on cutting edge AI. I've got courses to get you started -- not just to teach the basics, but also to get you excited to learn more. For more, see my Guide to Coding or YouTube.

Welcoming Guest Teacher Derek! I was formerly an instructor for the largest computer science course at UC Berkeley, where I taught for several years and won the Distinguished GSI (graduate student instructor) award. I am now a software engineer working on experimentation platforms at a large tech company. 4.45 / 5.00 average rating (943 reviews) at UC Berkeley. For more, see my Skillshare or Webs... See full profile

Level: Intermediate

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Introduction: Hello there. Welcome to my course on Java. Now if you click on this course, you probably have at least a vague idea of what Java is and that is somehow important to your career and your education. Well, you're not wrong. Let me show you how Java is one of the most popular programming languages out there, used by pretty much every single tech company, pretty much any tech company's careers page is going to list Java as one of the skills. Knowing how to program at all is the skill that puts you on the fast track for a very generous salary. The reason is that Java is performant, feature rich, and relatively easy to pick up compared to some other languages such as C. That also means that you can pick up programming without going through a week's long course. The essentials of Java can be distilled into just a few hours, which is what I've done in this course. You'll use the lessons in this course to build your very own interactive game that you can then share with your friends or put on your resume. One thing that recruiters look for are personal verifiable projects, and this one fits the bill quite nicely. You can choose to do the entire project on your own if you want to challenge. Alternatively, I've also included four walk through videos. Help you out just in case you get lost. I've also set up all code samples in an online sandbox environment. Now, what does that mean? It means that there's no need for complex computers. No arcane set up instructions. All you need to do is visit the links I provide and click the green Run button. You can spend all your energy focusing on the actual coding instead of wasting time setting up a coding environment. I hope you're excited to learn about Java. I spend a lot of time putting this course together and I hope that it shows. I'll see you in the next video. 2. About You and Me: Hello there. In this video, we're going to talk briefly about the intended audience for this course, as well as why you should choose this course out of all the available courses that you probably see out there. So firstly, why should you trust me? You don't even know me well. I work for one of the largest tech companies in the world that is currently based out of Cupertino, California. I'm not really allowed to say whom I work for. But suffice it to say that advertent code that has impacted the user experiences of millions of people out there, maybe even yours. I have a lot of experience writing code that matters. Before working in the tech industry, I actually taught undergraduate computer science at the University of California, Berkeley for four years. The course I taught C 61 was named one of the top five courses in the United States by Bloomberg and regularly saw more than 2000 students each semester. I also recorded Youtube video walk throughs for that course under the channel CS 61, a departmental. As of August 2023, that channel has received more than 963,000 views. Finally, in 2020, I was named among the top 13 instructors in the university's engineering department. Out of several hundred, I have a lot of experience teaching and managing large classes, especially those with a significant online component such as this one. Now why should he choose this class? Well, I alluded to this in a previous video, but one significant advantage of this course is that all the code is public and executable. Now, you may not understand what that means or why it's significant, and that's totally reasonable. Basically, one problem that often occurs in programming courses is that even if you take the instructor's code exactly as it is and put it in your computer, you might not get the same output or maybe the code doesn't even run. The reason is that computers are very complex machines. Often your computer might not be configured exactly the same way as the instructor's computer is configured. In this course, all the code has been moved to an online environment, including the project code. All the coding set up has been abstracted away for you and taken care of so you can focus all of your energy on programming instead of setting up your computer. If you want to follow along interactively in this course, I recommend you set up an account at Repl. I'll drop a link in the course description as well as into resources. Next, I want to talk briefly about the intended audience for discourse. Now don't be alarmed by that statement. Even if you have zero experience in coding, you should still be able to get a lot out of this class. That being said, if you really want to cover all your bases and make sure you understand all of Java syntax from the bottom up, I recommend you take a look at my other course, Java for Beginners Code in 1 hour. That class will teach you some nitty gritty details about programming. However, you don't need to know everything from that class to understand things in this class. What I recommend you do is watch a couple of videos from this class and see if you understand the significance of what I'm saying. If it turns out that you don't understand anything, I recommend you take a break. Check out a couple of videos from the course that I filmed earlier and come back to this class when you're ready. And that's it for this video. The next time you see me, we're going to be jumping into some actual content. 3. Project Introduction: Welcome friends. In this video we're going to talk about the project that you're going to be implementing throughout this course. The project we're going to be implementing is called Minesweeper. Feel free to look it up on Google since it's a pretty popular game and not exclusive to this class. Even if you're already familiar with the game, I would still recommend you watch this video so that you understand our specific implementation. The code in the project you'll be given has been partially completed, but is missing some important pieces. Your objective will be to fix these critical components to make the game work as it does in this video. We'll walk through those components at later points in the course together so you don't get lost. At the end of the project, you should be able to play the game interactively and invite your friends and family to play it as well. Now let's see how this game works. Let's go ahead and click Run our game of Mind. Sweeper begins with a ten by ten board of untapped cells. All these cells, marked X are cells that have not yet been revealed. These cells, lettered A through J on the edges of the board, assist you in identifying the coordinates of a cell. Our coordinates are going to have the form row column. For example, this cell right here is going to have coordinates because it's in A. In column B, all cells are either number cells, empty cells, or mine cells, but their state is currently hidden by the X. If you tap on a cell that is a mine cell, you lose the game. The objective of the game is to find all non mine cells. Let's see what happens when we tap on a cell. We can do tap B, okay? B was revealed to be an empty cell, which we can see because, well, it's empty. An empty cell is one that has zero mines immediately adjacent to it. That means that cell A, cell B, A cell AC, cell BC, and cell BB all were not mines. That means that all of them were safe to tap. Notice that after we taped cell B, a bunch of other cells were also revealed as well. All of these right here, all these empty cells as well as these number cells right here. We do this because like I just said, an empty cell means that all adjacent cells to that empty cell are safe to tap. We just tap them for you to save time. If we find an additional empty cell next to the original empty cell that we taped, we additionally tap all safe cells around that cell as well. And we continue this process until we run out of safe cells to tap. Let's take a look at this cell for example. This cell was revealed to be a number cell. The number two means that there are exactly two mine cells immediately adjacent to it. That means that these cells are all potentially mine cells. This one is also potentially a mine cell. How do we figure out which one is safe or not? This is the crux of the mine sweeper game. We need to combine information from other cells in order to deduce information for this cell. Here's one way we can deduce which cell is a mine cell. Let's take a look at this cell right here. This cell has also been revealed to be a one, but since these cells around it have already been revealed to be empty cells, this has been revealed to be a number cell, and this has been revealed to be a number cell. There is only one cell left that is adjacent to this one. Therefore, this unrevealed cell must be the mine cell. Since we don't want to tap on a mine, we're going to flag the cell as a dangerous cell so that we know not to tap on it. We can see that this X right here is in row and column H. We can do flag F, H. This triangle symbol will indicate to us that the cell is flagged and we know not to tap on it. Now, since we know that this cell is a mine cell, we know that this cell is going to be safe. Why? Pause the video and I'll reveal the answer in 321. The reason is that this number cell right here is a one. We already deduced that this was a dangerous cell because of this number one over here. Therefore, because we have already found the one cell that is adjacent to this number cell that is a mine, we know that every other cell around this number one is going to be safe to tap. Let's go ahead and test our hypothesis. Let's go ahead and tap I. Indeed, we see that I was revealed to be a number cell, which is three that was safe to tap. Although there are many mines still in this area, in the vast majority of cases, you'll be able to continue this process of inference for the entire board and eventually identify where all the mines are. If you think you made a mistake, you can also unflag the cell like so. Now, H has been reset to an unrevealed cell for demo purposes. Let's see what happens if you tap on this mine cell. These asterisks represent minds in our board and we can see that we now have a game over. Let's restart the game by clicking the Run button. Now I'm going to speed through this next board really quickly so you can see the end result. Feel free to watch this video at very slow speeds if you want to follow along and see if you can determine why I made decisions to flag or tap certain cells. Finally, we can see that we have tapped all non mine cells. We have won the game in total. Each game should have ten mine cells. Okay, And that's it for this video. I hope this gets you excited about doing the project. I spend a lot of time putting this together for you and I hope you learned a lot about Java by doing it. I'll see you in the next video. 4. Inheritance Illustration: Welcome friends. In this video, we're going to talk about inheritance. To make this lesson a little less dry, we're going to talk about ice cream. This is ice cream. Now imagine that you have a friend who has never heard of ice cream and ask you to describe it to him. Each unit of ice cream comes with a number of common traits. For now, we'll simplify and it should be pretty safe to say that every ice cream unit has cream. A temperature of about 0 Celsius and a cone to hold the cream. Now imagine that you finished describing ice cream to your imaginary friend. But now he's curious about different types of ice cream like strawberry ice cream and blueberry ice cream. You would probably describe it in much in the same way as you describe the original ice cream over here. These new flavors also have a cone and a temperature of about 0 Celsius. The only difference is that the strawberry ice cream has strawberry flavored cream, and the blueberry ice cream has blueberry flavored cream. This is all fine and dandy for this particular example. If we only have three attributes to describe ice cream, it doesn't hurt to repeat ourselves for each, but you can imagine that we might want to add even more traits to describe this ice cream. Maybe we want to also add a cone flavor attribute, or a cone texture. Or maybe the weight of the ice cream, or the volume of the ice cream. You can get infinitely more descriptive of ice cream. And every time your friend asked you to describe a new flavored ice cream, you would need to redefine every single one of those traits over and over again. It would be really nice if we had a way to reduce the amount of work we have to do to describe new ice cream flavors. This is where inheritance comes in naturally. At some point, you'd get tired of describing the same characteristics for ice cream. Instead of reiterating that ice cream has a cone and a temperature of 0 Celsius, you tell your friend, well, blueberry ice cream is just like regular ice cream, except that the cream is a different flavor, everything else is the same. Inheritance is a paradigm in Java that allows us to do this. Inheritance means that behaviors and attributes of a base model get copied to a newer, updated model. We still have the ability to overwrite select attributes such as the cream flavor in this case. So this is pretty awesome now, instead of repeating ourselves and redefining every single ice cream attribute when we define a new ice cream flavor, all we have to do is override one attribute, the cream flavor attribute, and inherit the rest of the shared attributes from the base ice cream model, like the temperature and the cone. This sounds really simple, but it's a very important tenet of Java programming. Reducing repetitive code is so valuable to recap. Inheritance is how we maximize code, reuse and simplify your code. I'll show you some concrete examples of what this looks like in code in the next video. 5. Inheritance Examples: Hello friends. In this video, we're going to discuss some concrete inheritance examples. First, imagine that we have a class called dog and say that it has a static field called sound and a get method called get Sound that retrieves the sound in case you forgot or aren't familiar with the syntax. I recommend you pause the video now and watch the video titled Objects part Two in my other class, Java, for beginners in 1 hour. Now we further have another class called Brown Dog, which extends the dog class. This extends syntax is new. This is how we specify inheritance patterns in Java. In this case, we would say that the brown dog inherits from dog. Don't worry about the implications of this for now. Just recognize Dysntex. Now let's say the brown dog has one method called get color, which simply returns the word brown. Now let's put this all together. We have the dog class from earlier and we have the brown dog class that extends dog in our main class. Let's create an instance of the dog class and one instance of the brown dog class. Like so, if we print out dog get sound and brown dog getcolor, the output is pretty predictable. Dog do get sound. We'll just print out bark and brown dog getcolor, we'll print out brown word. Magic happens is when we do brown doggetund. Based on what we know so far of Java programming, this looks like it would fail, right? Since the brown dog class does not have a get sound method, that seems like a reasonable guess. It turns out that if you run this, this last statement will actually print out bark. The reason is that we have inheritance when one class extends another, Java will first look in the extended class and see if it has a method or field defined if it doesn't. Java then checks its parent class. In this case, we first check brown dog for the get sound method. It doesn't have that method, so we check the parent class dog dog has the get sound method. Use that method which returns bark. I want to emphasize here that Java will use the most specific method it finds first. Remember that Java looks in brown dog first for get sound before it looks in dog. This means that if brown dog had a get sound method that returns something different from the dogs get sound method and we call brown dog dog get sound. Java would have used the get sound method defined in brown dog instead. That was a mouthful. If you're watching on 1.5 x or two x speed and didn't catch that, I recommend you rewind 30 seconds and listen to that sentence again. On one X speed, that's the end of our discussion on inheritance. To recap, we use the extends keyword to tell Java we would like to create an inheritance relationship. Once the inheritance relationship has been established, Java uses dynamic method resolution to figure out which method to use. It first looks in the actual class we're calling the method from. And only if the method is absent does Java look in the parent class. Here's the link to the repel code, using this lesson for you to tinker with. I'll see you in the next video. 6. Super Examples: Welcome friends. In this video we're going to talk about super recall from the previous lesson that we had a dog class that had a get sound method. We also had a brown dog class that inherited from brown dog had a get color method. When we called brown dog get sound, Brown dog re used the get sound method from dog via inheritance. Also, recall the order in which Java resolves method names. If we called brown do get sound. Java would first look in the brown dog class for get sound. Java would only look in the dog class if brown dog did not have get Sound. If brown dog did have a get sound method defined and we called brown dog get sound, brown dogs get sound would override the get sound method of the dog class. Meaning that we would execute the logic contained within brown dog instead of dog. We can either re, use or override methods of the parent class. But what if we want to override and reuse the logic of the parent class? Let's see how it works. First, let's say we have our dog class again, get sound method that returns bark. Now say we have our brown dog class which inherits from dog and also has a get sound method. This method has a new keyword that we haven't seen before. Super. Super is how we reference the parent class of the current class. In this case, super is really an alias for the dog class. This means that super do get sound is analogous to saying dog get sound. Which means that super get sound will return bark. The result of this entire brown dogtetsund method will be bark brown bark. That's pretty much it. We've learned about our new keyword super, which is used to refer to a parent class when we're writing code inside the child class. This keyword also allows us to create hybrid override methods. That is to say we're able to re, use code from the parent class and also add our own custom logic. Here's the link to the repel code in this lesson for you to tinker with. I'll see you in the next video. 7. Subtype Polymorphism: In this video, we're going to talk about subtype polymorphism. Before we jump in, please don't be intimidated by these very fancy sounding words. The concept is actually not that much more complicated than anything we've seen so far, but the designers of Java couldn't come up with a simpler name. Once again, let's begin our illustration with a dog class that has a get sound method that returns bark. We'll also have a brown dog class that inherits from dog, and this brown dog method returns brown bark. Putting it all together, we have our two classes. We have a third get sound method located in our main class. This third method takes in a dog instance and simply calls that dogs get sound method. If we instantiate an instance of the base dog class and then pass that base dog class into this method as you would expect, we would get bark as output. But now let's say we instantiate a brown dog instance and pass that object into this get sound method. This is strange. The get sound method here in the bottom right only accepts arguments of type dog, yet the type of object we're passing in is brown dog. Based on what we know of Java, this seems like it should error, right? It turns out this will not error. This line will actually print out brown bark. This is due to something in Java called dynamic method Resolution is an example of subtype polymorphism. Subtype polymorphism basically means that a subtype of a parent type can be treated as a parent type. Intuitively, this should make sense. A brown dog should have all the properties of a dog. A brown Chihuahua should have all the properties of a brown dog. A more specific thing should at least have all the behaviors and traits of a less specific related thing. Now back to this example, the reason we can pass in a brown dog into this method that accepts dog types is that Java assumes specific types of dogs, will be able to call all methods of the base dog class when the program is actually run. Java will then resolve instance methods using the dynamic type of an object. Aka the type that an object actually is a brown dog and not the static type that we declare it to be in this method dog. I'll say that once again because it's a pretty important concept. The static type of an object is what we explicitly declare the object as. In this method, it's brown dog. In this method, the static type changes to dog. The dynamic type of an object is what the object actually is and it never changes. In this case, the dynamic type is brown dog. To resolve an instance method, we use the dynamic type of the object. You may be wondering why we do this at all. Why on earth would we confuse ourselves? Why not just call it a brown dog when we instantiate it and just keep it as a brown dog forever? The reason that we might want to re, use this method for many types of dogs. Imagine that on top of the brown dog class, we also had white dog, blue dog, and yellow dog classes, all of which inherit from dog and all of which have get sound methods. It would be really annoying if we had to define one method that takes in an object of type brown dog and another method that takes in an object of type white dog, and yellow dog, and blue dog. When all these methods do the exact same thing, instead of repeating ourselves, we just create one method that accepts the type of the base model dog. By having a more general input type, we can maximize our code reuse and just have one method that takes care of all the more specific cases. That's it for this video. To recap, we talked about subtype polymorphism. It's a Java paradigm that allows us to treat specific instances of an object as a less specific base object. We also talked about static versus dynamic types, which dictate the way we resolve instance methods. When referring to an instance method, we use the method defined in the dynamic type of an object instead of the static type. Here's the link to the repel code in this lesson for you to tinker with. I'll see you in the next video. 8. Abstract Illustration: Welcome friends. In this video, we're going to walk through a visual overview of abstract classes. In this illustration, we're actually going to return back to our ice cream examples from the inheritance illustration lesson. Recall that we have an ice cream class and we also have strawberry ice cream and blueberry ice cream classes that inherit from ice cream. Now if you think to yourself, what do these three classes look like in real life? You can probably come up with some idea of what strawberry and blueberry ice cream look like. More or less, they look something like this. These classes reflect reality and they are anchored to concrete examples. But what about the ice cream class? What does non flavored ice cream look like? You might be thinking of vanilla ice cream, but even vanilla is a flavor. Vanilla ice cream would also be a subclass that inherits from the ice cream class. But ice cream itself, with no flavor, there's no such thing, at least not in your local grocery store. In Java, we would actually model this ice cream class as an abstract. An abstract class is something that cannot be instantiated directly because an instance of that object doesn't make any sense. Just like ice cream with no flavor makes no sense. Instead, we can only instantiate subclasses of an abstract class, such as strawberry or blueberry ice cream. Once again, we're adding complexity to your job and knowledge. It seems like all we're doing is limiting your functionality. And you may be asking yourself, why. Why would we create an abstract class that can't even be instantiated? Aren't we deliberately limiting and slowing ourselves if we force ourselves to create a subclass before using it for anything? The answer is that even though an object like flavorless ice cream does not have any meaning in itself, it still holds value in two ways. The first is that inheritance patterns still hold true here. Just like with regular inheritance, we can define a field value on the base object and have subclasses inherit for that field. Even though flavorless ice cream does not exist, we can still declare its temperature to be 0 Celsius and have subclasses all inherit that temperature. This should make sense since we don't need to have a concrete ice cream class to determine its temperature. We can just say, in general, ice cream should be 0 Celsius and define that in the base abstract class. The second way abstract classes are still valuable is that they can specify a contract that subclasses must fulfill. For example, we can declare that all ice cream should have a method defined that returns the color of the ice cream in the base ice cream model. This method won't be defined because there's no such thing as a color for all ice cream instances. However, the strawberry ice cream can have a get color method that returns pink. And the blueberry ice cream can have a get color method that returns blue. If we had an additional ice cream class that did not provide a get color implementation, Java would fail to compile. That's a good thing because we don't want our code to compile unless we're absolutely sure that all concrete ice cream instances have color defined for them. That may sound a little confusing, but don't worry. I'll show you examples of how that works in the next video. That's it for this lesson. We talked about abstract classes and how they're almost objects in that they cannot be directly instantiated, but can provide a contract or template for subclasses. We'll see concrete examples of this soon. I'll see you in the next video. 9. Abstract Examples: Hello friends. In this video we're going to walk through some examples of abstract class usage. And we're actually going to shake things up today. Instead of walking through slides and diagrams of code, we're going to be hands on coding. Of course, I highly recommend you follow along in your Repel It account if you can. If not, be sure to visit the Repel link. After this lesson is over, fork it and tinker with the code. The first thing we're going to do is visit Repl. It hit Create repel button, choose the Java template and name your Repel abstract classes. Now that it's created, the first thing we're going to do is create an abstract dog class. We're going to do so by clicking the new file button over here and call it Java. The first thing we're going to do is create an abstract dog class. The class declaration looks almost like a regular class definition, except we're going to add the abstract modifier. The abstract modifier just means that we're going to have at least one abstract method within this class. Let's first define an attribute called numb legs and set it to four. Note that this is not an abstract field. There's no such thing. Only methods can be abstract in Java. Intuitively, it should make sense why we defined as attribute in an abstract class. Remember, we don't need a specific type of dog to tell us how many legs a dog has. Dogs in general have four legs. It's safe to define it here. Now let's define a regular non abstract method called Get Sound, which is going to return bark. This is going to behave exactly like any other non abstract method in a regular class. No surprises here. Now finally, let's define an abstract method. We're going to call it get color and not define it. Again, this should make sense. It makes sense to define, get sound for dogs in general, because dogs generally make the same sound. But what is the color of a dog? You can't answer that without having a concrete instance of a dog in front of you. Therefore, it's an abstract method. Now let's create a new class, regular class, not an abstract class. And have it extend our abstract dog class. We're going to call this guy a brown dog. And it's going to extend our dog class. Public class Brown. Do note that the syntax for extending an abstract class is the same as it is for extending a non abstract class. Here we're going to provide a concrete implementation of the abstract get color method. The color of a brown dog should be brown. We'll just have it returned brown. Let's additionally add an override annotation to this method. The at override annotation is 100% optional, but it's good practice to include it. The reason is that Java will then check at compile time whether the method you've annotated is actually overwriting a method. Examples in which this would be useful would be when you may be misspelled, the method or the method doesn't actually exist in the parent class. It's especially important when overwriting abstract methods because abstract methods don't have any logic defined in the abstract class. We want to be absolutely certain we've provided a concrete implementation for the method. Now let's put it all together in our main class. So the first thing we're going to test is instantiating a dog like so. Let's see what happens. Look, we got an error. It says that dog is abstract and cannot be instantiated. This makes sense, because as we've said before, abstract classes cannot be instantiated directly. We can only instantiate their subclasses. Now let's try instantiating a brown dog instead, which inherits from this time the code compiled without any issue. Again, this shouldn't make sense. Brown dog is a subclass of an abstract class. Now let's see what happens when we call these methods. First, let's rename this guy Brown Dog because it is a brown dog. Let's first take a look at brown dog dot numb legs. If you recall, brown dog dot numb legs should be this guy right here inside the dog class. Since fields cannot be abstract, numb legs is going to act exactly the same way as attributes defined in regular classes are going to work. When we call brown dog dot numb legs, Java will first look in the brown dog class to see whether a numb legs attribute exists. It does not. It then looks in the parent class, then it looks in dog and it sees that numb legs does exist. This first line should print out four. Let's test it. Indeed, we get four back. Next, let's try out some method calls. Let's see what happens when we call brown dog dot get color and brown dog dot get. Sound As expected, brown dog dog get color returns brown. That's the method that was empty in the original dog class but was overridden in brown dog, brown dog, dog get. Sound Was the method we defined in the parent dog class and that brown dog did not define explicitly. Quick recap. Brown dog has get color, dog has get. Sound. We can see that regular methods act exactly the same way as they used to. If it doesn't exist in brown dog. We will then call the method defined in the parent class. Do however, get color also acts similarly to regular classes. We call the method that is defined in the subclass. In this case, if we had forgotten to override the get color method of the abstract class that brown dog inherits from Java, would have thrown an error. Let's actually see what happens if we did that. Let's say we misspelled get color like so and we hit run. You see now we have an error. Brown dog is not abstract and does not override abstract method, get color in dog. This is one of the benefits of using the abstract classes. We see our errors upfront before we even run the code. That's it for this video. Today we took a look at abstract classes and how to implement them, as well as some of the errors that might arise when you misuse abstract classes. Here is the link to the repel code. I'd like for you to fork it and tinker around with the code. 10. Minesweeper Walkthrough 1: Welcome friends. In this video we're going to walk through the first part of this project using what we've learned in the last few lessons. If you want to follow along interactively, you're going to need to make a account and verify your E mail. The link for that should be in the class description and was in the intro video for this course. If you don't want to make another account, that's totally fine too though Of course I strongly recommend you do make an account. The first thing you'll want to do after making an account is visit bit dot lee, minesweeper skeleton like so. The link is also in the project description. Once you're at this page, click the fork button and it should take it to a copy of the code in your account. Let's take a look at the structure of this project. Have the files, main board cell, empty cell, mind cell, and number cell. Much of the code in Maine and Board has been implemented for you and we'll tackle some missing pieces later there in later walk throughs. For this video, we're going to focus on the cell classes. As you might have guessed already, a cell class represents one of the squares in the Minesweeper game. Let's take a closer look. The cell class is an abstract class. It declares a contract for other classes to follow, and also provides some default methods. Every concrete cell class must implement a two string method, which is its string representation in the board, and a tap method which defines what happens when the cell is tapped. We also have some flags that have default values of false and we have some methods that should be shared among all implementations has been tapped. Flag, un flag numb neighbor minds and increment numb neighbors. I want you to think about the following. Why are these methods abstract and why are these concrete methods? Pause the video and I'll answer in 321. Well, if I ask you what a cell in general should look like and minesweeper, could you answer that? You can't. A cell is blank. If it's an empty cell, it has a number in it. If it's a number cell and it has an asterisk, if it's a mind cell, you need a concrete implementation of a cell to determine what its string representation should look like. Similarly, the behavior for tap also depends on what kind of cell you're talking about. For example, if you tap on a mind cell, the game is over. But if you tap on an empty cell, we just help you tap all the neighboring safe cells. On the other hand, if I ask you whether a cell regardless of its type, has been tapped, can you answer that question? Yes, you can. Regardless of the type of cell it is, you can answer whether a cell has been tapped. Similarly, the behaviors of flag and unflag on a cell are the same across all cell classes, regardless of their type. Okay, let's begin addressing these two comments into cell class. Firstly, we see that there's a bullion method has been tapped. When you have a method that returns the state of an object, that's a hint that you should be looking at the fields of the object. In this case, we have tapped and is flagged. What do you think this method should return, given that information? Well, we should return tapped since its name suggests that it's going to store information about the cells tap state. Next, let's look at flag. It returns void. We don't have to worry about a return value. Instead, this void method to suggests that its sole purpose is to modify the state of an object. Given that we want to modify the state of the object, what variable do you think we should be modifying? Well, we should be modifying the flagged field, setting its value to true. Similarly, the unflagged method is going to set the is flagged field to false. That's all we have to do for the cell class. Let's move on to the empty cell. First we see that we have to override all abstract methods. Let's copy over the abstract methods and begin implementing them. We see here that there's a comment to use this special character for flagged cells. Let's start by implementing that logic. How do you tell whether a cell has been tapped? Well, let's take a look. We have this is flagged variable that stores information about the cell's flag state. Let's use that. If this cell has been flagged, we return this special character right here. Otherwise, if this cell has been tapped, then we return an empty space. Because it's an empty cell, if you tap on an empty cell, it should reveal an empty space. Finally, if this cell has neither been flagged nor tapped, what should it look like? Well, recall from our first video talking about this project, we said that all cells begin as an X, which simply which simply represents that, that cell state has not yet been revealed. Next, let's take a look at, as the name suggests, what do you think this method is going to do? Positive video, and I'll answer in 321. The top method is going to set the tapped field to true so that we can remember the state of this cell. After we set the flag to true, we notice that this method needs to return a bullion. Well, it's actually pretty hard to tell here whether we need to return true or false. I'll give you a hint. If you want to challenge, try visiting board Java and look at its tap method. See if you can deduce what the intended return value of the cell classes tap method should be on a successful tap. And pause the video if you want to think about it. If not, I'll just tell you the answer. The answer is in 321, we're going to return true, since a true return value indicates that the cell was safe to tap on. Which we can deduce from looking at Board dot Java. We see in board Java that if tap result is true, then we continue looking for neighboring empty cells to tap. In other words, a tap result of true means that the cell was safe to tap on. Otherwise, we wouldn't look for neighboring empty cells to tap. Now let's move on to the number cell and repeat the exercise. This time, we'll want to override the abstract methods and also numb neighbor minds. The tap method is going to be pretty much the same as the empty cell. A number cell is also safe to tap on. We turn true and flip the tap bullion to true. The two string method will also look very similar to the previous classes two string method except that if it's been tapped, we should return the number of mines that are neighbors to this cell. Conveniently, we see that there is a field called numb neighbor minds here. Don't worry too much about how we use this method increment Numb neighbors just know that we've already implemented that for you. Basically, we just call this method at the appropriate time when planting mines on the board. Numb neighbor Minds gives us the correct value. Since we want this method to return a string, Numb Neighbor Minds as an integer, we need to convert this integer to a string. But how do we do that? Well, let's use a fantastic resource called Google. Let's search Java how to convert an integer to a string. Let's go ahead and click on the first result. Let's scroll down a little bit, and we immediately see that there's an example right here, I equals ten. And we convert that ten to a string using string value. Let's go ahead and use that stream value of this number neighbor minds. This way this return value matches the return value of the two string method. Finally, let's also override numb neighbor minds, which we didn't have to do for the previous class. Numb neighbor minds, as the name suggests, returns the number of mines that are neighboring cell. We have a field that returns exactly that. Let's go ahead and return num neighbor minds. Now we've completed the number cell. Let's take a look at the final class we're implementing in this video. Mind cell is actually going to have a lot of similarities with the previous cells that we just implemented. Let's go ahead and copy these abstract methods. The mind cells tap method is going to be different from the previous classes. We're still going to be setting the tapped field to true, but instead of returning true, we're going to return false. Since true means that it was a safe tap, a mine is not a safe cell to tap on. The two string method is going to look similar to other classes, except that if it's been tapped, we should return an asterisk because that's its representation in the board. Actually, that's all we need to do now. We're done with all our cell classes. We actually won't be able to verify whether we've done it correctly until the very end of all these walk throughs. As a challenge, if you want to see whether you truly understood what was going on in this video, I recommend you re fork the original code and see if you can fill in all the to do comments in the skeleton without my help. Otherwise, I'll see you in the next video. 11. Interfaces: Welcome friends. In this video we're going to talk about interfaces. But wait, we haven't even talked about interfaces before. What are they? Interfaces are classes that specify a contract and cannot be instantiated directly. Now I know what you're thinking. Doesn't that sound exactly like the definition we gave for abstract classes? You would actually be correct. Interfaces are very similar to abstract classes and that their fundamental functionality is the same. Now you're probably asking yourself why though. Why do we have such entities in Java that pretty much do the same thing? It's almost as if the Java language designers are trying to trick us. Well, it turns out that there are some differences between abstract classes and interfaces. Let's go over them. The biggest difference is that abstract classes only support single inheritance, whereas interfaces support multiple implementations. In Java, a class can only inherit from at most, one class that includes abstract classes. Brown dog can inherit from dog, but we wouldn't be able to have brown dog inherit from something else, like say brown animal for example. Interfaces get around this problem. Interfaces aren't inherited like classes are. Instead they're implemented and a class can implement multiple interfaces. In our brown dog example, we could have brown dog implement a dog interface and implement a brown animal interface. And then brown dog would have two contracts to fulfill the dog interface and the brown animal interface. Based on this information, abstract classes are useful when we have straightforward object hierarchies. Interfaces are useful when we have an object whose contracts should mix and match methods from multiple hierarchies. Say we have a brown dog that inherits from a dog class, and the dog class inherits from a mammal class. This is a linear hierarchy, and it makes sense to implement our method contracts as abstract classes. On the other hand, say we have a brown dog, and we'd like it to fulfill the object template of a colored animal. And we'd also like it to fulfill the template of an animal with legs. Colored animals and animals with legs are two separate object hierarchies. Of course, there are many animals that should fulfill both contracts, but there are also animals that only fulfill one or the other. As you can see, choosing interfaces or abstract classes boils down to how you decide to design your class hierarchy. Now let's see how we actually use interfaces in practice. First, we define an interface called animal with legs and declare a method that must be implemented called get non legs. We'll also define an interface called colored animal that declares a method that must be implemented called get color. Now let's create a brown dog class. The first thing I want you to notice is that we're using the implements keyword here instead of extends. The next thing I want you to see is that here we've specified multiple interfaces that must be implemented by brown dog. If you try to do this with the extends keyword, Java will throw an error. This is a feature unique to interfaces, being able to implement multiple things. Apart from the class definition though, the rest of the class looks pretty similar to what we've seen. Since we must implement all methods declared in the interfaces we are implementing, we define both get color and get numb legs. We also add the override annotation to be explicit that these implementations are intended to override the declarations in the interfaces. That's pretty much it. In this video, we talked about interfaces, which are a new type of class that declares a contract that must be fulfilled by classes that implement them. Interfaces allow you to create multiple inheritance patterns that you can't do with regular abstract classes. Here's the link to the repo code used in this video. Please visit the link fork the repo and tinker with the code. I'll see you in the next video. 12. Enums: Hello friends. In this video we're going to talk about enums. Let's start off today's illustration by defining a class called dog one, which has a get type method that just returns brown dog. Let's say we also have a class called dog two, which also has a get type method, but this one returns white dog. Finally, we have dog three. Dog three get type returns yellow dog. Yes, that's a yellow with an H instead of a W. Now let's put it all together. We have our three dog definitions on the left and then on the right we instantiate three dogs, one instance for each class. Let's say we want to run some simple checks. We just want to call, get type on each of these dogs. Then check the output. If the output matches some expected value. We'll print something for our first dog. We want to check whether dog one's type is brown dog. For the second dog we'll want to check whether it's a white dog. Finally, for the third dog, we want to check whether it's a yellow dog. Well, since we accidentally misspelled yellow dog in our dog three get type definition, this condition will be false and we do not print out that dog three is yellow. That's not a huge problem in a simple program like this, but I can give you a higher stake situation. Imagine that your website search traffic from multiple countries and you want to change the language of the website based on the country the user is from. Let's say that for someone in Japan, you'd like to set the language of the website to Japanese. Similar to this logic, you'd have a bunch of if statements. Choosing the language of the website based on user dot get country. Now let's say that we misspell Japan somewhere in our code. Now this Japanese user is not going to get the right language and you just missed out on potential sales. It would be great if we could bulletproof our code against such typos, and we have a tool that does exactly that. Let's create an enum class called dog type. Usually when we create a class, we write public class name. But here, note that we're saying public enum, dog type inside this enum. We then define three values, yellow, brown, and white. Note that these three values are not in quotes, they are not strings. It might still not be clear how this helps. Let's take a look at how we use these. Let's define a new method for each of our dog classes called get enum type. We can then see for dog one, this method returns type brown and we return type white and doc type yellow. For the other two dogs, this might look basically like what we had before, but there's a very important distinction here. Enum acts similarly to a variable or a field in Java, in that Java will perform a look up when you reference it, when I say doc type brown, Java will actually look up the dog type enum class and see if there is a value inside of it called brown. If there is no such value, Java will fail to compile. That's one of the main benefits of enums. Enums allow Java to perform a compile time check that all the reference values actually exist. This reduces the chance that you'll misspell your reference values. Enums also mean that there's one source of truth for constant values instead of before when we manually wrote out each string to compare values. We can now do something like this, where we have a stronger guarantee that the constant value we're referring to actually exists. If we accidentally misspelled doctype yellow here, where we put Y E L L O H. Java would then fail to compile because it would check inside the doc type enum. Realize that there is no such thing as doc type Y L L O H. That's it for this video. We talked about enums, which allow us to define constant values for our applications. These constant values are helpful because if we ever have a misspelled reference to an enum, Java will throw a compilation error and we'll know exactly where to fix the issue. Enums also provide one source of truth for our constants. You define your constants in one place, and you always refer to those constants elsewhere in your program instead of rewriting the value over and over again. Here's the link to the Repl code in this video. I'll see you in the next one. 13. Switch: Hello friends. In this video we're going to talk about switch. Let's begin our illustration with similar definitions from the last video. We'll have a dog type with three color types and we'll have a brown dog whose get type method returns dog type brown. Now in our main method, let's instantiate a brown dog. We'll say if brown dog's type is white print that the dog is white. If the brown dog's type is yellow, print that the dogs is yellow. If the dog type is brown, print that the dog is brown. Otherwise, print that the dog's color is unknown. Now, there's nothing actually wrong with this code. It works perfectly fine. But note that here we have the same value in every if clause. And not only that, we have the same logical structure in each if clause, comparing the same value to different enum type. Again, nothing's wrong with this from a functional standpoint, but it just looks clunky. It turns out Java has a solution for that. Here's an alternate way of writing the same thing. Before I start talking about this code, I want you to take a look yourself. Can you guess what each new keyword is doing? Pause the video and when you're ready. Let's see how close you were. Firstly, this switch clause at the top is basically just saying that we want to compare this value over and over again. We're going to compare the value inside the switch parentheses to the values that follow these case keywords. This first case clause is pretty much equivalent to if brown dog dot get type is equal to dog type white. The second is equivalent to if brown doggettype is equal to dog type yellow. You can probably guess what the last case clause means. Notice that in these case clauses we don't say dog type white and dog type yellow. We just say white and yellow. The reason is that in switch blocks, Java will deduce the enum type, the value in the switch parentheses, and expects you to just write the enum values without the enum class name in front. That's a fairly minor point, but just keep it in mind if you run into any errors. Finally, this default case is roughly equivalent to else, but not exactly. It actually means always execute this case if the program reaches this line. However, we only reach this case in the Ls case because of these break statements. But what are they? It turns out that these break statements stop further evaluation within the switch block if the code path ever reaches them. For example, let's say that we did not have the break in the brown clause in the Brown case. If that were the case, then all this code would be executed. We would print out that dog is brown. And then since there is no brake line anymore, Java would continue executing the code in the next case. The next case here is the default case. We'll also print out Unknown dog color. As you can see, if our switch block had a lot more cases in it, it would be a big waste of time if we continue to run the code even after we already found the type of the brown dog. In general, when you're only expecting one case to be matched, it's best practice to set a brake line in each case. That's it for this video. In this lesson, we talked about switch, which basically is just a more concise way of writing repetitive if else logic. Here's the link to the Repl code in this video. I'll see you in the next one. 14. Minesweeper Walkthrough 2: Welcome friends. In this video, we're going to walk through the second part of this project using what we've learned in the last few lessons, specifically enums and switch. This time we're actually going to take a look at the main class. There's a lot going on in this file. Before we begin, please take a moment to read through it. It's okay if there are parts you don't understand. Many of the variable names are pretty descriptive and should at least give you a decent hint as to what it's doing. Now let's go through this together. First we create a board, we print the board, and then we begin an infinite loop here. This scanner input line basically is just telling the console to see what the user entered on the current turn. Recall in our demo we did things like flag row column and tap row column. Whatever you enter into the console will be saved into this string user input here, user input split just means we're going to separate the one string based on the white space. For example, when we have tap space a space B, then we should end up with an array that has three elements in it. The first element will be tap, the second element will be A, and the third element should be B. That's why if the length of the array is not three, we reject the command and start the loop over. You may not be familiar with this continue line. All it does is tell Java to skip the rest of the loop and start at the very top. Again, we're going to go back to the top of this y loop, Check for the next user input. Here we have row equals negative one, followed by an empty loop. Column equals negative one, also followed by an empty loop. We'll come back to this in a later video. It's not super important for now. Just know that row and column are going to be integers that represent the indices of the board that the user would like to perform an action on. Finally, we reached a part of the code that we are interested in. Here we create a bullion called safe cell. We have an empty switch block that follows it. Below we say that if is safe cell is false, then game over. This implies that this switch block should be changing the value of safe cell. Otherwise, is safe cell will just always be true. And it would be redundant to have this F case right here. Think about the last walk through that we did. Can you think of the method that we implemented that returns a bullion value indicating whether a tap was a safe tap or not? The answer is you implemented the tap method. Recall that we had this Tap method that records that the cell has been tapped for number cells and empty cells will return true for mind cells, we return false. And if you explored a code some more, you would have seen that in Board Java we also have a tap method. And what do we do? First, we tap the cell located at index row column and save the result of that tap into this bullion tap result. If it was a safe tap and there are no mines surrounding it, then we tap all neighboring cells around it and return true. Otherwise, if we taped on a mine, we return false. That implies that within this switch block, we should be calling tap row column, save the result of that call into is safe cell. But recall, a switch block is used when we have multiple cases to check what cases should we be checking within this switch case. Once again, pause the video and think about what we discussed was happening earlier in the sloop. I'll reveal the answer in 321. Well, the only time we get a value for is safe cell is when we tap on a cell. But those are not the only actions a user can take. Recall from the project intro video that a user can also flag and unflag a cell if you forgot what those do. Basically, flag will mark a cell as a potential mind but it won't tap the cell. Will remove a flag from the cell also without tapping the cell. Because the user command is going to take the form action row column, we're going to put command zero inside these parentheses right here. Our first case is going to be a tap. If the user input a tap as the command, then we're going to say, then we're going to reassign the value of a safe cell to be the result of tapping on the board at position row column. Don't forget, after we perform whatever action we want to perform within this case, we need to leave a break statement before the next case. If the user command was a flag, which method should recall? Well, here's a good chance to use our code reading skills. Let's see what other methods are in the board class. We have an is solved method right here, but that doesn't really seem likely. Hey, here we have a flag and an unfed method. Those seem to fit our use case, let's use them back in our main class. In the flag case, we're going to call flag column. Since this method returns, we don't really intend to use the return value of this method to do anything else, we just break. Finally, we'll have our last case, which is the flag case here. We'll do flag column, then we'll break as well. We do have one small problem here though. It's totally possible that a user could input some random string as the input command, or the user might have accidentally misspelled tap flag or unflag. But we want to make this code more robust and this is where enums come into play. Let's predefine some possible values that we want to accept from the user. Up here in the action, um, let's go ahead and define unflagg, tap. It doesn't really matter what order you write them in. Now here, let's convert these case values from strings, enum values. This will guard against potential typos. Let's go ahead and change it into a tap. Let's make this into a flag, let's make this into an un flag. But now we have a small problem. Remember that Java will infer the type of the value in these parentheses and check that that type matches the type of these case values. But that isn't the case here. The type of command zero is a string. The type of these case values is an action enum. How do we convert a string into an action enum? Well, this is a fantastic opportunity to flex our Googling skills. Let's go ahead and Google Java how to convert a string, a string, into an enum. Let's go ahead and click on the first result right here. We scroll down. We don't really need to read most of this, but we can see right here in the code block, they're telling you that they have an enum called Pisa status. Um, and it has a value inside of it. Piece status enum. Ready? Let's scroll it down some more. We see that we have this example, Pisa status enum. Except this time we derive the value of the enum, not by saying patatenum, ready, but piece of status, enum value of string, ready. That's a pretty good hint as telling us that the value method of an enum class will convert a string into an enum. Let's go ahead and use that instead of command zero, let's do action value of command zero. Now that's pretty much all we had to do for this walk through. Unfortunately, once again, we won't be able to see the result of what we did until we finished the entire project. But I hope you'll stick around to see the end result. That's all for this video. Thanks for watching and I'll see you in the next one. 15. Exceptions: Hello friends. In this video we're going to talk about exceptions. Let's revisit the example we had in the previous video. Recall that our dog type enum had three types, white, brown, and yellow. If the dog type matched any of these three cases, we would print a statement and then break out of the switch block. The only time we'll hit this default case is if brown dogs type is none of these three colors, but then we only have these three types defined. When would we ever encounter this case? Well, it could be if the type is null or maybe in the future we end up adding an extra dog type. But forget to update this switch block. But generally speaking, we don't actually expect to hit this default case in most use cases. If we do hit this default case with this code, we're actually going to get a silent fail. We'll have an extra line being printed out, Unknown dog color. But the program runs just fine. It doesn't fail to compile and there's no error when we run it. We don't know whether unknown dog color being printed out was expected or not. Instead, what we should do is throw an exception. Here's an example of one of the most common types of exceptions, illegal state exception. Note this in text here. We say throw, which tells Java to throw an error. And then we provide a new instance of the exception with new and passing an error message into the exception. Now if Java ever reaches this line of code, an error will be thrown when you run the program and the program will stop. This is actually a good thing. Let's say you added an extra dog type called Blue, But you forgot to add a case for it. You want the code to stop and tell you that there's an unknown type instead of continuing to run as if nothing happened. It's hard to see with this small program. But imagine you have a much more important application. For example, let's say there's an application that tells you how much money you have in the bank. It's a lot better for the bank to say there was an error loading your account rather than silently failing and telling you that you have negative $50,000 in your account for both the developer and the user of the application. The explicit error is a lot more informative than arbitrary weird output. The added benefit for the developer is that the custom error will actually tell you where something unexpected happened. It also makes debugging a lot easier. That's it for this video. We talked about exceptions which deliberately stop programs with the custom error message. Although at first glance, these may seem like a terrible thing to add to your program. But in fact, they help ensure program stability by providing sanity checks and providing hints to the developer in the event of a bug. Here's the link to the repel code used in this video. I'll see you in the next one. 16. HashMap: Welcome friends. In this video we're going to talk about the hash map. The example today is pretty short and can fit in one file. The first thing I want you to notice is this import at the top of the file. The hash map is a data structure that is included in the Java Util package, which is a built in package. Next, let's take a look at how we declare a Hashmap. As usual, we first declare the type of the variable which is a Hashmap. Then we use these angled brackets to specify the types of the keys and values within this map. The integer in de angled brackets specifies the type of the keys. The string in the brackets specifies the type of the values. A key is basically something we're going to use to look up values. For example, think of the context list in your phone. When you want to look up your friend's phone number, you first look for his or her name. When you click on the name, your phone will then display your friend's phone number. Your friend's name is a key that maps to a phone number which is a value. In this case, we're going to be mapping integers to strings. Also notice that we used capital I integer here instead of lower case t when we declare integer types that are contained within other objects as a key within a map, we use capital I integer, but otherwise capital Integer and lower case T are pretty much interchangeable. Next let's look at how we instantiate a hash map. Notice that we still include the angle brackets, but we don't put anything in them. That's because this syntax tells Java to simply infer the types of the keys and values. From the left side of this assignment, Java will know to create a hash map with integer keys and string values. In the next line, map put one yellow says that we are now mapping one to yellow within the map map dot put to brown means that we map two to brown. When we print map dot get one, we print out yellow. When we print map dot get two, we print out brown. It seems pretty simple and it usually is. One thing that I want to call out here is that these gets and puts happen in constant time. We haven't really talked about what this O of one notation means because it's not really a focus in this class. You don't really need to know in detail what's going on, but I'll give you a brief overview. The Hash and hash map is actually a mechanism in programming that allows the computer to store objects in a way such that it's very easy and fast to retrieve them later. It still takes time to retrieve and store those objects, but the time is pretty much negligible in most use cases. Maps are pretty great for storing data. All right, so that's it for this video. We talked about the hash map, which is a data structure that stores and maps keys to values. It does all this in constant time, meaning that the latency required to write to and read from the map doesn't increase by much as we increase the number of items in the map. Here's the link to the repel code used in this video. I'll see you in the next one. 17. Map Addendum: Welcome friends. In this video we're going to go over an additional feature of Java related to hash maps. Here's the example we had in the previous video with a little bit more code in it. First, let's import Java util dot map. Next, let's take a look at this line. Down below, we declare a variable called x and give it a type of map, integer, integer. We instantiate it using map 1234. A couple of things to note here. First, a map is not the same as a hash map. A map is actually an interface, and a hash map is a concrete implementation of that interface. Second, a map created with map of will be immutable, meaning that you cannot modify its keys or values once it's created. This map of syntax looks funny, but it's basically equivalent to mapping key one to value two and key three to value four. If we do do get one, we'll get two. Since one maps to two, if we do x dot get two, we'll get a null value because two is a value, not a key. Since the key two does not exist, we get a null result. Finally, docket three will give us four, since keys and values alternate in the map of creation call and we specify it three after the value two. That's it for this video. I just wanted to give you an introduction to a fast way to instantiate a map if you don't want to first create the map and then fill it up with keys and values one by one to quickly recap. Maps created this way are immutable. When we do so, we alternate keys and values within the map of call. Here's the link to the repel code in this video. I'll see you in the next one. 18. HashSet: Welcome friends. In this video, we're going to talk about the hash set. The example today is pretty similar to the one in the last video. It fits in one file, and even the syntax is pretty similar. Let's get into it. The first thing you should notice is that just like the hash map, hash sets must be explicitly imported. Hash sets also live in the Java Util package. Next, let's look at the variable declaration. We declare a hash set, and then within these angled brackets we declare the type of the elements that will be contained within it. We use capital I integer since we're wrapping the integers in a container, just like lists or hash maps, when instantiating the hash sets, we don't need to specify the type of the elements on the right side of the assignment. We can just put empty angled brackets, and Java will infer the type of the elements from the variable declaration on the left side of the assignment. The ad method allows us to store items in the set. Note that Java will not allow you to put an object of anything other than an integer in the set. You won't be able to put strings or bullion values. You would get a compile time error if you tried that. Here, if we try adding 35 after we already did so earlier, nothing will actually change. This is one of the key features of hash sets. Hash sets will only store unique items. If you try to add the same item twice, Java will not error, but it also won't do anything different. We also have a size method, and you can probably guess what that does. It just returns the number of items in the set. In this case, that's two. Since we only have 35.91 in the set, the contained method returns true or false depending on whether the requested item is in the set already. It's true for 35 and it's false for 36. You can also remove items from the set. If you call items that remove 35, then 35 will no longer be in the set. We can confirm by calling items that contains 35, which will return false. Now one final key takeaway for you. Just like hash Maps, hash sets also use the hashing mechanism. You don't need to know the details but just know that these calls contains add and remove, all happen in constant time. Meaning that the time required to run these methods does not increase significantly as the size of the set grows. This can be really helpful when you want to use a data structure for really fast look ups and storage. Say for example, you want to check whether a certain advertisement has already been played for a user. That way, we can always play unique advertisements. Well, one way you might represent that is each user object has a hash set associated with him or her. That set contains the advertisement objects that that user has already seen. That's just one basic example. And we'll have another use case for hash sets in the project, which you'll see very soon. All right, and that's it for this video. In this lesson, we talked about hash sets which allow us to store value for later look ups. They also have constant time reading rights, which make them very helpful in diverse use cases, like the unique advertisement example we talked about. Here's the repo link for the code in this video. I'll see you in the next one. 19. Minesweeper Walkthrough 3: Welcome friends. In this video we're going to walk through one of the most impactful parts of the project. Using what we've learned in the last few videos in board Java. Scroll down to this method called gather neighboring empty cells. Let's take a look at what it does. This Q class linked blocking Q might not look familiar to you, don't worry about that. It's not that relevant to the course. All you really need to know about this right here, is that it's assisting us in performing something called BFS, or Breadth First search. That's breath, as in B, R, E, A, D, T, H. We didn't talk about that in discourse. And it's not really necessary that you know how it works specifically. But feel free to Google it if you're curious because it's a very cool concept. In this method, our BFS search is collecting all empty cells that are adjacent to the provided row and column. Once it collects all adjacent empty cells, it then looks for empty cells that are adjacent to the empty cells we've already collected. And then we continue to look for empty cells adjacent to those empty cells, and so on. As you may have guessed, this is part of the code that handles a tap on an empty cell. Recall that when you tap on an empty cell, we typically get a huge chunk of the board tapped for us. That's done via this method, which tells the program where all the empty cells adjacent to the cell you tapped on are located. Before we go on, I want to acknowledge that some of you may be feeling a bit frustrated with these walk throughs. Perhaps you feel like, hey, why didn't we talk about BFS in the walk through videos? Why are we being introduced to new data structures and algorithms in this project? Well, there are a couple reasons for that. The main one is that a huge part of being a programmer is being able to read unfamiliar code, understand it at least partially, and then modify it. It's not true that there's a finite amount of Java you can learn. And only after you've learned it, you'll be ready to tackle all the code in the world. The truth is that there are a ton of smart people out there. And people use all sorts of hard to understand algorithms and code. There's no magical amount of Java that you need to know before you're ready to face the world. Learning to work with code you're not 100% familiar with is an everyday reality. If you've made it this far in the course, I'm glad you're still here and learning to learn with me. All right, now let's finally take a closer look at some key components of this method. Look at this variable called, especially the line right here that says pole split. What that's doing is it's removing a string from the data structure, separating the string into components using the delimeter, and then saving the result of that split into disvariable coordinates. For example, if there was an item in the Q that was a string a B, then the result of splitting by the would be a two element array whose first element would be a and whose second element would be B. Here you can see that in our case, A is actually a row index and B is actually a column index. We use these indices to select a cell in our board, and then we have this to do. It's actually really hard to understand what we need to do here. If you've never seen BFS, don't feel discouraged if you feel stumped. I'll tell you what's going on here though. In this loop that follows the to do we have this line A plus plus j. As you can probably guess, Ad will add the string, we give it to Q. One thing you might not notice immediately though, is that we might infinitely add items to Q. And then we'll never exit this loop that checks whether Q is empty. Basically, the idea is that we want to only perform this nested loop here, at most once, for every single cell in the board. But right now, if you've already seen row A in column B, you might still accidentally add a B to Q and run through this nested loop once again. So we need to keep track of all cells that we've already visited. We want to store cells that we've already seen in the data structure and then only execute this double nested loop at the current cell has not been visited already. Can you think of a data structure that we've learned about that allows for fast insertion and fast look ups? Think about it and I'll pause the video and I'll answer in 321, the answer is a hash set. We can store cells that we've already visited in a hash set. That means that if you encounter a cell that is not in the hash set, that means you've never encountered a cell before. This way, we can ensure we only run this double nested loop on each cell at most once. Here's what we need to do First up here we're going to instantiate our hash set called scene. Then down here we're going to first check have we already seen this cell? We can use the sets contains method for T. Then we wrap this entire double nested four loop inside of here and flip this to a negative. If we have not yet seen the given cell, then we add this cell to the scene hash set because now we have visited this cell. Now that we've visited this cell, we perform our loop. Now we ensure that this loop will never be run again. Why is that? Well, let's see, 1 second. I think I got this indentation messed up. There we go. Okay. Why does this work? Let's say we encounter a cell that has never before been seen. It's not going to be inside of scene. We add it to scene, and then we perform this double loop. Let's say that we accidentally add the cell that we just saw inside, back inside Q. Then when we go through the loop, again, we're going to that we're going to pop the cell that we've already seen out of the que. And then we're going to check if scene does not contain popped. Well, because we already added the cell that we saw into the scene has set here, then by the time we come back to this if statement on the next round, this will return false. We won't be able to execute this double nested for loop on that cell another time. That's it for this video. Now we've accomplished our task. We're just one piece away from being able to play our game. I'll see you in the next video. 20. Minesweeper Walkthrough 4: Welcome friends. In this video we're going to finally complete our game. When you're done with this video, you should be able to play the game interactively and share the link with your friends so they can play too. All right, for the first part of this walk through, we're going to revisit Board Java. At the top of this file, you should see that we have this letter to num map defined. Recall that when you play the game, our commands take the form. Action, row, column like a, B. Our row and columns are input as letters, but we need to convert these letters into indices. And our minesweeper board, our board indices, are going to start from top to bottom, left to right. In other words, A maps to index zero, maps to index one, and maps to index two, and so on. Here, we just need to define those mappings. Let's do that. We have a mapping to zero, mapping to one Quick thing to note, the fact that I left a new line between each pair of values, Key values is actually not necessary. You can also just put these all in one line. I just put it into different lines to make it look nicer. Also, make sure that you have double quotes around your keys. If you put single quotes, that's actually a different Java type called a character. Next we're going to go to Main Java, scroll down to where we have integer row equals. This is where we do the conversion from letter to number. Recall from the previous video where we talked about this commands array right here, when we split by white space, we break up the user command into three elements. The command is the first element, the row letter is the second element, and the column letter is the third element. Remember, our indices start at zero. That means that the row letter is going to be at index one. In commands, let's retrieve the number mapping of the row by doing board letter to nu map get commands one here. This letter to numb map is what we just defined over here. It's going to take the row letter that the user input and then fetch the numerical index that that letter corresponds to that we just defined in the other class. Similarly, let's do the same thing for column board letter to numb mapget commands to. Now we actually need to add a few enhancements and correct a typo I made in previous videos in Board Java where we implemented gather neighboring empty cells, change scene to scene cells. The last line of this method here we actually expect a variable to exist called scene cells. That was my bad, I apologize. Let's change the scene to scene cells. Finally, in the cell classes that we implemented in one of the first walk throughs for this, make sure that you have the tapped, the tapped case before the is flagged case. This is because once you tap a cell, that cell state is final. You can't flag or untap it. However, if is flag comes first in the two string method, then that means if you flag a cell first and then later tap it, the board is still going to render the triangle symbol for the board instead of the tapped state since it checks the flag bull before the tapped bull. Don't worry if that's a bit confusing, it's a tricky bug. The main point of this project was to practice coding, not to find obscure bugs. Don't worry about it. Now let's try clicking Run and Play our game. Nice. It looks like the game is working. We're getting number cells revealed, empty cells revealed at all the proper places. We can also try flagging, and we get a flag in the correct place. All right, so that's it for this video. Thanks for making it this far. Now you can play the game and share with your friends. I'll see you in the next video. 21. Module 2 Conclusion: Hello again. Welcome to the end of this course. Congratulations. You've now built a working mines fee per game that can generate more than 1 trillion configurations. And you can use these to challenge your friends and show off on your resume. And by the way, I'm not exaggerating, I really do mean more than 1 trillion. You can check my math. You've also learned several ways of designing code. Using inheritance, abstract classes and interfaces. You've also learned about useful data structures such as hash maps and sets. It may be hard to believe me right now, but as you progress through your career, you're actually going to find that a lot of advanced technologies are actually just built on top of basic things such as inheritance and basic data structures, like the ones you learned in this course. You'll just have to take my word for it for now. But eventually, I hope that one day you'll see what I mean. Most importantly, programming is a skill in which everyone is continuously learning. I don't promise to have taught you everything there is to know about Java programming, but I do hope I've given you a clearer picture of the fundamentals so that you're well equipped to learn even further on your own, whether it's through my future courses or through someone else's. Once again, congratulations on finishing the course, and I wish you all the best until next time.