Completing the Hardest Section so Far at Flatiron School

I’m going to be honest. This last section was brutal. I had to reach out to help often, and I can’t say with certainty that I really understand everything as well I want to. It’s sort of like knowing what a hammer and screwdriver do, but I can’t build you a house with them…

I have discovered a few things about myself so far.¬†Mainly, I tend to overly complicate my code. In the code I’m about to review, my last, most critical, piece of code was completely hampered by code that passed the initial tests in an earlier lesson but that was just overly complex or built on a flimsy foundation. The biggest culprit was the over method. I had to go out on Google and research it and found a much better solution that I admit I copied over. I took the time to marvel at its elegance which really made me question my own skills… I mean, look at the difference (I did need to fix the code up to work here, but I tend to take Ruby, a language that is heralded as simple and beautiful and make it byzantine…)

My first over? method:

and the new and improved method:

I mean, I don’t know how I never realized full was not needed originally… Oh well…

In any case, let’s take a look at what we have here…

First, we start with the bin file, which is what runs the game from the command line.

This is basically welcoming the player to the game, displaying the initial, empty board and then calling the play method to start the game. Next, we have the tic_tac_toe.rb file which has all of the methods handy. I’m going to show the whole thing first, the talk about each method briefly, explaining what I did in each, or why something works the way it does.

This is the nested array of winning combinations. I discussed this in an earlier post here.

This next bit I also discussed in a previous post here, but I have made some changes to the code, tweaking here and there to fix up stuff.

My biggest changes are using string interpolation to tighten up the display_board method, and in these two:

Completely tightening up the code. Let’s take a closer look.

In the position_taken? method, I went from this:

to what I have above. I actually came across the above code from a lesson where Flatiron School included it in a lab. I was blown away, but took the time to understand why they did what they did here.

My original code, and let’s be honest and say a lot of my code, relied on if else statements. I seem to use them everywhere. Once I had this pointed out, I started attempting to fix this. It has been long and arduous. I probably have more to fix. I am slowly learning, however, that everything in Ruby is truthy, except false and nil. This is a hard thing to keep in mind. In fact, I may have this wrong, but will continue looking into it.

Anyways, just look at how complex my original code is! If the board position is an empty space (defined two different ways) or nil, return false. If it has “X” or “O”, return true. But there is a lot there.

The better code

uses the exclamation point in front of two statements in parentheses which negates them. It basically says the position is taken if the two items inside the parentheses are not true, either the position is nil or an empty space. So simple!

For the valid_move? method, I simply removed the if statement as it was not needed.

In the move method above, I removed the default character as we will now be using X and O, I added the turn_count method as that will need to be incremented each time a move is taken, and I added the display_board method as whenever a move is made the user should see where the character was placed.

In the turn method, I changed the char argument to current_player(board) as this is where the X or O gets assigned from. I honestly feel like I could clean this up a little more… Maybe later on… Let’s look at the methods these are relying on.

So, as I said above, turn_count is basically starting a count at 0, and each time a move is made it increases count by 1.

The current_player method assumes the first move is X, thus if the turn_count is odd then it is O’s turn, otherwise if its even it is X’s turn.

I wrote about the above method extensively and recommend going and taking a look at it here.

These next methods look at the status of the game:

The first method is full? and what it does is use the enumerable of none? to ask whether there are empty or nil positions left on the board. Once there are none of these, the board is full.

Next, the draw? method sees whether the game is ended in a draw. If the won? method from above has returned nil, and the board is full, it returns true prompting the draw.

Next, is the over? method which gave me so much trouble. It essentially checks whether the game is either at a draw or a winner has been chosen and if so the game is over. So simple, yet it gave me MANY headaches. I overthought it…

Finally, the winner method decides who the winner is. I had this one also very complicated, and was able to simplify it once I got a handle on the != (not equal) and the idea of keeping it simple. Here was my original:

I mean, in retrospect, it makes sense. You look at what happened with the won? method. If the game was nil, you return nil. Otherwise, if one of the winning combination returns “X” that means all are “X” and that is the winner. If one of them is “O”, then “O” wins.

This does the same thing, but once I realized it really doesn’t matter in this method that I extrapolate the “X” or “O” I was able to beat it int submission. I just needed to grab the “X” or “O”…

The problem I think I am experiencing is that I need to keep each helper method exactly to their function and nothing else. That is hard to keep in mind at times.

Finally, the last method:

This one was a doozy, but since over? was broke it caused me multiple headaches.

So, basically all it does is say until over? returns true, take turns. If a draw? occurs, tell the user its a “Cats game” and if someone wins congratulate them and call the character.

So, this overall was a huge learning experience. It was difficult and took a lot longer than I thought. There was many times I said to myself:

I think the increasing difficulty was at times a huge jump, but it also got me out of my comfort spot and seeking help which led to some interesting discussions concerning Ruby. That was the most helpful in getting me where I am right now.

One thought on “Completing the Hardest Section so Far at Flatiron School

Comments are closed.