 So that's our mutable model and now we can lastly look at the actual GUI stuff the part where we create a window and draw on it and handle the keyboard input First off the fill point function is what actually does our drawing within the window the fill point function takes three parameters G point and color point in color should be pretty self-explanatory point is a coordinate on our field and Color is an instance of the Java dot dot color class representing some color G though is short for graphics as in graphics context And if you've ever worked in a GUI toolkit like swing, you'll know that a graphics context is basically an object Which has methods which when invoked will draw within some designated surface some surface area associated with the graphics context Once we create our window it'll become clear where this graphics context comes from but for now Just take on faith that this graphics context has two functions. We're using set color and fill rect Set color sets the active color on the graphics context the color which it will use for its subsequent drawn operations And then fill rect will draw a filled in rectangle. That's what it stands for So in the function first we need to take the point the coordinate on the field and translate it into a sequence of four elements An x pixel coordinate a y pixel coordinate and then a pixel width and pixel height So that's what point the screen rect returns and using destructuring in this let form We bind each of those values to x y width and height Then we invoke the set color method of the graphics context with the argument color So we're setting the color to whatever is passed in as color And then we invoke the fill rect method of the graphics context with the arguments x y width and height And that will draw a filled in rectangle of the currently set color Starting at pixel coordinate x y and having the specified width and height So that's our function, which does the actual drawing What we have next is the use of the macro def multi which creates what closure calls a multi method a Multi method in short is a special kind of function which dispatches to some other function So when we call the multi method based on the arguments we pass in it's going to dispatch to some other function in Truth, this is nothing we couldn't do with just ordinary functions But as you'll see particularly with more complicated examples multi methods make this pattern more convenient So in this case the death multi macro is deafening to the symbol paint this fn form here Which takes two arguments GA graphics context and some other object And then the dispatching function returns the value of the type keyword of the object So objects should be some sort of map object, which has a value for the key keyword type And it's the value of this dispatching function which determines which particular method we dispatch to with the same argument Those methods of the multi method we create with the def method macro And so you see here we create two methods for paint and notice that after the paint symbol But before the parameter list we specify a value and if this value matches the value returned by the dispatch function Then this is a method which gets invoked So the first method here is invoked when the type of the object is the keyword Apple And the second is invoked when the type of the object is the keyword snake So in effect when we invoke the multi method passing in an object Which is an apple then we're painting an apple, but when we pass in a snake, then we're painting a snake Looking at the first method we use destructuring on the second parameter to bind the location and color of the apple to symbols of the same name And then we invoke fill point with the arguments g location and color So we're painting the single point specified by a location in the color specified as color And then in the second method the one that paints snakes using destructuring We take from the object parameter the keys body and color and then in the body using the do seek macro Which is a macro that iterates through every element of the sequence body here and the binds each element of the body sequence to point for each iteration So effectively we're iterating through all the points in the body and we're drawing them with the fill point function In truth this example probably makes multi methods seem like more trouble than they're worth But in some more complicated examples they can be very helpful Anyway moving on next we have this game panel function which returns a new j panel Which is where we actually draw our game In swing a j panel is not a window itself but it's an area within a window which we can draw to and also listen for events Like keyboard key presses and mouse clicks and so forth So first off this game panel function takes three arguments A j frame object And then the other two parameters receive refs which hold the current value of the snake and the current value of the apple We haven't introduced proxy before what it does in short is create a one-off Java instance So rather than creating a whole Java class and then instantiate it We just create a one-off instance of an effectively anonymous Java class So a proxy form starts out with two vectors The first of which specifies the class from which to inherit and then zero or more interfaces to implement So this proxy here we create in an instance that extends jPanel and implements the action listener and key listener interfaces And then the second vector of proxy is where we specify arguments to the super constructor to the jPanel constructor in this case But we don't need to pass anything to the jPanel constructor. So our vector here is empty After the two vectors we then have methods each in its own pair of parentheses So first we have a method paint component that has one parameter g get preferred size with no parameters Then a method action performed with one parameter e Key pressed with a parameter e key released with one parameter e and key typed with one parameter e Notice that the bodies of key released and key typed are both empty The reason we have those methods included is because they are part of the key listener interface And so we do have to include them even though our versions are not going to do anything Anyway looking at the first two methods here paint component and get preferred size These are methods of the jPanel class and we're overriding them in our subclass here this proxy Paint component is the method that gets invoked when swing decides it needs to repaint this panel a panel is a kind of component And so swing will provide g the graphics context which we need to do the actual painting So the first thing we do in paint component is use the proxy super macro to invoke the inherited version of paint component The one we're overriding and the reason we want to do this is because the inherited paint component We'll first blank out the whole panel every time we draw the new state of the game We don't want the old state to be lingering around the result would look totally wrong, of course Anyway, so after blanking out the canvas we then use the paint multi-method to paint the apple and then the snake Get preferred size as a method invoked by swing when it wants to determine how much space the panel needs or how much space it wants rather There are cases where swing will override the preferred size of a particular component In this case though because our frame contains just one panel and that's the entire panel There aren't really any conflicts that'll arise and so we'll we'll get our preferred size So get preferred size is expected to return a dimension object We instantiate dimension here again using this special syntax instead of the new special form And the dimension constructor expects two arguments a width and a height The width here is the product of field width incremented by one multiplied by point size And the height is field height incremented by one also multiplied by point size So recall that our field width is 50 our field height is 30 and point size is 15 So our dimension will end up being 750 pixels wide and 450 pixels tall The action-performance method of the action listener interface as we'll see in a moment is going to get invoked every time our game needs to update The parameter E receives an action-performance event object which we're not actually going to pay attention to We're just going to ignore it but it's a required parameter of this method so that's why we include it So in the method first thing we do is invoke update positions which recall updates to snake and apple roughs And then with the updated value of snake we test if we have lost the game with the lose function And if so then we reset the game with the reset game function And we invoke the static method show message dialog of the joption pane class Which simply displays a pop-up alert window here with the text you lose Notice that we pass in the j-frame because a pop-up dialog has to be associated with an actual window Pop-up dialogs are actually associated with a window they're not their own free-floating windows Anyway if lose returns false then well maybe we won so we invoke the win function to see if we've won And if so then again we reset the game and we pop up a message dialog but this one says you win Lastly because of all that because the game state has updated the repaint method doesn't immediately invoke paint component But it tells swing that the component does need a repaint and so swing will invoke paint component in short order Lastly we have the methods of the key listener interface and the only one we've implemented to do anything is key pressed Again it takes a parameter e representing the event the key press event And in this case we actually care about the event object because we're going to invoke is get key code method To return the key code of the key that was pressed and we invoke our directions map as a function with the key code as argument And so we're looking up in the directions map we're looking up that key code to get the associated value the direction vector That vector is bound to the symbol direction by this let form and then in the body of the let form If direction is anything other than false or nil which it will be if the key pressed was either left right up or down In which case we invoke update direction passing in the snake ref and this new direction the one that we got from the key code So when key pressed is past a key listener event with a key code of either up down left or right then we're going to update the direction of our snake Finally our last function game is the program kickoff In the body we have a let form in which we bind a snake a new ref with the value returned by create snake And we bind to apple a new ref with the value returned from create apple We bind the frame a new instance of J frame to the constructor of which we pass a string snake which is simply the title of the window Then we bind the panel the result of calling game panel And lastly we bind a timer a new instance of the timer class to whose constructor we passed turn millisecond which recall was the value 100 And this new panel We then invoke two methods on this panel set focusable with the argument true and add key listener with the panel itself as argument We want the panel to be focusable because without focus a window component cannot receive key events And when we add the panel itself as a key listener of the panel then when key events happen on the panel when it has focus they get dispatched to the panel So when you have focus on the panel and you hit a key on the keyboard then the key pressed method of our panel object gets invoked Next on our frame object we invoke four methods first add we're adding the panel to the frame without doing this the panel wouldn't appear in our window Having then added all the components of the frame we then invoke pack which will size and position the elements within the frame Because newly created J frames it start out not visible we need to call set visible To ensure that all the threads used by swing get shut down when we close the window we set the default close operation to exit on close A static enumerated value of the J frame class And lastly because once we create a frame it starts out not visible we need to set visible to true otherwise the window won't show up And then finally very very last thing we need to start our timer with the start method Once started the timer will invoke the action performed method of our panel at regular intervals every 100 seconds That's what a timer does you pass in a number of milliseconds and some action listener object and it will invoke its action performed method every number of milliseconds So that's our kickoff game function and we start our program by invoking game Now before we go you may be wondering why we used refs in this program Why did we store the snake and the apple in ref values instead of perhaps just say vars in the current namespace using the def form that would have worked too Well if it were the case that say the methods which paint our panel and the methods which update the snake and apple if they ran in separate threads we would definitely want to use refs here Without refs our paint method might draw an inconsistent state of the game where say the snake has been updated after one move but the apple has not And if it were the case that say our action listener method action performed which is triggered by the timer and the key pressed method which is triggered by hitting keys If those methods ran in separate threads we would have a danger of inconsistent updates to the snake You could have a scenario say where the user updates the direction of the snake by hitting a key but if the action performed method is running concurrently it might undo that update And so a change in the snake's direction could get inappropriately lost By using refs we can ensure that methods running in different threads can have consistent views of our snake and our apple Now it turns out that the way swing works is that these event handler methods paint component get preferred size action performed key pressed all of these methods were using They don't run in separate threads they're all guaranteed to run in one thread And so this program actually really doesn't need refs It's good policy however when writing closure code to when dealing with global mutable state like snake and apple here to always just use refs by default Because maybe you don't have any concurrency problems now but going forward you might be introducing multi-threading into your program and then you're going to want them And then in certain cases with experience will recognize that oh I don't actually need a ref maybe I need an atom or maybe I need an agent