sea_battle 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sea_battle.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 michal szyma
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # SeaBattle
2
+
3
+ Sea Battle is a guessing game for two players
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'sea_battle'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install sea_battle
18
+
19
+ ## Usage
20
+
21
+ Initialize board of the game
22
+
23
+ $ require "sea_battle"
24
+
25
+ $ board = SeaBattle::Board.new.board
26
+ $ board[0][3].is_attacked?
27
+
28
+ Add random ship on the board
29
+
30
+ $ require "random_ship"
31
+ ...
32
+
33
+ SeaBattle::RandomBoard.new(board, 3).add_ship
34
+
35
+ Play on console
36
+
37
+ $ sea_battle
38
+
39
+ #=> SEA BATTLE
40
+
41
+ #=> A B C D E F G H I J A B C D E F G H I J
42
+ #=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
43
+ #=> 0 │ │ │ │ │ │ │ │ ◯ │ │ │ 0 │ │ │ │ │ │ │ │ │ │ │
44
+ #=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
45
+ #=> 1 │ ◯ │ │ │ │ │ │ │ │ │ ◯ │ 1 │ │ │ │ │ │ │ │ │ │ │
46
+ #=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
47
+ #=> 2 │ ◯ │ │ │ │ │ │ │ │ │ ◯ │ 2 │ │ │ │ │ │ │ • │ • │ │ │
48
+ #=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
49
+ #=> 3 │ ◯ │ │ ⬤ │ ⬤ │ │ │ │ │ │ │ 3 │ │ │ │ │ │ │ │ • │ │ │
50
+ #=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
51
+ #=> 4 │ ⬤ │ │ │ │ │ ◯ │ │ │ │ │ 4 │ │ │ │ │ │ • │ │ │ │ │
52
+ #=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
53
+ #=> 5 │ │ │ ◯ │ │ │ ◯ │ │ │ │ ◯ │ 5 │ │ │ │ │ │ │ │ │ │ │
54
+ #=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
55
+ #=> 6 │ ◯ │ │ │ │ │ │ │ ◯ │ │ │ 6 │ │ │ │ │ │ │ │ │ │ │
56
+ #=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
57
+ #=> 7 │ │ │ ◯ │ │ │ │ │ ◯ │ │ │ 7 │ │ │ │ │ │ │ │ │ │ │
58
+ #=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
59
+ #=> 8 │ │ │ ◯ │ │ │ │ │ ◯ │ │ │ 8 │ │ │ │ │ │ │ │ │ │ │
60
+ #=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
61
+ #=> 9 │ │ │ ◯ │ │ │ │ │ │ │ │ 9 │ │ │ │ │ │ │ │ │ │ │
62
+
63
+ #=> 4a, ... - select part of ship
64
+ #=> (e)xit of game
65
+
66
+ Use class SeaBattle
67
+
68
+ $ require "sea_battle"
69
+
70
+ $ first_board = SeaBattle::Board.new
71
+ $ second_board = SeaBattle::Board.new
72
+ $ SeaBattle.new(first_board, second_board)
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/sea_battle ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "sea_battle"
4
+
5
+ SeaBattle::GUI.new.play
@@ -0,0 +1,99 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative "cell"
4
+ require_relative "random_ship"
5
+
6
+ class SeaBattle
7
+ # It's Board of game Sea Battle
8
+ class Board
9
+
10
+ attr_reader :board, :vertical, :horizontal, :status
11
+
12
+ def initialize(board = "1" * 100, status = :initialized)
13
+ @board = board.split("").map do |status|
14
+ Cell.new(status.to_i)
15
+ end.each_slice(10).to_a
16
+ @horizontal = 10
17
+ @vertical = 10
18
+
19
+ @status = status
20
+ @quantity_ships = {1 => 4, 2 => 3, 3 => 2, 4 => 1}
21
+ check_board
22
+ end
23
+
24
+ def activated_board
25
+ @status = :activated
26
+ end
27
+
28
+ def attack(row, column)
29
+ board[row][column].attack
30
+ end
31
+
32
+ def is_in_ship?(row, column)
33
+ board[row][column].is_in_ship?
34
+ end
35
+
36
+ # Set ships on the board (random positions)
37
+ def random_ships
38
+ return unless @status == :initialized
39
+ reset_board
40
+ [1, 1, 1, 1, 2, 2, 2, 3, 3, 4].each do |length|
41
+ RandomShip.new(self, length).add_ship
42
+ end
43
+ end
44
+
45
+ # Return array of position ship if it will be on position [row, column]
46
+ def ship_positions(row, column)
47
+ horizontal = horizontal_ship_position(row, column)
48
+ vertical = vertical_ship_position(row, column)
49
+ return horizontal if horizontal.size > vertical.size
50
+ vertical
51
+ end
52
+
53
+ private
54
+
55
+ # It should raise error when @board isn't Array
56
+ def check_board
57
+ raise "The board is not Array class" unless @board.size == 10
58
+ end
59
+
60
+ # it should return array of ship position
61
+ # for horizontal line with position [row, column]
62
+ def horizontal_ship_position(row, column)
63
+ result = []
64
+ 10.times do |position|
65
+ if @board[position][column].is_in_ship?
66
+ result << [position, column]
67
+ else
68
+ break if result.include?([row, column])
69
+ result = []
70
+ end
71
+ end
72
+ result
73
+ end
74
+
75
+ def reset_board
76
+ board.each do |line|
77
+ line.each do |cell|
78
+ cell.reset_cell
79
+ end
80
+ end
81
+ end
82
+
83
+ # it should return array of ship position
84
+ # for vertical line with position [row, column]
85
+ def vertical_ship_position(row, column)
86
+ result = []
87
+ 10.times do |position|
88
+ if @board[row][position].is_in_ship?
89
+ result << [row, position]
90
+ else
91
+ break if result.include?([row, column])
92
+ result = []
93
+ end
94
+ end
95
+ result
96
+ end
97
+
98
+ end
99
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ class SeaBattle
4
+ # It's Cell of Board
5
+ class Cell
6
+
7
+ attr_reader :status
8
+
9
+ # status value:
10
+ # 1 -> empty field
11
+ # 2 -> field is part of ship
12
+ # 4 -> attacked field
13
+ # 8 -> is only selected by user
14
+ # 6 -> attacked field and exsist ship
15
+ def initialize(status = 1)
16
+ @status = status
17
+ end
18
+
19
+ def add_ship
20
+ @status += 2 unless is_in_ship?
21
+ end
22
+
23
+ def attack
24
+ @status += 4 unless is_attacked?
25
+ end
26
+
27
+ def switch_select
28
+ is_selected? ? @status -= 8 : @status += 8
29
+ end
30
+
31
+ def is_attacked?
32
+ @status & 4 == 4
33
+ end
34
+
35
+ def is_empty?
36
+ @status & 1 == 1
37
+ end
38
+
39
+ def is_in_ship?
40
+ @status & 2 == 2
41
+ end
42
+
43
+ def is_selected?
44
+ @status & 8 == 8
45
+ end
46
+
47
+ def reset_cell
48
+ @status = 1
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,112 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative "board"
4
+ require_relative "version"
5
+ require_relative "../sea_battle"
6
+
7
+ class SeaBattle
8
+ # User can play with computer on console
9
+ class GUI
10
+
11
+ def initialize
12
+ @user_board = ::SeaBattle::Board.new
13
+ @computer_board = ::SeaBattle::Board.new
14
+ @computer_board.random_ships
15
+ @computer_board.activated_board
16
+ @sea_battle = ::SeaBattle.new(@user_board, @computer_board)
17
+ set_default_keyboard
18
+ end
19
+
20
+ def play
21
+ while true and not @keyboard[:exit]
22
+ system "clear"
23
+ show_boards
24
+ get_input
25
+ if @keyboard[:position]
26
+ @sea_battle.move(:first_player, :attack, @row, @column)
27
+ system "clear"
28
+ show_boards
29
+ while @sea_battle.active_user == :second_player
30
+ sleep 1 + rand
31
+ @sea_battle.move(:second_player, :attack, rand(10), rand(10))
32
+ system "clear"
33
+ show_boards
34
+ end
35
+ @keyboard[:position] = false
36
+ end
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def set_default_keyboard
43
+ @keyboard = {
44
+ exit: false,
45
+ activate: false,
46
+ position: nil
47
+ }
48
+ end
49
+
50
+ def show_boards
51
+ show_title
52
+
53
+ puts ""
54
+ puts " A B C D E F G H I J A B C D E F G H I J"
55
+ @user_board.board.each_with_index do |line, index|
56
+ user_line = line.map do |cell|
57
+ if cell.is_attacked? and cell.is_in_ship?
58
+ " ⬤ "
59
+ elsif cell.is_attacked? and not cell.is_in_ship?
60
+ " • "
61
+ elsif not cell.is_attacked? and cell.is_in_ship?
62
+ " ◯ "
63
+ else
64
+ " "
65
+ end
66
+ end.join("│")
67
+ computer_line = @computer_board.board[index].map do |cell|
68
+ if cell.is_attacked? and cell.is_in_ship?
69
+ " ⬤ "
70
+ elsif cell.is_attacked? and not cell.is_in_ship?
71
+ " • "
72
+ else
73
+ " "
74
+ end
75
+ end.join("│")
76
+ puts " ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼"
77
+ puts "#{index} │#{user_line}│ #{index} │#{computer_line}│"
78
+ end
79
+ end
80
+
81
+ def show_title
82
+ puts ""
83
+ puts "#{' '*10}SEA BATTLE ver#{VERSION}"
84
+ end
85
+
86
+ def get_input
87
+ puts ""
88
+ puts "4a, ... - select part of ship"
89
+ unless @keyboard[:activate]
90
+ puts "(r)andom your ships on board"
91
+ puts "(a)ctivate your game if all ships are at properly place"
92
+ end
93
+ puts "(e)xit of game"
94
+ keyboard = gets.chomp
95
+ @keyboard[:exit] = true if keyboard == "e"
96
+ if not @keyboard[:exit] and @keyboard[:activate]
97
+ @keyboard[:position] = true
98
+ @row, @column = keyboard.split("")
99
+ @column = @column.ord - 97
100
+ @row = @row.to_i
101
+ end
102
+ if keyboard == "a"
103
+
104
+ @keyboard[:activate] = true
105
+ @user_board.activated_board
106
+
107
+ end
108
+ @user_board.random_ships if keyboard == "r"
109
+ end
110
+
111
+ end
112
+ end
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ class SeaBattle
5
+ # It's random positions for new ship
6
+ class RandomShip
7
+
8
+ def initialize(board, length = 1)
9
+ @board = board.board
10
+ @length = length
11
+ @horizontal = board.horizontal
12
+ @vertical = board.vertical
13
+ end
14
+
15
+ # Add new Ship on board
16
+ def add_ship
17
+ if Random.rand(2) == 0
18
+ return if add_ship_of(:vertical)
19
+ return if add_ship_of(:horizontal)
20
+ else
21
+ return if add_ship_of(:horizontal)
22
+ return if add_ship_of(:vertical)
23
+ end
24
+ end
25
+
26
+ def ship_positions(row, column, direct)
27
+ result = []
28
+
29
+ @length.times do |offset|
30
+ if direct.eql?(:vertical)
31
+ result << [row + offset, column] if row + offset < @vertical
32
+ else
33
+ result << [row, column + offset] if column + offset < @horizontal
34
+ end
35
+ end
36
+ result
37
+ end
38
+
39
+ def area_ship_positions(row, column, direct)
40
+ result = []
41
+ first_row = row - 1
42
+ first_column = column - 1
43
+
44
+ last_row, last_column = row + 1, column + 1
45
+ last_row += @length - 1 if direct.eql?(:vertical)
46
+ last_column += @length - 1 if direct.eql?(:horizontal)
47
+
48
+ vertical_range = (first_row..last_row).to_a & (0...@vertical).to_a
49
+ horizontal_range = (first_column..last_column).to_a & (0...@horizontal).to_a
50
+ vertical_range.product(horizontal_range)
51
+ end
52
+
53
+ def mixed_board_positions
54
+ offset = Random.rand(@horizontal * @vertical)
55
+ (0...@vertical).to_a.product(
56
+ (0...@horizontal).to_a
57
+ ).rotate(offset)
58
+ end
59
+
60
+ def add_ship_of(direct)
61
+ mixed_board_positions.each do |row, column|
62
+ next if direct.eql?(:vertical) and row + @length - 1 >= @vertical
63
+ next if direct.eql?(:horizontal) and column + @length - 1 >= @horizontal
64
+
65
+ if is_area_empty?(row, column, direct)
66
+ positions = ship_positions(row, column, direct)
67
+ positions.map do |row, column|
68
+ @board[row][column].add_ship
69
+ end
70
+ return positions
71
+ end
72
+ end
73
+ nil
74
+ end
75
+
76
+ def is_area_empty?(row, column, direct)
77
+ area_ship_positions(row, column, direct).each do |row_index, column_index|
78
+ return false if @board[row_index][column_index].is_in_ship?
79
+ end
80
+ true
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,3 @@
1
+ class SeaBattle
2
+ VERSION = "0.1.1"
3
+ end
data/lib/sea_battle.rb ADDED
@@ -0,0 +1,65 @@
1
+ require "sea_battle/version"
2
+ require "sea_battle/board"
3
+ require "sea_battle/gui"
4
+
5
+ class SeaBattle
6
+
7
+ def initialize(first_board, second_board, last_attack_move = nil)
8
+ @last_attack_move = last_attack_move.split(";") unless last_attack_move.nil?
9
+ @first_board = first_board
10
+ @second_board = second_board
11
+ end
12
+
13
+ def active_user
14
+ return :first_player if @last_attack_move.nil?
15
+ player, row, column = @last_attack_move
16
+ if player.to_sym == :first_player
17
+ if @second_board.is_in_ship?(row.to_i, column.to_i)
18
+ return :first_player
19
+ else
20
+ return :second_player
21
+ end
22
+ else
23
+ if @first_board.is_in_ship?(row.to_i, column.to_i)
24
+ return :second_player
25
+ else
26
+ return :first_player
27
+ end
28
+ end
29
+ end
30
+
31
+ def last_attack_move
32
+ return if @last_attack_move.nil?
33
+ @last_attack_move.join(";")
34
+ end
35
+
36
+ def move(player, type, row, column)
37
+ return false unless [:first_player, :second_player].include?(player)
38
+ return false unless [:choose, :attack, :mark].include?(type)
39
+
40
+ case type
41
+ when :attack
42
+ return false unless active_user == player
43
+ return false unless first_status.eql?(:activated) and second_status.eql?(:activated)
44
+ if player == :first_player
45
+ @second_board.attack(row, column)
46
+ else
47
+ @first_board.attack(row, column)
48
+ end
49
+ @last_attack_move = [player, row, column]
50
+ else
51
+ end
52
+ true
53
+ end
54
+
55
+ private
56
+
57
+ def first_status
58
+ @first_board.status
59
+ end
60
+
61
+ def second_status
62
+ @second_board.status
63
+ end
64
+
65
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sea_battle/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sea_battle"
8
+ spec.version = SeaBattle::VERSION
9
+ spec.authors = ["Michał Szyma"]
10
+ spec.email = ["raglub.ruby@gmail.com"]
11
+ spec.description = %q{Sea Battle is a guessing game for two players}
12
+ spec.summary = %q{It is a popular game Battleship}
13
+ spec.homepage = "https://github.com/raglub/sea_battle"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_dependency "rspec", ">= 2.0.0"
23
+ spec.add_dependency "rspec_progress"
24
+ spec.add_development_dependency "rake"
25
+ end
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ require "sea_battle"
4
+ describe SeaBattle::Board do
5
+
6
+ let(:klass) { SeaBattle::Board }
7
+
8
+ it "should properly initialize class" do
9
+ expect { SeaBattle::Board.new }.to_not raise_error
10
+ end
11
+
12
+ it "should not properly initialize class" do
13
+ expect { SeaBattle::Board.new("") }.to raise_error
14
+ end
15
+
16
+ context "should check method ship_positions"do
17
+
18
+ it "for non-ship" do
19
+ board = "0"*100
20
+ board[2] = "2"
21
+ board[3] = "2"
22
+
23
+ klass.new(board).ship_positions(1, 2).should eq([])
24
+ end
25
+
26
+ it "for horizontal ship" do
27
+ board = "1"*100
28
+ board[2] = "2"
29
+ board[3] = "2"
30
+ klass.new(board).ship_positions(0, 2).should eq([[0, 2], [0, 3]])
31
+ end
32
+
33
+ it "for vertical ship" do
34
+ board = "0"*100
35
+ board[23] = "2"
36
+ board[33] = "2"
37
+ klass.new(board).ship_positions(2, 3).should eq([[2, 3] ,[3, 3]])
38
+ end
39
+
40
+ end
41
+
42
+ context "should add new ship in random position" do
43
+
44
+ let(:board) { klass.new }
45
+
46
+ it "should spred randomly ships on the board" do
47
+ board.random_ships
48
+ result = 0
49
+ board.board.flatten.each do |cell|
50
+ result += 1 if cell.is_in_ship?
51
+ end
52
+ result.should eq(20)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ require "sea_battle"
4
+
5
+ describe SeaBattle::Cell do
6
+
7
+ let(:klass) { SeaBattle::Cell }
8
+
9
+ it "should properly initialize class" do
10
+ expect { klass.new(1) }.to_not raise_error
11
+ end
12
+
13
+ it "should check method is_attacted?" do
14
+ klass.new(1).is_attacked?.should be_false
15
+ klass.new(4).is_attacked?.should be_true
16
+ end
17
+
18
+ it "should check method attack" do
19
+ cell = klass.new(1)
20
+ cell.is_attacked?.should be_false
21
+ cell.attack
22
+ cell.is_attacked?.should be_true
23
+ end
24
+
25
+ it "should check method is_empty?" do
26
+ klass.new(1).is_empty?.should be_true
27
+ klass.new(5).is_empty?.should be_true
28
+ end
29
+
30
+ it "should check method is_in_ship?" do
31
+ klass.new(1).is_in_ship?.should be_false
32
+ klass.new(2).is_in_ship?.should be_true
33
+ klass.new(3).is_in_ship?.should be_true
34
+ end
35
+
36
+ it "should check method is_selected?" do
37
+ klass.new(1).is_selected?.should be_false
38
+ klass.new(2).is_selected?.should be_false
39
+ klass.new(8).is_selected?.should be_true
40
+ end
41
+
42
+ it "should check method switch_select" do
43
+ cell = klass.new(1)
44
+ cell.is_selected?.should be_false
45
+ cell.switch_select
46
+ cell.is_selected?.should be_true
47
+ cell.switch_select
48
+ cell.is_selected?.should be_false
49
+ end
50
+
51
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require "sea_battle"
4
+ def puts(message)
5
+ @@content ||= ""
6
+ @@content << message
7
+ end
8
+
9
+ def reset_content
10
+ @@content = ""
11
+ end
12
+
13
+ def content
14
+ @@content
15
+ end
16
+
17
+ def sleep(value)
18
+ end
19
+
20
+ def system(value)
21
+ end
22
+
23
+ describe SeaBattle::GUI do
24
+
25
+ it "should let user exit from game" do
26
+ gui = SeaBattle::GUI.new
27
+ gui.stub(:gets).and_return("e")
28
+ reset_content
29
+ gui.play
30
+ content.should include("(r)andom your ships on board")
31
+ end
32
+
33
+ it "should let to random user's ships" do
34
+ gui = SeaBattle::GUI.new
35
+ gui.stub(:gets).and_return("r", "e")
36
+ reset_content
37
+ gui.play
38
+ content.should include("◯")
39
+ end
40
+
41
+ it "should let user attacked field 2b" do
42
+ gui = SeaBattle::GUI.new
43
+ gui.stub(:gets).and_return("a", "2b", "7c", "3a", "e")
44
+ reset_content
45
+ gui.play
46
+ content.scan(/•|⬤/ ).should_not be_empty
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,98 @@
1
+ # encoding: utf-8
2
+
3
+ require "sea_battle"
4
+
5
+ describe SeaBattle::RandomShip do
6
+
7
+ let(:board) { SeaBattle::Board.new("1"*100) }
8
+
9
+ let(:object) { klass.new(board) }
10
+
11
+ let(:klass) { SeaBattle::RandomShip }
12
+
13
+ context "#area_positions_with" do
14
+ it "for vertical in centre position" do
15
+ klass.new(board, 3).area_ship_positions(2, 3, :vertical).should eq([
16
+ [1, 2], [1, 3], [1, 4],
17
+ [2, 2], [2, 3], [2, 4],
18
+ [3, 2], [3, 3], [3, 4],
19
+ [4, 2], [4, 3], [4, 4],
20
+ [5, 2], [5, 3], [5, 4]
21
+ ])
22
+ end
23
+
24
+ it "for vertical in right position" do
25
+ klass.new(board, 1).area_ship_positions(5, 9, :vertical).should eq([
26
+ [4, 8], [4, 9],
27
+ [5, 8], [5, 9],
28
+ [6, 8], [6, 9]
29
+ ])
30
+ end
31
+
32
+ it "for horizontal in centre position" do
33
+ klass.new(board, 2).area_ship_positions(3, 4, :horizontal).should eq([
34
+ [2, 3], [2, 4], [2, 5], [2, 6],
35
+ [3, 3], [3, 4], [3, 5], [3, 6],
36
+ [4, 3], [4, 4], [4, 5], [4, 6]
37
+ ])
38
+ end
39
+
40
+ end
41
+
42
+ it "should check method ship_positions for vertical" do
43
+ klass.new(board, 3).ship_positions(2, 3, :vertical).should eq([
44
+ [2, 3], [3, 3], [4, 3]
45
+ ])
46
+
47
+ klass.new(board, 3).ship_positions(2, 3, :horizontal).should eq([
48
+ [2, 3], [2, 4], [2, 5]
49
+ ])
50
+ end
51
+
52
+ it "should check method is_area_empty?" do
53
+ klass.new(board, 2).is_area_empty?(3, 3, :vertical).should be_true
54
+ end
55
+
56
+ it "should check method mixed_board_positions" do
57
+ Random.stub(:rand).with(10 * 10) { 34 }
58
+ klass.new(board, 4).mixed_board_positions.first.should eq([3, 4])
59
+ end
60
+
61
+ context "for method #add_ship_of(:vertical)"do
62
+ it "in centre of board" do
63
+ Random.stub(:rand).with(10 * 10) { 34 }
64
+ klass.new(board, 2).add_ship_of(:vertical).should eq([[3, 4], [4, 4]])
65
+ board.board[4][4].is_in_ship?.should be_true
66
+ end
67
+
68
+ it "in bottom of board" do
69
+ Random.stub(:rand).with(10 * 10) { 93 }
70
+ klass.new(board, 2).add_ship_of(:vertical).should eq([[0, 0], [1, 0]])
71
+ board.board[1][0].is_in_ship?.should be_true
72
+ end
73
+
74
+ it "in bottom of board" do
75
+ Random.stub(:rand).with(10 * 10) { 93 }
76
+ klass.new(board, 2).add_ship_of(:vertical).should eq([[0, 0], [1, 0]])
77
+ board.board[1][0].is_in_ship?.should be_true
78
+ end
79
+
80
+ end
81
+
82
+ it "should check method #add_ship_of(:horizontal)" do
83
+ Random.stub(:rand).with(10 * 10) { 54 }
84
+ klass.new(board, 2).add_ship_of(:horizontal).should eq([[5, 4], [5, 5]])
85
+ board.board[5][5].is_in_ship?.should be_true
86
+ end
87
+
88
+ it "should check method #add_ship" do
89
+ Random.stub(:rand).with(2) { 0 }
90
+ Random.stub(:rand).with(10 * 10) { 54 }
91
+ klass.new(board, 2).add_ship
92
+ board.board[6][4].is_in_ship?.should be_true
93
+
94
+ klass.new(board, 2).add_ship
95
+ board.board[6][6].is_in_ship?.should be_true
96
+ end
97
+
98
+ end
@@ -0,0 +1,88 @@
1
+ # encoding: utf-8
2
+
3
+ require "sea_battle"
4
+
5
+ describe SeaBattle do
6
+
7
+ let(:board) { SeaBattle::Board }
8
+
9
+ # ABCDEFGHIJ
10
+ # 1 *
11
+ # 2 **** *
12
+ # 3
13
+ # 4 * *
14
+ # 5* * *
15
+ # 6 *
16
+ # 7
17
+ # 8 ***
18
+ # 9 ** *
19
+ # 10 * *
20
+ let(:first_raw_board) {
21
+ "1111111121" +
22
+ "1222211121" +
23
+ "1111111111" +
24
+ "1111112112" +
25
+ "2112112111" +
26
+ "1111112111" +
27
+ "1111111111" +
28
+ "1222111111" +
29
+ "1111122112" +
30
+ "1211111112"
31
+ }
32
+ it "should properly initialize class" do
33
+ expect { SeaBattle.new(board.new, board.new) }.to_not raise_error
34
+ end
35
+
36
+ context "for preparation game" do
37
+ it "should not attack player one if game isn't active" do
38
+ board_zero = board.new(first_raw_board, :initialized)
39
+ board_one = board.new(first_raw_board, :initialized)
40
+ sea_battle = SeaBattle.new(board_zero, board_one, nil)
41
+ sea_battle.move(:first_player, :attack, 2, 1)
42
+ sea_battle.last_attack_move.should eq(nil)
43
+ end
44
+ end
45
+
46
+ context "for active game (first move)" do
47
+ let(:board_zero) { board.new(first_raw_board, :activated) }
48
+ let(:board_one) { board.new(first_raw_board, :activated) }
49
+ let(:sea_battle) { SeaBattle.new(board_zero, board_one, nil) }
50
+
51
+ it "should properly attack second player" do
52
+ sea_battle.move(:first_player, :attack, 1, 2).should be_true
53
+ sea_battle.last_attack_move.should eql("first_player;1;2")
54
+ end
55
+
56
+ it "shouldn't properly attack first player" do
57
+ sea_battle.move(:second_player, :attack, 1, 2).should be_false
58
+ sea_battle.last_attack_move.should eql(nil)
59
+ end
60
+
61
+ it "should get first_player" do
62
+ sea_battle.active_user.should eql(:first_player)
63
+ end
64
+ end
65
+
66
+ context "for active game and first player correctly attacked competition ship then" do
67
+
68
+ let(:board_zero) { board.new(first_raw_board, :activated) }
69
+ let(:board_one) { board.new(first_raw_board, :activated) }
70
+ let(:sea_battle) { SeaBattle.new(board_zero, board_one, "first_player;1;1") }
71
+
72
+ it "first player should properly attack second player" do
73
+ sea_battle.move(:first_player, :attack, 1, 2).should be_true
74
+ sea_battle.last_attack_move.should eql("first_player;1;2")
75
+ end
76
+
77
+ it "second player shouldn't properly attack first player" do
78
+ sea_battle.move(:second_player, :attack, 1, 2).should be_false
79
+ sea_battle.last_attack_move.should eql("first_player;1;1")
80
+ end
81
+
82
+ it "should get first_player" do
83
+ sea_battle.active_user.should eql(:first_player)
84
+ end
85
+
86
+ end
87
+
88
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sea_battle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Michał Szyma
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 2.0.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 2.0.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec_progress
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: Sea Battle is a guessing game for two players
79
+ email:
80
+ - raglub.ruby@gmail.com
81
+ executables:
82
+ - sea_battle
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - .rspec
88
+ - Gemfile
89
+ - LICENSE.txt
90
+ - README.md
91
+ - Rakefile
92
+ - bin/sea_battle
93
+ - lib/sea_battle.rb
94
+ - lib/sea_battle/board.rb
95
+ - lib/sea_battle/cell.rb
96
+ - lib/sea_battle/gui.rb
97
+ - lib/sea_battle/random_ship.rb
98
+ - lib/sea_battle/version.rb
99
+ - sea_battle.gemspec
100
+ - spec/sea_battle/board_spec.rb
101
+ - spec/sea_battle/cell_spec.rb
102
+ - spec/sea_battle/gui_spec.rb
103
+ - spec/sea_battle/random_ship_spec.rb
104
+ - spec/sea_battle_spec.rb
105
+ homepage: https://github.com/raglub/sea_battle
106
+ licenses:
107
+ - MIT
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 1.8.24
127
+ signing_key:
128
+ specification_version: 3
129
+ summary: It is a popular game Battleship
130
+ test_files:
131
+ - spec/sea_battle/board_spec.rb
132
+ - spec/sea_battle/cell_spec.rb
133
+ - spec/sea_battle/gui_spec.rb
134
+ - spec/sea_battle/random_ship_spec.rb
135
+ - spec/sea_battle_spec.rb