Skip to content
63 changes: 6 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,19 @@

## Description

Write a program that plays the game of Battleship. The user can act as Player 1, and the computer can act as Player 2.
This is my Battleship game!

## Objectives

### Learning Objectives
To play against either the computer or another player and beat them!

After completing this assignment, you should...
### Gameplay

* Understand the basics of control flow, variables, and methods in Ruby.
* Understand the basics of Object Oriented Programming.
* Understand the basic use cases of Git for single-developer projects.
* Understand the purpose of test suites and how they can assist in development.
* Understand how frustrating it would have been to try to check and debug this assignment without written tests!
The game gives you five ships, each with a certain number of hit points. You will place the ships giving X, Y coordinates and then try to find your opponent's in order to destroy them.

### Performance Objectives
When you shoot, name the coordinates you're aiming at (A3, D4, etc). Your target board will record whether you hit their ship. You sink the ship by hitting all the squares that it covers. Once you sink all their ships, you win!

After completing this assignment, you should be able to effectively...

* Accomplish all objectives from earlier in the week.
* Build a game-playing application that asks the user for input and provides output to the user.
* Create a computer player that can act like a human (albeit not necessarily an intelligent one).
* Write an program that can satisfy a test suite.

## Details

### Deliverables

* **A Repository.** Fork this repository to your own github account.
* **A README.** Wipe out this README and write your own. It should tell readers how to play your version of the game.
* **Ruby Files.** You'll need a lot of these, and you'll be creating them from scratch. Again, you should have one per class, plus at least one other to be executed from the command line to run the game.
* **A Playable Game.** When I clone your repository, I should be able to run your program and play through an entire game of Battleship. I should be able to win and to lose.

When you are finished, create a pull request.

### Requirements

The major requirement of this project is for the TEST SUITE TO PASS. You are coding to the tests, and ideally, you're making them pass one at a time. As discussed in class, I would suggest making the first test pass USING THE SIMPLEST MEANS POSSIBLE. Then move on to the second test, the third test and so on. You should commit after each test passes.

Just to be clear, your computer player does not have to be smart. It just has to play until the game is finished.

Here's the odd thing. READ THIS. If you're ever going to call `gets.chomp` in your code to prompt the user for his/her input, don't. Put the following code at the top of any file that needs to prompt the user:

```
def get_user_input
gets.chomp
end
```

This goes BEFORE you start defining your class. I know that looks stupid, and I apologize for it, but the test suite will only run if you ALWAYS ask for user input by calling `get_user_input` rather than `gets.chomp`. Sorry again.

## Normal Mode

It's finally time. Your task this weekend, whether or not you choose to accept it, is to write a program that plays the game of Battleship. The user can act as Player 1, and the computer can act as Player 2. However, as you work through the assignment, you'll notice that you're also building it so that two humans could play each other.

This assignment will bring together two of the assignments from earlier in the week: your written set of computer-friendly instructions from Day 1, and the draft code of your objects from Day 3. You WON'T be using that draft code as a starting point, because it's likely that the classes you designed won't match what the test suite is expecting. You'll be writing code to make a test suite pass, so it is going to dictate a lot of what you put together.

