Reputation: 1437
I have an assignment to build a tic-tac-toe game using ruby classes.
I'm new to programming and self taught so far, but was accepted into a program and need to polish up on some concepts to be ahead of the game.
I understand most concepts and got the majority of spec files to work for my game, but I did need to reference the solution code a few times to help solve the last bit of the problem.
In creating the board class, two methods were created that were defined using empty arrays. I have never seen this before and wanted to know what was going on. When I went into my IDE and created a method with the name [](empty array) and two parameters, I'd get an error (syntax error, expecting end of input) trying to run it. It seems this must be something you can only do while setting up a class?
I'm assuming these are getter and setter methods?
def [](pos)
row, col = pos
grid[row][col]
end
def []=(pos, value)
row, col = pos
grid[row][col] = value
end
In the above code, grid is an instance variable of the board class. Why can you use an instance variable in a method without putting the "@" symbol in front of it - (@grid, instead of grid). This is a little confusing because with normal methods, if you define a variable outside of the method, the method doesn't recognize it. Why is it different inside of classes?
#example
x = 6
def add(b)
x + b
end
=> will return an error - local variable x is undefined.
Below is the full board class in case it'll make better sense understanding and answering the questions. Thank you!
class Board
attr_reader :grid, :marks
def initialize(grid = [])
if grid.empty?
@grid = Array.new(3) { Array.new(3) }
else
@grid = grid
end
@marks = [:X, :O]
end
def place_mark(pos, mark)
grid[pos[0]][pos[1]] = mark
end
def [](pos)
row, col = pos
grid[row][col]
end
def []=(pos, value)
row, col = pos
grid[row][col] = value
end
def empty?(pos)
grid[pos[0]][pos[1]].nil? ? true : false
end
def winner
(grid + grid.transpose + diagnol).each do |win|
return :X if win == [:X,:X,:X]
return :O if win == [:O,:O,:O]
end
nil
end
def diagnol
diag1 = [[0, 0], [1, 1], [2, 2]]
diag2 = [[0, 2], [1, 1], [2, 0]]
[diag1, diag2].map do |diag|
diag.map {|row, col| grid[row][col]}
end
end
def over?
return true if grid.flatten.compact.size == 9 || winner
return false if grid.flatten.compact.size == 0 || winner.nil?
end
end
Upvotes: 0
Views: 208
Reputation: 165
A bit late but I was also looking into this and found this on the web. Apparently, it is syntactic sugar for classes with grid-like instance variables.
The Syntactic Sugar
These are all equivalent ways to get the bottom-left square:
board.grid[2][0] board.[](2, 0) board[2, 0] # syntactic sugar
The syntactic sugar allows us to call the Board#[] method with our arguments inside of the square brackets themselves rather than in parentheses following the square brackets.
Similarly, the following are equivalent ways to set the top-right square:
board.grid[0][2] = :x board.[]=(0, 2, :x) board[0, 2] = :x # syntactic sugar
Naturally, if we bother to set up the special [] and []= methods, we'll use the syntactic sugar way. :)
More information can be found from this link:
https://github.com/emgreen33/Practice/blob/master/W2D4/bracket-methods.md
Upvotes: 0
Reputation: 4813
Board
. (FWIW I think that it's poor Ruby style to do this, so I wouldn't use this in the future in your own code. I think that's why your IDE is having issues with this method as well.You can use grid
without the @ because of the attr_reader
declaration at the top of your class. This creates a read-only variable for the instance variable that is public on the class. It effectively creates a method called:
def grid
@grid
end
You would not be able to do grid = []
because attr_reader
only creates a read only method. To create a read-write accessor, you would use attr_accessor
. Keep in mind, using attr_
methods make the variable in question public on the class, so if you wanted to keep something internal, you would not use them.
Upvotes: 2