 So that's the triple winner function after that function you see a use of the declare macro What declare does is really just def the supplied symbol to the value nil It would really be the same thing if we just wrote def triples nil But declare is preferred in this sort of situation because it better conveys our intent We don't really want to give triples the value nil We just want to make sure that the symbol triples is present in the current namespace Because we happen to define our next function winter question mark before our triples function and the winter question mark function It needs to invoke the triples function even though the triples function hasn't yet been defined when the winter function is compiled By creating the mapping in the current namespace of the symbol triples to some empty var The winter function will now at least compile It won't complain that the symbol triples doesn't resolve to anything Even though if we left the var of triples empty if we left it as nil Then of course at runtime trying to invoke triples as a function would trigger an exception because you can't invoke nil Of course as a function So that's what the declare form is for when we need to make sure that a symbol to var mapping pre exists for the Satisfaction of compiling some function even though we're not yet ready to define that thing Now in this example We could have simply written the winter function after the triples function and it would have worked us fine But for other cases particularly cases of mutual recursion when you have a function foo and bar that both need to invoke each other Well, one of them has to be compiled first. They can't both be compiled before the other So you're going to have to pre declare one of them. So that's the case where pre declaration is actually strictly necessary Anyway, let's look at this winter function What the winter function does is when passed in a board it will return the keyword x if x is when I'll turn the keyword Oh, if O's win and otherwise it's going to return nil if there's no winner, which doesn't necessarily mean a draw It just means that there's no winner yet. We have another function later that will determine whether there's a draw Looking in this function. We have a series of nested calls looking at the innermost call We're invoking the triples function passing in board and as we already discussed the triples function Returns a sequence of all the triples of the board the map function recall It's first argument is some function to invoke on all the elements of the provided sequence So the provided sequence here is what gets returned from triples and we're passing each element of that sequence to the triple Winner function and then the map function itself will return a sequence of all the values returned by triple winner So now that map is going to be a sequence of elements All of which are nil's keyword x's or keyword O's for our purposes We want to ignore the nil's so we're going to use the filter function to keep only the x's and the O's and The filter function is another sequence function whose first argument is a predicate function And so each element of the sequence returned by map is passed to this predicate function a set of two values and For all the elements for which the predicate function returns true. They end up in the sequence returned by filter So this called a filter returns a sequence that has all the values from map Which meet this predicate which are either the keyword X or the keyword O and then what filter returns that sequence We're getting its first value and that's what we return from winner So first consider the case where our board has no winner Then the map function here is going to return a sequence of all nil's and we call filter on that and we get an Empty sequence call first on an empty sequence and you get the value nil In the case though where one and only one of the triples is made up of all keyword X's Then the map function will return a sequence with just one value keyword X And so filter will likewise return the same sequence and then first we'll return the sole value of that sequence the keyword X And that's what our function is going to return Same story if our board has one triple and only one triple that's filled in entirely with keyword O's our Function is going to return keyword O Now there could be the case of multiple triples having winners You can have like one row that's filled entirely with X's and another row that's filled entirely with O's Such a board could logically exist But as you'll see elsewhere, we're not going to get there because the first time we get a board that has a winner We're going to stop the game. So we don't really need to consider such cases Just be clear if you did have such a board passed to this winner function Then whether this function returns X or O would just be a matter of looking at the triple's function Which one of those rows columns or diagonals comes first in the sequence returned by triples? But it's probably the best you consider such behavior to be undefined because again, we really don't care about such cases We're not supposed to get there our board shouldn't get into that state Anyway, hopefully you now understand these three functions looking further on After the triples function we define another function called full board question mark Which again takes board as its only argument and it returns true or false if all of the elements of the board Are either X's or O's in other words if the board is full This function is quite simple again We're using the every sequence function with a set as predicate such that if all the values of the board are Found in this set then every will return true. Otherwise it will return false So if any of the values in our board are neither keyword X's or keyword O's if they're the value nil Then the full board function will return false After the full board function we define another function print board which will display a board on the console and Note that this is actually our first impure function all the previous functions were all pure They didn't have any side effects. They just took an immutable input value and spit out an immutable output value Any case looking at print board first off We have a let form in which we are binding to board the result of this call to map Which is taking as its sequence the parameter board Remember we can do this in let form as the expression that returns the value We're binding to the symbol can use a symbol of the same name from the surrounding context and that actually works fine And let so the board that we're binding to and the board we're taking the value from the let form knows that they're separate values In any case the call to map takes as its predicate a function which we're defining in line Remember that the number sign parent syntax is just shorthand for an fn form in which the body has just one expression and The single expression in this fn body is an if form Inside this if form you'll notice that we have Percent signs and these percent signs refer implicitly to the first parameter of this shorthand function That's the other convenience of the shorthand function as we don't have explicitly declare parameters They're just implicitly percent sign one percent sign two percent sign three to refer to the first second and third parameters And and so forth with the extra convenience that percent sign by itself is just shorthand for percent sign one So in this if form we have a condition expression of keyword question mark The keyword function returns true if its argument is a keyword So if the parameter to the function is a keyword then this condition tests true And if it is true this if form executes and returns the result of subs subs is a function that returns a sub string from a string and the string from which we're getting a sub string here is The returned by the call to stir stir takes this argument and returns a string representation like if you passed stir a number it returns a string representation of that number and In this case the argument is percent sign. It's the parameter the function which here will be a key word And so we're returning a string representation of that key word and the call to subs Substring is returning a string of all the characters starting at index one of the string. So everything from the second character to the end So now in the case that when our predicate function here is passed a keyword x The condition of the if will test true and so we will call substring here subs with an argument which is a string with two characters colon x and Substring will return just lowercase x If though this predicate is passed a value, which is not a keyword that the condition will test false and The if form will return percent sign will return just the parameter itself So this call to map will return a sequence which is just like the board which we passed to it Except all the key words will be replaced by a string with the same name as the key word But without the colon like say keyword x becomes a string that just reads x So that is the sequence bound to board in this let form Then in the body of this let form we call print line three times and in these calls print line We're using the int function to return the individual values of board The first call to print line is printing out the top row of the board The second call to print line is printing out the middle row of the board and the third call to print line is Printing out the bottom row of the board The next function player name very simply takes a player name in the form of keyword x or keyword o Which is what we use to denote the players and returns the string representation of that player name is just a letter x or o Just like we did in the print board function We take the string representation of the key word and then we call subs to get the substring starting at the second character of the string Next we have not a function definition But just a def of some global variable starting board Which as the name implies is the starting state of our board earlier I believe I said that we represent the empty slots the unoccupied slots with nil values. I'm a spoke It's actually we represent them with the number indicating the name of the slot and that's just for the sake of when we print out The board is just friendlier to look at numbers representing the slot names rather than a bunch of nils So that's why it's one two three four five six seven eight nine After deafening starting board we then deaf player sequence Which is given the value returned by cycle with the argument of a vector keyword x keyword o the cycle function recall Returns an infinite lazy sequence that's made up of its sequence argument elements repeated ad infinitum So this infinite sequence now in the var of the player sequence symbol It's an infinite sequence that goes keyword x keyword o keyword x keyword o keyword x keyword o On into infinity as you'll see we'll iterate through this sequence to go back and forth between the turns of the two players