Battleship Flashcards
Class : BOARD
What is the first step in creating the Battleship game?
- Initialize the board which will take “n” as the argument which will represent the size of the row and the size of the column.
board = Board.new(n)
- create a @grid and @size attribute with @size = n * n
- Create the attr_reader and attr_writer for the attributes
Class : BOARD
What is the next step in using bracket methods?
- bracket method #1 ( #[ ] ) will accept a position with an index pair like [0, 0] with row equal to position[0] and column equating to position[1]. Should use @grid.
to define : def [ ] (position)
to call : self [position]
- bracket method #2 (#[ ]=) will accept both a position and a value and will reassign the grid at that position to that value. Should also use @grid[row][col]
to define : def [ ] (position, value)
to call : self [position] = value
WITH BOTH METHODS, NEED TO USE SELF TO CALL ON THE METHOD NAME.
Class : BOARD
How do you count the number of ships there are?
@grid.flatten.count(:S)
Class : BOARD
How do you make an attack?
- Need to accept a position as a parameter
- Need to use the [ ] bracket method to check what the value is in the grid at that position and see if it’s a ship :S or not
- If it matches to an S, then use the [ ]= bracket method to reassign to a Hit or :H then print “you sunk my battleship” and return true. Don’t forget to actually add ‘return’ and also have it the last line of code within the if statement.
- if false, then use the [ ]= method again to reassign to an :X to indicate a failed attempt and then return false. Again, don’t forget to actually add the ‘return’ keyword and have it the last line of code.
def attack(position) if self[position] == :S self[position] = :H puts "you sunk my battleship!" return true end self[position] = :X return false end
Class : BOARD
How do you randomly place ships on the board at 25% of the board spaces.
- Define an instance method
- Create a quarter variable that takes the @size and multiples by 0.25
- Create a while loop that takes the num_ships method (self.num_ships) and sets it to while it’s still lower than the quarter. => “while self.num_ships < quarter”
- find the random row using #rand and find the random column also using #rand with the ranges from 0 to @grid.length
- set position as an array with the randomized row and column
- use the bracket method again [ ]= to set the randomly selected positions with a ship or :Sdef place_random_ships
quarter = @size * 0.25
while self.num_ships < quarter
rand_row = rand(0…@grid.length)
rand_col = rand(0…@grid[0].length)
position = [rand_row, rand_col]
self[position] = :S
end
end
Class : BOARD
How do you then hide the ships on the grid without mutating the original array?
- create an instance method
- Use the map method to reassign the :S -> :N but then assign it to a “hidden” variable so that hidden grid version can be returned later on
- Using nested map methods where it iterates through the grid first then the sub-arrays and checks if each element in the sub-array matches to :S ship or not. If it does match, reassign to a :N. If it doesn’t match, keep the same element. MAKE SURE it’s a full ternary statement as it still needs to retain the original element if it’s not a ship.
- Make sure to use self.grid as long as an accessor is being used for :grid specifically.
def hidden_ships_grid hidden = self.grid.map do |row| row.map do |e| e == :S ? (e = :N) : (e) end end hidden end
Class : BOARD How do you create a class method to print the grid?
- Since it’s a class method, need to use self in the definition of the method
- SINCE IT’S A CLASS METHOD, DON’T USE @. The @attributes are instance attributes and apply to instances ONLY.
- Iterate through the grid and then each row is an array so can just join with a “ “ to change to one string instead.
- DONT FORGET TO USE PUTS TO PRINT OUT ON A NEW LINE
def self.print_grid(grid) grid.each do |row| puts row.join(" ") end end
Class : BOARD For the #cheat and #print method, it needs to use the class method to print_grid. How are these methods defined?
- since it’s using a class method, it needs to use the class to call on the method.
- The print_grid class method requires a grid as an argument so we should use the self.grid to call on an instance and its corresponding grid.
def cheat Board.print_grid(self.grid) end
def print Board.print_grid(self.hidden_ships_grid) end
class : PLAYER
Define the method #get_move where it asks the user to input coordinates separated by a space
- Include the print statement
- Create a ‘response’ variable that gets the user input with gets.chomp
- Since it automatically returns as a string, need to convert into integers and then place into an array so that it can be used as coordinates
- Iterate through the string, to look at each char and if the char is not a “ “ space then convert to an integer using .to_i and shovel into a position array.
- Return the position
class Player
def get_move p 'enter a position with coordinates separated with a space like `4 7`' response = gets.chomp position = [] response.each_char do |char| position << char.to_i if char != " " end position end
end
class : BATTLESHIP
What is the first step in initializing the board taking in “n” to represent the length of the board
- Since this is the parent class, it needs to require_relative the child classes - “./board.rb” and “./player.rb” assuming they’re in the same folder
- Create a @player instance attribute by initializing the Player class
- Create a @board attribute and initialize the board with the (n) argument provided.
- Create a @remaining_misses which will be half the size of the board. This needs to call upon the board instance created prior with the @board attribute. REMINDER - in the board class, when initialize a board instance, it’s going to hold both the @grid and @size within each instance. So need to use board_instance.size to call upon that attribute.
class Battleship
attr_reader :player, :board attr_accessor :remaining_misses def initialize(n) #length of the board @player = Player.new @board = Board.new(n) @remaining_misses = @board.size / 2 end
class : BATTLESHIP
How do you start the game?
- The @board attribute create the Battleship class initialization was assigned to an INSTANCE of the board class. So from here on, we can use ‘board’ to call on any method belonging to the Board class
- Need to randomly place ship using the method created in the Board class and using the board attribute as a board instance.
- Use the #num_ships method to print # of ships
- Use the #print method to print the board with the hidden ships instead
def start_game board.place_random_ships p board.num_ships p board.print end
class : BATTLESHIP
How do you create methods to see if the player has won or lost?
How do you create the method to have the game over if the player has won or lost?
def lose? if self.remaining_misses <= 0 p "you lose" return true end return false end
def win? if board.num_ships == 0 p "you win" return true end return false end
def game_over? if self.win? || self.lose? return true end return false end
class : BATTLESHIP
How do you create a “turn” method?
- Need to get a position from the player. Within the Player class, we defined a method #get_move which had the user input coordinates and convert the coordinates into an array and returned the position. We need to invoke that method. Since we initialized the @player attribute as a Player instance (Player.new) we can then use the player attribute to call on that method.
- We need to use the #attack method defined in the Board class which returns a true or false on whether a hit was successful or not. Since it’s returning a true/false, if it’s false and the hit was not successful, then we want to decrement the remaining misses. Since we used an attr_accessor on the remaining misses we can use self to access it as it was initialized in the Battleship class.
- then we need to print, so that should be OUTSIDE of the if statement and the last lines of code.
def turn
position = player.get_move #returns a position
if !board.attack(position) #return t or f
self.remaining_misses -= 1
end
p board.print p self.remaining_misses end