ang_ttt_gem 1.0.0 → 1.0.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/lib/ang_ttt_gem/ai.rb +12 -14
- data/lib/ang_ttt_gem/board.rb +13 -13
- data/lib/ang_ttt_gem/computer_player.rb +3 -3
- data/lib/ang_ttt_gem/game.rb +13 -20
- data/lib/ang_ttt_gem/human_player.rb +2 -2
- data/lib/ang_ttt_gem/message.rb +14 -14
- data/lib/ang_ttt_gem/player.rb +1 -1
- data/lib/ang_ttt_gem/scoring.rb +3 -3
- data/lib/ang_ttt_gem/validate.rb +3 -3
- metadata +1 -1
data/lib/ang_ttt_gem/ai.rb
CHANGED
@@ -2,28 +2,26 @@ require "scoring"
|
|
2
2
|
require "board"
|
3
3
|
|
4
4
|
class Ai
|
5
|
-
|
5
|
+
|
6
6
|
def initialize(player, board)
|
7
7
|
@board = board
|
8
8
|
@scoring = Scoring.new
|
9
9
|
@max_mark = player.mark
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def find_opponent_mark
|
13
13
|
state = @board.current_state
|
14
|
-
min_mark = state.reject {|c| c =~ /^#{@max_mark}|\s{1}$/ }
|
15
|
-
@min_mark = min_mark[0]
|
14
|
+
@min_mark = state.reject {|c| c =~ /^#{@max_mark}|\s{1}$/ }.first
|
16
15
|
end
|
17
|
-
|
16
|
+
|
18
17
|
def select_optimal_start_move
|
19
|
-
|
20
|
-
best_move = start_moves.sample
|
18
|
+
[0, 2, 4, 6, 8].sample
|
21
19
|
end
|
22
|
-
|
20
|
+
|
23
21
|
def random_move
|
24
|
-
|
22
|
+
@board.available_spaces.sample
|
25
23
|
end
|
26
|
-
|
24
|
+
|
27
25
|
def find_best_move
|
28
26
|
if @board.available_spaces.count == 9
|
29
27
|
best_move = select_optimal_start_move
|
@@ -34,7 +32,7 @@ class Ai
|
|
34
32
|
end
|
35
33
|
best_move
|
36
34
|
end
|
37
|
-
|
35
|
+
|
38
36
|
def max_move
|
39
37
|
best_move = nil
|
40
38
|
best_score = nil
|
@@ -53,7 +51,7 @@ class Ai
|
|
53
51
|
end
|
54
52
|
return best_move, best_score
|
55
53
|
end
|
56
|
-
|
54
|
+
|
57
55
|
def min_move
|
58
56
|
best_move = nil
|
59
57
|
best_score = nil
|
@@ -72,11 +70,11 @@ class Ai
|
|
72
70
|
end
|
73
71
|
return best_move, best_score
|
74
72
|
end
|
75
|
-
|
73
|
+
|
76
74
|
def state_is_terminal?
|
77
75
|
@scoring.winner?(@board) || @scoring.draw?(@board)
|
78
76
|
end
|
79
|
-
|
77
|
+
|
80
78
|
def evaluate_the_board
|
81
79
|
decision = nil
|
82
80
|
decision = 1 if @scoring.winner?(@board) && @scoring.winning_mark(@board) == @max_mark
|
data/lib/ang_ttt_gem/board.rb
CHANGED
@@ -1,64 +1,64 @@
|
|
1
1
|
class Board
|
2
|
-
|
2
|
+
|
3
3
|
def initialize
|
4
4
|
@cells = Array.new(9) {" "}
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
7
|
def get(cell_number)
|
8
8
|
@cells[cell_number]
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def set(cell_number, mark)
|
12
12
|
@cells[cell_number] = mark
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def undo_move(cell_number)
|
16
16
|
@cells[cell_number] = " "
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def available_spaces
|
20
20
|
available_spaces = @cells.each_with_index.select { |i, idx| i =~ / / }
|
21
21
|
available_spaces = available_spaces.map{|i| i[1] }
|
22
22
|
available_spaces
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def cell_occupied?(cell_number)
|
26
26
|
get(cell_number.to_i - 1) != " "
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def current_state
|
30
30
|
current_state = @cells.map {|c| c}
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def clear_all_spaces
|
34
34
|
mark = " "
|
35
35
|
@cells.each_with_index do |cell, index|
|
36
36
|
set(index, mark)
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
def rows
|
41
41
|
[ @cells[0..2],
|
42
42
|
@cells[3..5],
|
43
43
|
@cells[6..8] ]
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
def columns
|
47
47
|
rows.transpose
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
def diagonal_forward
|
51
51
|
[ @cells[2],
|
52
52
|
@cells[4],
|
53
53
|
@cells[6] ]
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
def diagonal_back
|
57
57
|
[ @cells[0],
|
58
58
|
@cells[4],
|
59
59
|
@cells[8] ]
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
def possible_winning_combinations
|
63
63
|
possible_winning_combinations = []
|
64
64
|
rows.collect{|row| possible_winning_combinations << row }
|
data/lib/ang_ttt_gem/game.rb
CHANGED
@@ -5,33 +5,33 @@ require "human_player"
|
|
5
5
|
require "computer_player"
|
6
6
|
|
7
7
|
class Game
|
8
|
-
|
8
|
+
|
9
9
|
attr_reader :players, :board
|
10
|
-
|
10
|
+
|
11
11
|
def initialize
|
12
12
|
@board = Board.new
|
13
13
|
@scoring = Scoring.new
|
14
14
|
@validate = Validate.new
|
15
15
|
@players = []
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def create_computer_player(mark)
|
19
19
|
@players << ComputerPlayer.new(mark)
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def create_human_player(mark)
|
23
23
|
@players << HumanPlayer.new(mark)
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def get_player_move(player)
|
27
27
|
index = player - 1
|
28
28
|
@players[index].get_move(@board)
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def move_valid?(move)
|
32
32
|
(0..8).include?(move)
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def make_move_player(player, move)
|
36
36
|
index = player - 1
|
37
37
|
mark = @players[index].mark
|
@@ -39,28 +39,21 @@ class Game
|
|
39
39
|
@board.set(move, mark)
|
40
40
|
prepare_display_state
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
def square_taken?(cell_number)
|
44
44
|
@board.cell_occupied?(cell_number)
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
def prepare_display_state
|
48
|
-
|
49
|
-
|
50
|
-
cell_numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
|
51
|
-
index = 0
|
52
|
-
current_state.each do |cell|
|
53
|
-
board_display_state << cell_numbers[index] if cell == " "
|
54
|
-
board_display_state << current_state[index] unless cell == " "
|
55
|
-
index += 1
|
48
|
+
@board.current_state.each_with_index.map do |cell, index|
|
49
|
+
cell == " " ? (index + 1).to_s : cell
|
56
50
|
end
|
57
|
-
board_display_state
|
58
51
|
end
|
59
|
-
|
52
|
+
|
60
53
|
def is_over?
|
61
54
|
@scoring.winner?(@board) || @scoring.draw?(@board)
|
62
55
|
end
|
63
|
-
|
56
|
+
|
64
57
|
def result
|
65
58
|
message_key = :draw
|
66
59
|
@players.each_with_index do |player, i|
|
data/lib/ang_ttt_gem/message.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
1
|
class Message
|
2
|
-
|
2
|
+
|
3
3
|
def initialize
|
4
|
-
|
4
|
+
|
5
5
|
@message = {
|
6
|
-
welcome: "Welcome to Tic Tac Toe! You will create 2 players. The first player you create will go first
|
7
|
-
create_player: "Create a player
|
8
|
-
determine_player_type: "Do you want the player to be human or computer? (H/C)
|
9
|
-
select_player_mark: "Please select a single letter to represent the player
|
10
|
-
invalid_selection: "That is an invalid selection, please make a valid selection
|
11
|
-
select_square: "Please select an open square
|
12
|
-
player_1_win: "Player 1 is the winner
|
13
|
-
player_2_win: "Player 2 is the winner
|
14
|
-
draw: "It's a draw
|
15
|
-
play_again?: "Would you like to play again? (Y/N)
|
6
|
+
welcome: "Welcome to Tic Tac Toe! You will create 2 players. The first player you create will go first.",
|
7
|
+
create_player: "Create a player.",
|
8
|
+
determine_player_type: "Do you want the player to be human or computer? (H/C)",
|
9
|
+
select_player_mark: "Please select a single letter to represent the player.",
|
10
|
+
invalid_selection: "That is an invalid selection, please make a valid selection.",
|
11
|
+
select_square: "Please select an open square.",
|
12
|
+
player_1_win: "Player 1 is the winner!",
|
13
|
+
player_2_win: "Player 2 is the winner!",
|
14
|
+
draw: "It's a draw.",
|
15
|
+
play_again?: "Would you like to play again? (Y/N)",
|
16
16
|
}
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def passed(*keys)
|
20
20
|
message = String.new
|
21
21
|
keys.each do |key|
|
22
|
-
message << @message[key]
|
22
|
+
message << @message[key] + "\n"
|
23
23
|
end
|
24
24
|
message
|
25
25
|
end
|
data/lib/ang_ttt_gem/player.rb
CHANGED
data/lib/ang_ttt_gem/scoring.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "board"
|
2
2
|
|
3
3
|
class Scoring
|
4
|
-
|
4
|
+
|
5
5
|
def winner?(board)
|
6
6
|
winner = false
|
7
7
|
board.possible_winning_combinations.each do |combo|
|
@@ -11,7 +11,7 @@ class Scoring
|
|
11
11
|
end
|
12
12
|
winner
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def winning_mark(board)
|
16
16
|
board.possible_winning_combinations.each do |combo|
|
17
17
|
if combo.uniq.length == 1 && combo[0] != " "
|
@@ -19,7 +19,7 @@ class Scoring
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def draw?(board)
|
24
24
|
winner?(board) == false && board.available_spaces.count == 0
|
25
25
|
end
|
data/lib/ang_ttt_gem/validate.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
class Validate
|
2
|
-
|
2
|
+
|
3
3
|
def player_input(input)
|
4
4
|
return false unless input =~ /[Hh,Cc]/
|
5
5
|
return true
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def mark_input(input)
|
9
9
|
return false unless input =~ /[a-zA-Z]/
|
10
10
|
return true
|
@@ -14,7 +14,7 @@ class Validate
|
|
14
14
|
return false unless input =~ /[1-9]/
|
15
15
|
return true
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def play_again_input(input)
|
19
19
|
return false unless input =~ /[Nn,Yy]/
|
20
20
|
return true
|