Your program should allow the user to play a full game of Battleship against the computer. The rules of the game are given in the [Hasbro instructions](http://www.hasbro.com/common/instruct/battleship.pdf).

## Hard Mode

Modify your computer player so that it makes intelligent moves. In other words, Normal Mode is satisfied if the computer fires randomly. Hard mode required the computer to fire with some meaning. It has to have a chance of winning.

In addition to the above, add ten more (meaningful) tests to the test suite. Get them to pass!

## Nightmare Mode

In addition to the above, modify your existing code to ask the user which type of game he/she would like to play: regular or SALVO. Allow the user to select and play either game.
Simply run the battleship.rb file!
11 changes: 11 additions & 0 deletions battleship.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require './ship.rb'
require './board.rb'
require './player.rb'
require './human_player.rb'
require './computer_player.rb'
require './game.rb'

if __FILE__ == $0
game= Game.new(HumanPlayer.new, HumanPlayer.new("Bob"), [2, 3, 3, 4, 5])
game.play
end
129 changes: 129 additions & 0 deletions board.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
class Board
attr_accessor :ships, :misses, :hits, :is_target_board

def initialize
@ships = []
@hits = []
@misses = []
@is_target_board = false
end


def place_ship(ship, x, y, across)
ship.place(x, y, across)
conflict = false
@ships.each do |s|
if s.overlaps_with?(ship)
conflict = true
end
end
if !conflict
@ships << ship
return true
else
return false
end
end


def has_ship_on?(x, y)
has_ship_on = false
@ships.each do |s|
if s.covers?(x,y)
has_ship_on = true
end
end
return has_ship_on
end

def fire_at(x, y)
if @ships.empty? || @hits.include?([x, y])
return false
else
@ships.each do |ship|
if ship.fire_at(x, y)
@hits << [x, y]
return true
else
return false
end
end
end
end


def display_header
puts " 1 2 3 4 5 6 7 8 9 10"
puts " -----------------------------------------"
end

def display_bottom
puts " -----------------------------------------"
end

def display
letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
output = ""
self.display_header
(1..10).each do |r|
output = "#{letters[r - 1]} |"
if @is_target_board == true
(1..10).each do |c|
if @hits.include?([c, r])
output << " + |"
elsif @misses.include?([c, r])
output << " - |"
else
output << " |"
end
end
else
(1..10).each do |c|
if @hits.include?([c, r])
output << " X |"
elsif self.has_ship_on?(c, r)
output << " O |"
else
output << " |"
end
end
end
puts output
end
self.display_bottom
end

def sunk?
if @ships.empty?
return false
end
@ships.each do |ship|
if ship.sunk? == false
return false
else
return true
end
end
end

def x_of(coords)
@coords = coords
x = coords [1..coords.length].to_i
end

def y_of(coords)
letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
y = coords[0]
letters.each_with_index do |l, index|
if y == l
return (index + 1)
end
end
end

end



attacker_board = Board.new
defender_board = Board.new
Empty file added class.rb
Empty file.
47 changes: 47 additions & 0 deletions computer_player.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require "./board.rb"
require "./ship.rb"

class ComputerPlayer < Player
attr_reader :target_board

def initialize
super
@board = Board.new
@target_board = Board.new
@name = "HAL 9000"
end

def ships
board.ships
end

def name
@name
end

def place_ships(lengths)
lengths.each do |l|
ship_placed = false
until ship_placed == true do
ship_placed = place_ship(l)
end
end
puts "HAL 9000 has placed his ships.\n"
true
end

def place_ship(l)
x = rand(1..10)
y = rand(1..10)
across = [true, false].sample
new_ship = Ship.new(l)
ship_placed = new_ship.place(x, y, across)
if ship_placed == true
board.ships << new_ship
end
ship_placed
end



end
104 changes: 104 additions & 0 deletions game.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
require "./player.rb"
require "./human_player.rb"
require "./computer_player.rb"

def get_user_input
gets.chomp
end

class Game
def initialize(player_1, player_2, ships = [2, 3, 3, 4, 5])
@player_1 = player_1
@player_2 = player_2
@ships = ships
@player_1_goes = true

end


def welcome
puts "Welcome, #{@player_1.name} and #{@player_2.name}!\nIt's time to play Battleship.\n"

end

def place_ships
@player_1.place_ships(@ships)
@player_2.place_ships(@ships)
end

def take_turn
if @player_1_goes || @player_2.class != ComputerPlayer
coord = get_user_input
else
coord = "A1"
end

if @player_1_goes
@player_1_goes = false
x = @player_2.board.x_of(coord)
y = @player_2.board.y_of(coord)
if @player_2.board.fire_at(x, y)
puts "Hit!"

# puts @player_1.target_board.hits
@player_1.target_board.hits << [x, y]
# puts @player_1.target_board.hits


if @player_2.board.sunk?
@game_over = true
puts "Congratulations, #{@player_1.name}!"
end
return
else
puts "Miss!"


# puts @player_1.target_board.misses
@player_1.target_board.misses << [x, y]
# puts @player_1.target_board.misses


return
end
else
@player_1_goes = true
x = @player_1.board.x_of(coord)
y = @player_1.board.y_of(coord)
if @player_1.board.fire_at(x, y)
puts "Hit!"


# puts @player_2.target_board.hits
@player_2.target_board.hits << [x, y]
# puts @player_2.target_board.hits


if @player_1.board.sunk?
@game_over = true
puts "Congratulations, #{@player_2.name}!"
end
return
else
puts "Miss!"


# puts @player_2.target_board.misses
@player_2.target_board.misses << [x,y]
# puts @player_2.target_board.misses


return
end
end
end

def play
self.welcome
self.place_ships
until @game_over == true
self.take_turn
end
end

end
Loading