sea_battle 0.1.1 → 0.1.3
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/README.md +60 -35
- data/lib/sea_battle/board.rb +65 -8
- data/lib/sea_battle/cell.rb +9 -0
- data/lib/sea_battle/gui.rb +122 -56
- data/lib/sea_battle/random_ship.rb +2 -7
- data/lib/sea_battle/support.rb +15 -0
- data/lib/sea_battle/version.rb +1 -1
- data/lib/sea_battle.rb +20 -0
- data/spec/sea_battle/board_spec.rb +60 -13
- data/spec/sea_battle/gui_spec.rb +1 -1
- data/spec/sea_battle_spec.rb +22 -1
- metadata +3 -2
data/README.md
CHANGED
@@ -18,55 +18,80 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
Initialize board of the game
|
21
|
+
### Initialize board of the game
|
22
22
|
|
23
23
|
$ require "sea_battle"
|
24
24
|
|
25
25
|
$ board = SeaBattle::Board.new.board
|
26
26
|
$ board[0][3].is_attacked?
|
27
27
|
|
28
|
-
Add random ship on the board
|
28
|
+
### Add random ship on the board
|
29
29
|
|
30
30
|
$ require "random_ship"
|
31
31
|
...
|
32
32
|
|
33
33
|
SeaBattle::RandomBoard.new(board, 3).add_ship
|
34
34
|
|
35
|
-
|
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
|
35
|
+
### Use class SeaBattle
|
67
36
|
|
68
37
|
$ require "sea_battle"
|
69
38
|
|
70
39
|
$ first_board = SeaBattle::Board.new
|
71
40
|
$ second_board = SeaBattle::Board.new
|
72
|
-
$ SeaBattle.new(first_board, second_board)
|
41
|
+
$ sea_battle = SeaBattle.new(first_board, second_board)
|
42
|
+
|
43
|
+
#### Game is activated?
|
44
|
+
$ sea_battle.is_activated?
|
45
|
+
|
46
|
+
#### You can get which player is active
|
47
|
+
$ sea_battle.active_user #=> :first_player
|
48
|
+
|
49
|
+
#### Ship on position row, column is sunken?
|
50
|
+
$ sea_battle.is_sunken_ship?(3, 7) #=> false
|
51
|
+
|
52
|
+
#### You can attack position (row, column)
|
53
|
+
$ sea_battle.move(:second_player, :attack, 2, 9)
|
54
|
+
|
55
|
+
#### When game is over you can see winner
|
56
|
+
$ sea_battle.winner_is #=> :first_player
|
57
|
+
|
58
|
+
### Play on console (min 92x40)
|
59
|
+
|
60
|
+
$ sea_battle
|
61
|
+
|
62
|
+
#=> SEA BATTLE
|
63
|
+
|
64
|
+
#=> A B C D E F G H I J A B C D E F G H I J
|
65
|
+
#=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
|
66
|
+
#=> 0 │ □ │ │ │ │ │ │ │ │ │ □ │ 0 │ │ │ │ │ │ │ │ │ │ │
|
67
|
+
#=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
|
68
|
+
#=> 1 │ □ │ │ □ │ │ □ │ │ │ ⬤/│ │ □ │ 1 │ │ │ │ │ │ • │ ⬤/│ │ │ │
|
69
|
+
#=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
|
70
|
+
#=> 2 │ □ │ │ │ │ ■ │ │ │ │ │ □ │ 2 │ │ │ │ │ │ │ ⬤/│ • │ • │ │
|
71
|
+
#=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
|
72
|
+
#=> 3 │ □ │ • │ │ │ □ │ • │ • │ │ │ │ 3 │ • │ │ │ │ │ │ ⬤/│ • │ • │ │
|
73
|
+
#=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
|
74
|
+
#=> 4 │ │ │ • │ │ │ │ │ □ │ │ │ 4 │ │ │ │ ⬤/│ ⬤/│ │ │ │ • │ │
|
75
|
+
#=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
|
76
|
+
#=> 5 │ │ • │ │ │ │ │ │ □ │ │ │ 5 │ │ │ │ │ │ │ │ • │ ⬤/│ │
|
77
|
+
#=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
|
78
|
+
#=> 6 │ │ │ • │ │ │ • │ │ │ • │ • │ 6 │ │ │ │ │ │ │ • │ │ • │ │
|
79
|
+
#=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
|
80
|
+
#=> 7 │ │ │ │ • │ │ │ │ • │ ■ │ │ 7 │ │ │ │ │ │ │ │ │ │ │
|
81
|
+
#=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
|
82
|
+
#=> 8 │ ⬤ │ │ │ • │ │ │ □ │ │ □ │ │ 8 │ │ • │ │ • │ ⬤/│ • │ │ │ │ │
|
83
|
+
#=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
|
84
|
+
#=> 9 │ ⬤ │ │ │ │ □ │ │ │ │ │ • │ 9 │ │ │ │ │ • │ │ │ │ │ │
|
85
|
+
#=> ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼ ┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼
|
86
|
+
|
87
|
+
#=> 09:49:09 Computer: Moved on position 6j
|
88
|
+
#=> 09:49:11 You: Moved on position 9e
|
89
|
+
#=> 09:49:13 Computer: Moved on position 3b
|
90
|
+
#=> 09:49:15 You: Used incorrect command: a
|
91
|
+
#=> ____________________________________________________________
|
92
|
+
#=> ⬤/ - sunk ship; ■ - hit ship; □ - selected ship; • - mishit
|
93
|
+
|
94
|
+
#=> (r)andom position into attack
|
95
|
+
#=> 4a, 8i, ... - select part of ship
|
96
|
+
#=> (e)xit of game
|
97
|
+
#=> #=>
|
data/lib/sea_battle/board.rb
CHANGED
@@ -2,37 +2,77 @@
|
|
2
2
|
|
3
3
|
require_relative "cell"
|
4
4
|
require_relative "random_ship"
|
5
|
+
require_relative "support"
|
5
6
|
|
6
7
|
class SeaBattle
|
7
8
|
# It's Board of game Sea Battle
|
8
9
|
class Board
|
10
|
+
include ::SeaBattle::Support
|
9
11
|
|
10
12
|
attr_reader :board, :vertical, :horizontal, :status
|
11
13
|
|
12
14
|
def initialize(board = "1" * 100, status = :initialized)
|
13
|
-
@
|
14
|
-
|
15
|
-
|
16
|
-
@horizontal = 10
|
17
|
-
@vertical = 10
|
15
|
+
@horizontal, @vertical = 10, 10
|
16
|
+
|
17
|
+
load_board(board)
|
18
18
|
|
19
19
|
@status = status
|
20
|
-
@quantity_ships = {1 => 4, 2 => 3, 3 => 2, 4 => 1}
|
21
20
|
check_board
|
22
21
|
end
|
23
22
|
|
24
|
-
|
23
|
+
# When all ships are on board then board can be activated
|
24
|
+
# Return true when board was activated
|
25
|
+
def activate_board
|
26
|
+
result = 0
|
27
|
+
@board.flatten.each do |cell|
|
28
|
+
result += 1 if cell.is_in_ship?
|
29
|
+
end
|
30
|
+
return false unless result == 20
|
25
31
|
@status = :activated
|
32
|
+
true
|
26
33
|
end
|
27
34
|
|
28
35
|
def attack(row, column)
|
29
|
-
|
36
|
+
if @status == :activated
|
37
|
+
board[row][column].attack
|
38
|
+
is_sunken_ship?(row, column)
|
39
|
+
is_finished?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def is_attacked?(row, column)
|
44
|
+
board[row][column].is_attacked?
|
30
45
|
end
|
31
46
|
|
32
47
|
def is_in_ship?(row, column)
|
33
48
|
board[row][column].is_in_ship?
|
34
49
|
end
|
35
50
|
|
51
|
+
# Return true if on position (row, column) is the ship which is sunked
|
52
|
+
# Return false if on position (row, column) is not the ship which is sunked
|
53
|
+
# or don't exist the ship
|
54
|
+
def is_sunken_ship?(row, column)
|
55
|
+
positions = ship_positions(row, column)
|
56
|
+
return false if positions.empty?
|
57
|
+
is_sunk = true
|
58
|
+
positions.each do |position_row, position_column|
|
59
|
+
is_sunk = false unless board[position_row][position_column].is_attacked?
|
60
|
+
end
|
61
|
+
if is_sunk
|
62
|
+
positions.each do |position_row, position_column|
|
63
|
+
board[position_row][position_column].sunk
|
64
|
+
end
|
65
|
+
end
|
66
|
+
is_sunk
|
67
|
+
end
|
68
|
+
|
69
|
+
# Return position to attack (have not attacked)
|
70
|
+
def random_position
|
71
|
+
mixed_board_positions.each do |row, column|
|
72
|
+
return [row, column] unless is_attacked?(row, column)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
36
76
|
# Set ships on the board (random positions)
|
37
77
|
def random_ships
|
38
78
|
return unless @status == :initialized
|
@@ -57,6 +97,17 @@ class SeaBattle
|
|
57
97
|
raise "The board is not Array class" unless @board.size == 10
|
58
98
|
end
|
59
99
|
|
100
|
+
def is_finished?
|
101
|
+
is_finished = true
|
102
|
+
board.each do |line|
|
103
|
+
line.each do |cell|
|
104
|
+
is_finished = false if cell.is_in_ship? and not cell.is_sunk?
|
105
|
+
end
|
106
|
+
end
|
107
|
+
@status = :finished if is_finished
|
108
|
+
is_finished
|
109
|
+
end
|
110
|
+
|
60
111
|
# it should return array of ship position
|
61
112
|
# for horizontal line with position [row, column]
|
62
113
|
def horizontal_ship_position(row, column)
|
@@ -72,6 +123,12 @@ class SeaBattle
|
|
72
123
|
result
|
73
124
|
end
|
74
125
|
|
126
|
+
def load_board(board)
|
127
|
+
@board = board.split("").map do |status|
|
128
|
+
Cell.new(status.to_i)
|
129
|
+
end.each_slice(10).to_a
|
130
|
+
end
|
131
|
+
|
75
132
|
def reset_board
|
76
133
|
board.each do |line|
|
77
134
|
line.each do |cell|
|
data/lib/sea_battle/cell.rb
CHANGED
@@ -11,6 +11,7 @@ class SeaBattle
|
|
11
11
|
# 2 -> field is part of ship
|
12
12
|
# 4 -> attacked field
|
13
13
|
# 8 -> is only selected by user
|
14
|
+
#16 -> is sunk
|
14
15
|
# 6 -> attacked field and exsist ship
|
15
16
|
def initialize(status = 1)
|
16
17
|
@status = status
|
@@ -24,6 +25,10 @@ class SeaBattle
|
|
24
25
|
@status += 4 unless is_attacked?
|
25
26
|
end
|
26
27
|
|
28
|
+
def sunk
|
29
|
+
@status += 16 unless is_sunk?
|
30
|
+
end
|
31
|
+
|
27
32
|
def switch_select
|
28
33
|
is_selected? ? @status -= 8 : @status += 8
|
29
34
|
end
|
@@ -44,6 +49,10 @@ class SeaBattle
|
|
44
49
|
@status & 8 == 8
|
45
50
|
end
|
46
51
|
|
52
|
+
def is_sunk?
|
53
|
+
@status & 16 == 16
|
54
|
+
end
|
55
|
+
|
47
56
|
def reset_cell
|
48
57
|
@status = 1
|
49
58
|
end
|
data/lib/sea_battle/gui.rb
CHANGED
@@ -12,26 +12,26 @@ class SeaBattle
|
|
12
12
|
@user_board = ::SeaBattle::Board.new
|
13
13
|
@computer_board = ::SeaBattle::Board.new
|
14
14
|
@computer_board.random_ships
|
15
|
-
@computer_board.
|
15
|
+
@computer_board.activate_board
|
16
16
|
@sea_battle = ::SeaBattle.new(@user_board, @computer_board)
|
17
17
|
set_default_keyboard
|
18
|
+
push_message("Initialized SeaBattle")
|
18
19
|
end
|
19
20
|
|
20
21
|
def play
|
21
22
|
while true and not @keyboard[:exit]
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
update_screen
|
24
|
+
user_command
|
25
|
+
next if @keyboard[:error]
|
25
26
|
if @keyboard[:position]
|
26
|
-
|
27
|
-
|
28
|
-
show_boards
|
27
|
+
attack_on(@row, @column, :first_player)
|
28
|
+
break unless @sea_battle.winner_is.nil?
|
29
29
|
while @sea_battle.active_user == :second_player
|
30
30
|
sleep 1 + rand
|
31
|
-
|
32
|
-
|
33
|
-
show_boards
|
31
|
+
row, column = @computer_board.random_position
|
32
|
+
attack_on(row, column, :second_player)
|
34
33
|
end
|
34
|
+
break unless @sea_battle.winner_is.nil?
|
35
35
|
@keyboard[:position] = false
|
36
36
|
end
|
37
37
|
end
|
@@ -39,73 +39,139 @@ class SeaBattle
|
|
39
39
|
|
40
40
|
private
|
41
41
|
|
42
|
+
def all_positions
|
43
|
+
(0..9).to_a.product(
|
44
|
+
(0..9).to_a.map do |column|
|
45
|
+
(column + 97).chr
|
46
|
+
end
|
47
|
+
).map { |row, column| "#{row}#{column}" }
|
48
|
+
end
|
49
|
+
|
50
|
+
def attack_on(row, column, active_player)
|
51
|
+
player_name = (active_player == :first_player ? "You" : "Computer")
|
52
|
+
@sea_battle.move(active_player, :attack, row, column)
|
53
|
+
push_message("Moved on position #{row}#{(97 + column).chr}", player_name)
|
54
|
+
if @sea_battle.is_sunken_ship?(row, column, active_player)
|
55
|
+
push_message("Sunk ship", player_name)
|
56
|
+
end
|
57
|
+
if @sea_battle.winner_is == active_player
|
58
|
+
push_message("WIN!!!", player_name)
|
59
|
+
end
|
60
|
+
update_screen
|
61
|
+
end
|
62
|
+
|
63
|
+
def board_line(board, index, player)
|
64
|
+
board.board[index].map do |cell|
|
65
|
+
if cell.is_attacked? and cell.is_in_ship?
|
66
|
+
unless cell.is_sunk?
|
67
|
+
" ■ "
|
68
|
+
else
|
69
|
+
" ⬤ "
|
70
|
+
end
|
71
|
+
elsif cell.is_attacked? and not cell.is_in_ship?
|
72
|
+
" • "
|
73
|
+
elsif not cell.is_attacked? and cell.is_in_ship? and player == :first_player
|
74
|
+
" □ "
|
75
|
+
else
|
76
|
+
" \u205f "
|
77
|
+
end
|
78
|
+
end.join("│")
|
79
|
+
end
|
80
|
+
|
81
|
+
def info_command
|
82
|
+
puts "⬤/ - sunk ship; ■ - hit ship; □ - selected ship; • - mishit"
|
83
|
+
puts ""
|
84
|
+
unless @sea_battle.is_activated?
|
85
|
+
puts "(r)andom your ships on board"
|
86
|
+
puts "(a)ctivate your game if all ships are at properly place"
|
87
|
+
else
|
88
|
+
puts "(r)andom position into attack"
|
89
|
+
puts "4a, 8i, ... - select part of ship"
|
90
|
+
end
|
91
|
+
puts "(e)xit of game"
|
92
|
+
print "#=> "
|
93
|
+
end
|
94
|
+
|
42
95
|
def set_default_keyboard
|
43
96
|
@keyboard = {
|
44
97
|
exit: false,
|
45
|
-
|
46
|
-
|
98
|
+
position: nil,
|
99
|
+
error: false
|
47
100
|
}
|
48
101
|
end
|
49
102
|
|
50
|
-
def
|
103
|
+
def update_screen
|
104
|
+
system "clear"
|
51
105
|
show_title
|
106
|
+
column_position = "A B C D E F G H I J"
|
107
|
+
end_of_board = "┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼"
|
52
108
|
|
53
|
-
puts ""
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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}│"
|
109
|
+
puts " #{column_position} #{column_position}"
|
110
|
+
(0..9).each do |index|
|
111
|
+
user_line = board_line(@user_board, index, :first_player)
|
112
|
+
computer_line = board_line(@computer_board, index, :second_player)
|
113
|
+
puts " #{end_of_board} #{end_of_board}"
|
114
|
+
puts " #{index} │#{user_line}│ #{index} │#{computer_line}│"
|
78
115
|
end
|
116
|
+
puts " #{end_of_board} #{end_of_board}\n \n"
|
117
|
+
show_messages
|
79
118
|
end
|
80
119
|
|
81
120
|
def show_title
|
82
121
|
puts ""
|
83
122
|
puts "#{' '*10}SEA BATTLE ver#{VERSION}"
|
123
|
+
puts ""
|
84
124
|
end
|
85
125
|
|
86
|
-
def
|
87
|
-
|
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"
|
126
|
+
def user_command
|
127
|
+
info_command
|
94
128
|
keyboard = gets.chomp
|
95
129
|
@keyboard[:exit] = true if keyboard == "e"
|
96
|
-
if
|
97
|
-
@keyboard[:
|
98
|
-
|
99
|
-
|
100
|
-
|
130
|
+
if @sea_battle.is_activated?
|
131
|
+
@keyboard[:error] = false
|
132
|
+
if all_positions.include?(keyboard)
|
133
|
+
@row, @column = keyboard.split("")
|
134
|
+
@column = @column.ord - 97
|
135
|
+
@row = @row.to_i
|
136
|
+
@keyboard[:position] = true
|
137
|
+
#if @computer_board.is_attacked?(@row, @column)
|
138
|
+
# @keyboard[:error] = true
|
139
|
+
# @keyboard[:position] = false
|
140
|
+
# push_message("Used incorrect command: #{keyboard}")
|
141
|
+
#end
|
142
|
+
elsif keyboard == "r"
|
143
|
+
@row, @column = @computer_board.random_position
|
144
|
+
@keyboard[:position] = true
|
145
|
+
else
|
146
|
+
@keyboard[:error] = true
|
147
|
+
push_message("Used incorrect command: #{keyboard}")
|
148
|
+
end
|
149
|
+
else
|
150
|
+
if keyboard == "a"
|
151
|
+
if @user_board.activate_board
|
152
|
+
push_message("Activated game")
|
153
|
+
else
|
154
|
+
push_message("Don't activated game!!!")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
if keyboard == "r"
|
159
|
+
@user_board.random_ships
|
160
|
+
push_message("Random ships")
|
161
|
+
end
|
101
162
|
end
|
102
|
-
|
163
|
+
end
|
103
164
|
|
104
|
-
|
105
|
-
|
165
|
+
def push_message(message, player = "You")
|
166
|
+
@messages ||= []
|
167
|
+
@messages = @messages.rotate(1)
|
168
|
+
@messages[3] = " #{Time.now.strftime("%H:%M:%S")} #{player}: #{message}"
|
169
|
+
end
|
106
170
|
|
107
|
-
|
108
|
-
@
|
171
|
+
def show_messages
|
172
|
+
@messages ||= []
|
173
|
+
puts @messages.compact.join("\n")
|
174
|
+
puts "_"*60
|
109
175
|
end
|
110
176
|
|
111
177
|
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require_relative "support"
|
3
4
|
|
4
5
|
class SeaBattle
|
5
6
|
# It's random positions for new ship
|
6
7
|
class RandomShip
|
8
|
+
include ::SeaBattle::Support
|
7
9
|
|
8
10
|
def initialize(board, length = 1)
|
9
11
|
@board = board.board
|
@@ -50,13 +52,6 @@ class SeaBattle
|
|
50
52
|
vertical_range.product(horizontal_range)
|
51
53
|
end
|
52
54
|
|
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
55
|
def add_ship_of(direct)
|
61
56
|
mixed_board_positions.each do |row, column|
|
62
57
|
next if direct.eql?(:vertical) and row + @length - 1 >= @vertical
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class SeaBattle
|
4
|
+
# Common methods
|
5
|
+
module Support
|
6
|
+
|
7
|
+
def mixed_board_positions
|
8
|
+
offset = Random.rand(@horizontal * @vertical)
|
9
|
+
(0...@vertical).to_a.product(
|
10
|
+
(0...@horizontal).to_a
|
11
|
+
).rotate(offset)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
data/lib/sea_battle/version.rb
CHANGED
data/lib/sea_battle.rb
CHANGED
@@ -28,12 +28,26 @@ class SeaBattle
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
def is_activated?
|
32
|
+
not first_status.eql?(:initialized) and not second_status.eql?(:initialized)
|
33
|
+
end
|
34
|
+
|
35
|
+
def is_sunken_ship?(row, column, player)
|
36
|
+
if player == :first_player
|
37
|
+
@second_board.is_sunken_ship?(row, column)
|
38
|
+
else
|
39
|
+
@first_board.is_sunken_ship?(row, column)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
31
43
|
def last_attack_move
|
32
44
|
return if @last_attack_move.nil?
|
33
45
|
@last_attack_move.join(";")
|
34
46
|
end
|
35
47
|
|
36
48
|
def move(player, type, row, column)
|
49
|
+
return false unless winner_is.nil?
|
50
|
+
|
37
51
|
return false unless [:first_player, :second_player].include?(player)
|
38
52
|
return false unless [:choose, :attack, :mark].include?(type)
|
39
53
|
|
@@ -52,6 +66,12 @@ class SeaBattle
|
|
52
66
|
true
|
53
67
|
end
|
54
68
|
|
69
|
+
def winner_is
|
70
|
+
return :second_player if first_status.eql? :finished
|
71
|
+
return :first_player if second_status.eql? :finished
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
|
55
75
|
private
|
56
76
|
|
57
77
|
def first_status
|
@@ -1,10 +1,26 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require "sea_battle"
|
4
|
+
|
4
5
|
describe SeaBattle::Board do
|
5
6
|
|
6
7
|
let(:klass) { SeaBattle::Board }
|
7
8
|
|
9
|
+
let(:raw_board) {
|
10
|
+
"1111111121" +
|
11
|
+
"1222211121" +
|
12
|
+
"1111111111" +
|
13
|
+
"1111112112" +
|
14
|
+
"2112112111" +
|
15
|
+
"1111112111" +
|
16
|
+
"1111111111" +
|
17
|
+
"1222111111" +
|
18
|
+
"1111122112" +
|
19
|
+
"1211111112"
|
20
|
+
}
|
21
|
+
|
22
|
+
let(:board) { SeaBattle::Board.new(raw_board) }
|
23
|
+
|
8
24
|
it "should properly initialize class" do
|
9
25
|
expect { SeaBattle::Board.new }.to_not raise_error
|
10
26
|
end
|
@@ -13,28 +29,28 @@ describe SeaBattle::Board do
|
|
13
29
|
expect { SeaBattle::Board.new("") }.to raise_error
|
14
30
|
end
|
15
31
|
|
32
|
+
context "should check method #activate_board" do
|
33
|
+
it "for empty board" do
|
34
|
+
SeaBattle::Board.new.activate_board.should be_false
|
35
|
+
end
|
36
|
+
|
37
|
+
it "for properly arranged ships on board" do
|
38
|
+
SeaBattle::Board.new(raw_board).activate_board.should be_true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
16
42
|
context "should check method ship_positions"do
|
17
43
|
|
18
44
|
it "for non-ship" do
|
19
|
-
board
|
20
|
-
board[2] = "2"
|
21
|
-
board[3] = "2"
|
22
|
-
|
23
|
-
klass.new(board).ship_positions(1, 2).should eq([])
|
45
|
+
board.ship_positions(6, 2).should eq([])
|
24
46
|
end
|
25
47
|
|
26
48
|
it "for horizontal ship" do
|
27
|
-
board
|
28
|
-
board[2] = "2"
|
29
|
-
board[3] = "2"
|
30
|
-
klass.new(board).ship_positions(0, 2).should eq([[0, 2], [0, 3]])
|
49
|
+
board.ship_positions(7, 2).should eq([[7, 1], [7, 2], [7, 3]])
|
31
50
|
end
|
32
51
|
|
33
52
|
it "for vertical ship" do
|
34
|
-
board
|
35
|
-
board[23] = "2"
|
36
|
-
board[33] = "2"
|
37
|
-
klass.new(board).ship_positions(2, 3).should eq([[2, 3] ,[3, 3]])
|
53
|
+
board.ship_positions(5, 6).should eq([[3, 6] ,[4, 6], [5, 6]])
|
38
54
|
end
|
39
55
|
|
40
56
|
end
|
@@ -52,4 +68,35 @@ describe SeaBattle::Board do
|
|
52
68
|
result.should eq(20)
|
53
69
|
end
|
54
70
|
end
|
71
|
+
|
72
|
+
context "should check method attack"do
|
73
|
+
|
74
|
+
it "for non-ship" do
|
75
|
+
board.activate_board
|
76
|
+
board.attack(0, 8)
|
77
|
+
board.board[0][8].is_sunk?.should be_false
|
78
|
+
board.attack(1, 8)
|
79
|
+
board.board[0][8].is_sunk?.should be_true
|
80
|
+
board.board[1][8].is_sunk?.should be_true
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
context "should random new position into attack" do
|
86
|
+
let(:active_board) do
|
87
|
+
result = raw_board
|
88
|
+
result[12] = "6"
|
89
|
+
result
|
90
|
+
end
|
91
|
+
|
92
|
+
let(:board) { SeaBattle::Board.new(active_board) }
|
93
|
+
|
94
|
+
it "for simply type" do
|
95
|
+
board.activate_board
|
96
|
+
Random.stub(:rand) { 12 }
|
97
|
+
board.random_position.should eql([1, 3])
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
55
102
|
end
|
data/spec/sea_battle/gui_spec.rb
CHANGED
data/spec/sea_battle_spec.rb
CHANGED
@@ -29,6 +29,7 @@ describe SeaBattle do
|
|
29
29
|
"1111122112" +
|
30
30
|
"1211111112"
|
31
31
|
}
|
32
|
+
|
32
33
|
it "should properly initialize class" do
|
33
34
|
expect { SeaBattle.new(board.new, board.new) }.to_not raise_error
|
34
35
|
end
|
@@ -64,7 +65,6 @@ describe SeaBattle do
|
|
64
65
|
end
|
65
66
|
|
66
67
|
context "for active game and first player correctly attacked competition ship then" do
|
67
|
-
|
68
68
|
let(:board_zero) { board.new(first_raw_board, :activated) }
|
69
69
|
let(:board_one) { board.new(first_raw_board, :activated) }
|
70
70
|
let(:sea_battle) { SeaBattle.new(board_zero, board_one, "first_player;1;1") }
|
@@ -85,4 +85,25 @@ describe SeaBattle do
|
|
85
85
|
|
86
86
|
end
|
87
87
|
|
88
|
+
context "for method winer_is" do
|
89
|
+
let(:first_board) { board.new(first_raw_board, :activated) }
|
90
|
+
let(:second_board) { board.new(first_raw_board, :activated) }
|
91
|
+
let(:sea_battle) { SeaBattle.new(first_board, second_board, nil) }
|
92
|
+
|
93
|
+
it "should return nil if no one win of game" do
|
94
|
+
sea_battle.winner_is.should be_nil
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should return :first_player if first player win of game" do
|
98
|
+
first_board.stub(:status) { :finished }
|
99
|
+
sea_battle.winner_is.should eq(:second_player)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should return :second_player if second player win of game" do
|
103
|
+
second_board.stub(:status) { :finished }
|
104
|
+
sea_battle.winner_is.should eq(:first_player)
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
88
109
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sea_battle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-07-
|
12
|
+
date: 2013-07-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -95,6 +95,7 @@ files:
|
|
95
95
|
- lib/sea_battle/cell.rb
|
96
96
|
- lib/sea_battle/gui.rb
|
97
97
|
- lib/sea_battle/random_ship.rb
|
98
|
+
- lib/sea_battle/support.rb
|
98
99
|
- lib/sea_battle/version.rb
|
99
100
|
- sea_battle.gemspec
|
100
101
|
- spec/sea_battle/board_spec.rb
|