Skip to content

Instantly share code, notes, and snippets.

@Dawenster
Last active December 13, 2015 23:39
Show Gist options
  • Save Dawenster/4993396 to your computer and use it in GitHub Desktop.
Save Dawenster/4993396 to your computer and use it in GitHub Desktop.
class AI
attr_reader :already_guessed
def initialize
@already_guessed = []
@coordinates = {}
end
def choose_coordinates
@coordinates = {}
col = rand(COL_RANGE)
row = ROW_RANGE.to_a.sample
@coordinates = {row: row, column: col}
if already_guessed.include?(@coordinates)
choose_coordinates
else
already_guessed << @coordinates
@coordinates
end
end
end
COL_RANGE = 1..10
ROW_RANGE = "A".."J"
SHIPS = [1,2,3,4,5]
DIRECTIONS = [:row, :column]
class Board
attr_reader :playing_field, :ships_sunk
def initialize
set_blank_board
@ships_sunk = []
end
def playing_field_values
playing_field.values.flatten
end
def set_blank_board
@playing_field = {}
letter = 'A'
ROW_RANGE.to_a.each do |row_letter|
@playing_field[row_letter] = Array.new(10) { "." }
@playing_field[row_letter].unshift(letter)
letter = letter.succ
end
@playing_field
end
def place_all_the_ships
begin
SHIPS.each do |ship_value|
place_ship(ship_value)
end
rescue CannotBeDrawn
set_blank_board
place_all_the_ships
end
end
def place_ship(ship_value)
spot = random_starting_point
ship_direction = DIRECTIONS.sample
increment_direction = DIRECTIONS.find {|d| d != ship_direction}
increment_value = spot[increment_direction]
ship_value.times do
coordinates = {
ship_direction => spot[ship_direction],
increment_direction => increment_value
}
draw(coordinates, ship_value)
increment_value = increment_value.succ
end
end
def draw(coordinates, value)
row = coordinates[:row]
column = coordinates[:column]
row_values = playing_field[row] # sometimes this will be K, L, M... (if it goes off the map on a column boat)
raise CannotBeDrawn unless row_values
coordinate_value = row_values[column - 1]
raise CannotBeDrawn unless coordinate_value == '.'
playing_field[coordinates[:row]][coordinates[:column] - 1] = value
end
def draw_attack(coordinates, interface, boards, board)
if playing_field[coordinates[:row]][coordinates[:column]] == '.'
playing_field[coordinates[:row]][coordinates[:column]] = 'O'
interface.miss(boards, board, coordinates)
else
playing_field[coordinates[:row]][coordinates[:column]] = 'X'
interface.hit(boards, board, coordinates)
end
end
def random_starting_point
col = rand(COL_RANGE)
row = ROW_RANGE.to_a.sample
{row: row, column: col}
end
def check_sunk_ship(interface, boards, board)
current_player = ''
boards[0] == board ? current_player = 'Your' : current_player = "AI\'s"
SHIPS.each do |ship|
unless playing_field_values.include?(ship)
ships_sunk << ship
interface.sunk_ship(ship, current_player) if ships_sunk.count(ship) == 1
end
end
end
def all_sunk?(board)
board.ships_sunk.uniq.length == 5
end
end
class Game
attr_reader :interface, :ai, :user, :players, :boards
attr_accessor :user_board, :ai_board
def initialize(user_board, ai_board)
@interface = Interface.new
@ai = AI.new
@user = User.new
@players = [user, ai]
@user_board = user_board
@ai_board = ai_board
@boards = [user_board, ai_board]
@user_attack_coords = {}
@ai_attack_coords = {}
end
def run
user_board.place_all_the_ships
ai_board.place_all_the_ships
interface.display_boards(boards)
until all_ships_sunk?
take_turns
draw_attacks
interface.display_boards(boards)
check_sunk_ships?
end
end
def take_turns
players.each do |player|
if player == user
@user_attack_coords = attack(player)
else
@ai_attack_coords = attack(player)
end
end
end
def attack(player)
if player == user
user.choose_coordinates(interface)
else
ai.choose_coordinates
end
end
def draw_attacks
boards.each do |board|
if board == user_board
boards.find {|b| b != board }.draw_attack(@user_attack_coords, interface, boards, board)
else
boards.find {|b| b != board }.draw_attack(@ai_attack_coords, interface, boards, board)
end
end
end
def check_sunk_ships?
boards.each do |board|
board.check_sunk_ship(interface, boards, board)
end
end
def all_ships_sunk?
boards.each do |board|
if board.all_sunk?(board)
interface.game_over(boards, board)
exit
end
end
false
end
end
class User
attr_reader :already_guessed
def initialize
@already_guessed = []
@coordinates = {}
end
def choose_coordinates(interface)
@coordinates = {}
interface.enter_letter
letter_entry = gets.chomp.upcase
until letter_legit?(letter_entry, interface)
interface.enter_letter
letter_entry = gets.chomp.upcase
end
interface.enter_number
number_entry = gets.chomp.to_i
until number_legit?(number_entry, interface)
interface.enter_number
number_entry = gets.chomp.to_i
end
@coordinates = {row: letter_entry, column: number_entry}
duplicate_check(interface)
end
def letter_legit?(letter_entry, interface)
if !!(letter_entry =~ /^[a-jA-J]$/)
true
else
interface.wrong_letter
false
end
end
def number_legit?(number_entry, interface)
if number_entry <= 10 && number_entry >= 1
true
else
interface.wrong_number
false
end
end
def duplicate_check(interface)
if already_guessed.include?(@coordinates)
interface.guess_again
choose_coordinates(interface)
else
already_guessed << @coordinates
@coordinates
end
end
end
require_relative 'controller - board'
require_relative 'controller - game'
require_relative 'controller - user'
require_relative 'controller - ai'
require_relative 'view'
class CannotBeDrawn < StandardError
end
user_board = Board.new
ai_board = Board.new
game = Game.new(user_board, ai_board)
game.run
class Interface
ASTERIX_DIVIDER = '*' * 22
def display_boards(boards)
clear_screen
move_to_home
boards.each do |board|
puts ASTERIX_DIVIDER
puts board == boards[0] ? ' Your board' : " AI\'s board"
puts ASTERIX_DIVIDER
puts ' 1 2 3 4 5 6 7 8 9 10'
board.playing_field.each do |k, v|
if board == boards[0]
puts v.join(' ')
else
hide_nums = []
v.each do |e|
if e.class == Fixnum
hide_nums << '.'
else
hide_nums << e
end
end
puts hide_nums.join(' ')
end
end
puts ''
puts board == boards[0] ? 'Your remaining ships' : "AI\'s remaining ships"
p board.playing_field_values.select { |v| v.is_a?(Integer) }.uniq.sort
puts ''
letter = 'A'
end
end
def clear_screen
print "\e[2J"
end
def move_to_home
print "\e[H"
end
def enter_letter
puts 'Enter a letter:'
end
def enter_number
puts 'Enter a number:'
end
def guess_again
puts 'You have already guessed that - try again!'
end
def wrong_letter
puts "Please only put in one valid letter."
end
def wrong_number
puts "Please only put in one valid number between 1-10."
end
def miss(boards, board, coordinates)
pronoun = ''
boards[0] == board ? pronoun = 'You have' : pronoun = 'AI has'
puts "#{pronoun} missed at #{coordinates[:row]}#{coordinates[:column]}..."
sleep(1.0)
end
def hit(boards, board, coordinates)
pronoun = ''
boards[0] == board ? pronoun = 'You have hit AI' : pronoun = 'AI has hit you'
puts "#{pronoun} at #{coordinates[:row]}#{coordinates[:column]}!"
sleep(1.0)
end
def sunk_ship(ship, current_player)
puts "#{current_player} ship #{ship} has been sunk!"
end
def game_over(boards, board)
winning_message = ''
board == boards[0] ? winning_message = 'AI wins!' : winning_message = 'You win!'
puts "Game over! #{winning_message}"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment