sea_battle 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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