ttt-core 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +36 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +2 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +61 -0
- data/README.md +29 -0
- data/Rakefile +8 -0
- data/bin/run.sh +21 -0
- data/lib/ai_player.rb +117 -0
- data/lib/board.rb +87 -0
- data/lib/board_factory.rb +8 -0
- data/lib/game.rb +27 -0
- data/lib/player.rb +16 -0
- data/lib/player_factory.rb +38 -0
- data/lib/player_options.rb +48 -0
- data/lib/player_symbols.rb +16 -0
- data/lib/replay_option.rb +3 -0
- data/lib/ttt-core/version.rb +3 -0
- data/spec/ai_player_spec.rb +143 -0
- data/spec/board_factory_spec.rb +10 -0
- data/spec/board_spec.rb +125 -0
- data/spec/game_spec.rb +58 -0
- data/spec/player_options_spec.rb +33 -0
- data/spec/player_symbols_spec.rb +32 -0
- data/spec/replay_option_spec.rb +8 -0
- data/spec/spec_helper.rb +107 -0
- data/ttt-core-0.0.1/.gitignore +36 -0
- data/ttt-core-0.0.1/.rspec +2 -0
- data/ttt-core-0.0.1/.ruby-gemset +1 -0
- data/ttt-core-0.0.1/.ruby-version +1 -0
- data/ttt-core-0.0.1/.travis.yml +2 -0
- data/ttt-core-0.0.1/Gemfile +10 -0
- data/ttt-core-0.0.1/README.md +21 -0
- data/ttt-core-0.0.1/Rakefile +7 -0
- data/ttt-core-0.0.1/bin/run.sh +21 -0
- data/ttt-core-0.0.1/lib/ai_player.rb +117 -0
- data/ttt-core-0.0.1/lib/board.rb +87 -0
- data/ttt-core-0.0.1/lib/board_factory.rb +8 -0
- data/ttt-core-0.0.1/lib/game.rb +27 -0
- data/ttt-core-0.0.1/lib/player.rb +16 -0
- data/ttt-core-0.0.1/lib/player_factory.rb +38 -0
- data/ttt-core-0.0.1/lib/player_options.rb +48 -0
- data/ttt-core-0.0.1/lib/player_symbols.rb +16 -0
- data/ttt-core-0.0.1/lib/replay_option.rb +3 -0
- data/ttt-core-0.0.1/spec/ai_player_spec.rb +143 -0
- data/ttt-core-0.0.1/spec/board_factory_spec.rb +10 -0
- data/ttt-core-0.0.1/spec/board_spec.rb +125 -0
- data/ttt-core-0.0.1/spec/game_spec.rb +58 -0
- data/ttt-core-0.0.1/spec/player_options_spec.rb +33 -0
- data/ttt-core-0.0.1/spec/player_symbols_spec.rb +32 -0
- data/ttt-core-0.0.1/spec/replay_option_spec.rb +8 -0
- data/ttt-core-0.0.1/spec/spec_helper.rb +107 -0
- data/ttt-core.gemspec +22 -0
- metadata +150 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 592a2b99d813d6eff7554da5722ef2ce5f960470
|
|
4
|
+
data.tar.gz: 65262df5515d534718ed484cab124e32f847fb22
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e1eb6b836b09ba27c3c944a4ae5064242f8595e20955dbb0516405ad22bccebec1247e3a1a32c2999b32a06050cb7bbf3dc1a88bdedb059da668643bf9596f99
|
|
7
|
+
data.tar.gz: ce091661e1f82bd04dca7b1fa02a128a63361cba5fdb90bfd35b477aab073d85a475fddf55fb58ff0776de7001cf9ddb7f9771f3a872a455fe0ffa3c46184fca
|
data/.gitignore
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/test/tmp/
|
|
9
|
+
/test/version_tmp/
|
|
10
|
+
/tmp/
|
|
11
|
+
.coveralls.yml
|
|
12
|
+
|
|
13
|
+
## Specific to RubyMotion:
|
|
14
|
+
.dat*
|
|
15
|
+
.repl_history
|
|
16
|
+
build/
|
|
17
|
+
|
|
18
|
+
## Documentation cache and generated files:
|
|
19
|
+
/.yardoc/
|
|
20
|
+
/_yardoc/
|
|
21
|
+
/doc/
|
|
22
|
+
/rdoc/
|
|
23
|
+
|
|
24
|
+
## Environment normalisation:
|
|
25
|
+
/.bundle/
|
|
26
|
+
/vendor/bundle
|
|
27
|
+
/lib/bundler/man/
|
|
28
|
+
|
|
29
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
30
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
31
|
+
Gemfile.lock
|
|
32
|
+
# .ruby-version
|
|
33
|
+
# .ruby-gemset
|
|
34
|
+
|
|
35
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
36
|
+
.rvmrc
|
data/.rspec
ADDED
data/.ruby-gemset
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ttt
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.2.1
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: https://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
coveralls (0.8.10)
|
|
5
|
+
json (~> 1.8)
|
|
6
|
+
rest-client (>= 1.6.8, < 2)
|
|
7
|
+
simplecov (~> 0.11.0)
|
|
8
|
+
term-ansicolor (~> 1.3)
|
|
9
|
+
thor (~> 0.19.1)
|
|
10
|
+
tins (~> 1.6.0)
|
|
11
|
+
diff-lcs (1.2.5)
|
|
12
|
+
docile (1.1.5)
|
|
13
|
+
domain_name (0.5.25)
|
|
14
|
+
unf (>= 0.0.5, < 1.0.0)
|
|
15
|
+
http-cookie (1.0.2)
|
|
16
|
+
domain_name (~> 0.5)
|
|
17
|
+
json (1.8.3)
|
|
18
|
+
mime-types (2.99)
|
|
19
|
+
netrc (0.11.0)
|
|
20
|
+
rake (10.5.0)
|
|
21
|
+
rest-client (1.8.0)
|
|
22
|
+
http-cookie (>= 1.0.2, < 2.0)
|
|
23
|
+
mime-types (>= 1.16, < 3.0)
|
|
24
|
+
netrc (~> 0.7)
|
|
25
|
+
rspec (3.4.0)
|
|
26
|
+
rspec-core (~> 3.4.0)
|
|
27
|
+
rspec-expectations (~> 3.4.0)
|
|
28
|
+
rspec-mocks (~> 3.4.0)
|
|
29
|
+
rspec-core (3.4.1)
|
|
30
|
+
rspec-support (~> 3.4.0)
|
|
31
|
+
rspec-expectations (3.4.0)
|
|
32
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
33
|
+
rspec-support (~> 3.4.0)
|
|
34
|
+
rspec-mocks (3.4.1)
|
|
35
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
36
|
+
rspec-support (~> 3.4.0)
|
|
37
|
+
rspec-support (3.4.1)
|
|
38
|
+
simplecov (0.11.1)
|
|
39
|
+
docile (~> 1.1.0)
|
|
40
|
+
json (~> 1.8)
|
|
41
|
+
simplecov-html (~> 0.10.0)
|
|
42
|
+
simplecov-html (0.10.0)
|
|
43
|
+
term-ansicolor (1.3.2)
|
|
44
|
+
tins (~> 1.0)
|
|
45
|
+
thor (0.19.1)
|
|
46
|
+
tins (1.6.0)
|
|
47
|
+
unf (0.1.4)
|
|
48
|
+
unf_ext
|
|
49
|
+
unf_ext (0.0.7.1)
|
|
50
|
+
|
|
51
|
+
PLATFORMS
|
|
52
|
+
ruby
|
|
53
|
+
|
|
54
|
+
DEPENDENCIES
|
|
55
|
+
coveralls (= 0.8.10)
|
|
56
|
+
rake (= 10.5.0)
|
|
57
|
+
rspec (= 3.4.0)
|
|
58
|
+
simplecov (= 0.11.1)
|
|
59
|
+
|
|
60
|
+
BUNDLED WITH
|
|
61
|
+
1.11.2
|
data/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Apprenticeship-RubyTicTacToe
|
|
2
|
+
|
|
3
|
+
Tic Tac Toe Core Game implemented in Ruby
|
|
4
|
+
|
|
5
|
+
[](https://travis-ci.org/gemcfadyen/Apprenticeship-RubyTicTacToe) [](https://coveralls.io/github/gemcfadyen/Apprenticeship-RubyTicTacToe?branch=master)
|
|
6
|
+
|
|
7
|
+
To run the application clone the project into a folder
|
|
8
|
+
|
|
9
|
+
>> git clone git@github.com:gemcfadyen/Apprenticeship-RubyTicTacToe.git
|
|
10
|
+
|
|
11
|
+
To recreate the gem, do
|
|
12
|
+
>> gem build ttt-core.gemspec
|
|
13
|
+
|
|
14
|
+
To install locally, do
|
|
15
|
+
>> gem install ./ttt-core-0.0.1.gem
|
|
16
|
+
|
|
17
|
+
This will install the gem to the ttt gemset.
|
|
18
|
+
To use this gem, add the following to your Gemfile:
|
|
19
|
+
|
|
20
|
+
`gem ttt-core, '0.0.1'`
|
|
21
|
+
|
|
22
|
+
(update the version as appropriate)
|
|
23
|
+
|
|
24
|
+
Ensure your project will look at the ttt gemset path. Run `gem env` and check if the ttt gemset is listed under GEM PATHS.
|
|
25
|
+
|
|
26
|
+
If it is not, you can configure it by running
|
|
27
|
+
>> rvm 2.2.1@ttt
|
|
28
|
+
|
|
29
|
+
Run `gem env` again, and check that the gemset is listed under the GEM PATH.
|
data/Rakefile
ADDED
data/bin/run.sh
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
##Setup Load Path
|
|
4
|
+
$LOAD_PATH << File.expand_path("../../lib", __FILE__)
|
|
5
|
+
|
|
6
|
+
require 'command_line_app'
|
|
7
|
+
require 'command_line_ui'
|
|
8
|
+
require 'board_factory'
|
|
9
|
+
require 'command_line_player_factory'
|
|
10
|
+
require 'prompt_writer'
|
|
11
|
+
require 'prompt_reader'
|
|
12
|
+
|
|
13
|
+
writer = PromptWriter.new($stdout)
|
|
14
|
+
reader = PromptReader.new($stdin)
|
|
15
|
+
command_line_ui = CommandLineUI.new(writer, reader)
|
|
16
|
+
|
|
17
|
+
board_factory = BoardFactory.new
|
|
18
|
+
player_factory = CommandLinePlayerFactory.new
|
|
19
|
+
|
|
20
|
+
command_line_app = CommandLineApp.new(command_line_ui, board_factory, player_factory)
|
|
21
|
+
command_line_app.start
|
data/lib/ai_player.rb
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
require 'player_symbols'
|
|
2
|
+
require 'player'
|
|
3
|
+
|
|
4
|
+
class AiPlayer
|
|
5
|
+
include Player
|
|
6
|
+
|
|
7
|
+
def initialize(symbol)
|
|
8
|
+
super(symbol)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def choose_move(board)
|
|
12
|
+
minimax(board, true, board.vacant_indices.size, ALPHA, BETA).first[1]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ready?
|
|
16
|
+
true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def minimax(board, is_max_player, depth, alpha, beta)
|
|
20
|
+
best_score_so_far = initial_score(is_max_player)
|
|
21
|
+
|
|
22
|
+
if round_is_over(board, depth)
|
|
23
|
+
return score(board, depth)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
board.vacant_indices.each do |i|
|
|
27
|
+
new_board = board.make_move(i, current_players_symbol(is_max_player))
|
|
28
|
+
result = minimax(new_board, !is_max_player, depth - 1, alpha, beta)
|
|
29
|
+
best_score_so_far = update_score(is_max_player, i, best_score_so_far, score_from(result))
|
|
30
|
+
|
|
31
|
+
alpha = update_alpha(is_max_player, best_score_so_far, alpha)
|
|
32
|
+
beta = update_beta(is_max_player, best_score_so_far, beta)
|
|
33
|
+
|
|
34
|
+
if alpha > beta
|
|
35
|
+
break
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
best_score_so_far
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
ALPHA = -2
|
|
46
|
+
BETA = 2
|
|
47
|
+
|
|
48
|
+
def update_alpha(is_max_player, best_score_so_far, alpha)
|
|
49
|
+
if is_max_player && score_from(best_score_so_far) > alpha
|
|
50
|
+
alpha = score_from(best_score_so_far)
|
|
51
|
+
end
|
|
52
|
+
alpha
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def score_from(score)
|
|
56
|
+
score.first.first
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def update_beta(is_max_player, best_score_so_far, beta)
|
|
60
|
+
if !is_max_player && score_from(best_score_so_far) < beta
|
|
61
|
+
beta = score_from(best_score_so_far)
|
|
62
|
+
end
|
|
63
|
+
beta
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def round_is_over(board, depth)
|
|
67
|
+
@winner = board.winning_symbol
|
|
68
|
+
!@winner.nil? || depth == 0
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def score(board, depth)
|
|
72
|
+
if @winner.nil?
|
|
73
|
+
return {0 => nil}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if maximizing_player_won?(@winner)
|
|
77
|
+
return {(1 + depth) => nil}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
if minimizing_player_won?(@winner)
|
|
81
|
+
return {(-1 - depth) => nil}
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def maximizing_player_won?(winners_symbol)
|
|
86
|
+
symbols_are_equal?(winners_symbol, game_symbol)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def minimizing_player_won?(winners_symbol)
|
|
90
|
+
symbols_are_equal?(winners_symbol, PlayerSymbols::opponent(game_symbol))
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def symbols_are_equal?(symbol1, symbol2)
|
|
94
|
+
symbol1 == symbol2
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def initial_score(is_max_player)
|
|
98
|
+
if is_max_player
|
|
99
|
+
best_score_so_far = {ALPHA => nil}
|
|
100
|
+
else
|
|
101
|
+
best_score_so_far = {BETA => nil}
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def current_players_symbol(is_max_player)
|
|
106
|
+
is_max_player == true ? game_symbol : PlayerSymbols::opponent(game_symbol)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def update_score(is_max_player, move, score, result_score)
|
|
110
|
+
if is_max_player && (result_score >= score_from(score))
|
|
111
|
+
return {result_score => move}
|
|
112
|
+
elsif !is_max_player && (result_score < score_from(score))
|
|
113
|
+
return {result_score => move}
|
|
114
|
+
end
|
|
115
|
+
return score
|
|
116
|
+
end
|
|
117
|
+
end
|
data/lib/board.rb
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
class Board
|
|
2
|
+
|
|
3
|
+
def initialize(symbols = Array.new(9))
|
|
4
|
+
@grid = symbols
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def empty?
|
|
8
|
+
grid.all?(&:nil?)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def make_move(index, symbol)
|
|
12
|
+
copy_of_grid = grid.dup
|
|
13
|
+
copy_of_grid[index] = symbol
|
|
14
|
+
Board.new(copy_of_grid)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def free_spaces?
|
|
18
|
+
grid.include?(nil)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def get_symbol_at(position)
|
|
22
|
+
grid.at(position)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def winning_combination?
|
|
26
|
+
not_nil_row(find_winning_row_from(all_rows))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def winning_symbol
|
|
30
|
+
@winning_row = find_winning_row_from(all_rows)
|
|
31
|
+
@winning_row.nil? ? nil : @winning_row.first
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def vacant_indices
|
|
35
|
+
grid.each_index.select{|v| grid[v].nil?}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def grid_for_display
|
|
39
|
+
rows
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
attr_reader :grid
|
|
45
|
+
|
|
46
|
+
def find_winning_row_from(rows)
|
|
47
|
+
@all_rows ||= rows.find do |row|
|
|
48
|
+
all_cells_match = row.all? {|cell| cell == row.first}
|
|
49
|
+
all_cells_match && not_nil_symbol(row.first)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def not_nil_row(row)
|
|
54
|
+
!row.nil?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def all_rows
|
|
58
|
+
@all ||= rows + columns + diagonals
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def not_nil_symbol(cell)
|
|
62
|
+
!cell.nil?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def rows
|
|
66
|
+
[
|
|
67
|
+
[grid.at(0), grid.at(1), grid.at(2)],
|
|
68
|
+
[grid.at(3), grid.at(4), grid.at(5)],
|
|
69
|
+
[grid.at(6), grid.at(7), grid.at(8)]
|
|
70
|
+
]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def columns
|
|
74
|
+
[
|
|
75
|
+
[grid.at(0), grid.at(3), grid.at(6)],
|
|
76
|
+
[grid.at(1), grid.at(4), grid.at(7)],
|
|
77
|
+
[grid.at(2), grid.at(5), grid.at(8)]
|
|
78
|
+
]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def diagonals
|
|
82
|
+
[
|
|
83
|
+
[grid.at(0),grid.at(4), grid.at(8)],
|
|
84
|
+
[grid.at(2), grid.at(4), grid.at(6)]
|
|
85
|
+
]
|
|
86
|
+
end
|
|
87
|
+
end
|
data/lib/game.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class Game
|
|
2
|
+
|
|
3
|
+
def initialize(board, players)
|
|
4
|
+
@board = board
|
|
5
|
+
@players = players
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def play
|
|
9
|
+
while game_in_progress?
|
|
10
|
+
@board = board.make_move(current_player.choose_move(board), current_player.game_symbol)
|
|
11
|
+
players.reverse!
|
|
12
|
+
end
|
|
13
|
+
board
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
attr_reader :board, :players
|
|
19
|
+
|
|
20
|
+
def game_in_progress?
|
|
21
|
+
current_player.ready? && board.free_spaces? && !board.winning_combination?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def current_player
|
|
25
|
+
players.first
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/player.rb
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'player_symbols'
|
|
2
|
+
require 'player_options'
|
|
3
|
+
require 'ai_player'
|
|
4
|
+
|
|
5
|
+
class PlayerFactory
|
|
6
|
+
def create_players(player_option, command_line_ui)
|
|
7
|
+
if player_option == PlayerOptions::HUMAN_VS_HUMAN
|
|
8
|
+
human_vs_human(command_line_ui)
|
|
9
|
+
elsif player_option == PlayerOptions::HUMAN_VS_AI
|
|
10
|
+
human_vs_ai(command_line_ui)
|
|
11
|
+
else
|
|
12
|
+
ai_vs_human(command_line_ui)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def human_vs_human(command_line_ui)
|
|
19
|
+
[
|
|
20
|
+
create_human(command_line_ui, PlayerSymbols::X),
|
|
21
|
+
create_human(command_line_ui, PlayerSymbols::O)
|
|
22
|
+
]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def human_vs_ai(command_line_ui)
|
|
26
|
+
[
|
|
27
|
+
create_human(command_line_ui, PlayerSymbols::X),
|
|
28
|
+
AiPlayer.new(PlayerSymbols::O)
|
|
29
|
+
]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def ai_vs_human(command_line_ui)
|
|
33
|
+
[
|
|
34
|
+
AiPlayer.new(PlayerSymbols::X),
|
|
35
|
+
create_human(command_line_ui, PlayerSymbols::O)
|
|
36
|
+
]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
class PlayerOptions
|
|
2
|
+
HUMAN_VS_HUMAN = "Human vs Human"
|
|
3
|
+
HUMAN_VS_AI = "Human vs Ai"
|
|
4
|
+
AI_VS_HUMAN = "Ai vs Human"
|
|
5
|
+
|
|
6
|
+
ID_TO_PLAYER_TYPE = {
|
|
7
|
+
1 => HUMAN_VS_HUMAN,
|
|
8
|
+
2 => HUMAN_VS_AI,
|
|
9
|
+
3 => AI_VS_HUMAN
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
def self.valid_ids
|
|
13
|
+
ID_TO_PLAYER_TYPE.keys
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.get_player_type_for_id(id)
|
|
17
|
+
game_value_of_player = ID_TO_PLAYER_TYPE.fetch(id)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.display_player_options
|
|
21
|
+
player_options_for_display = ID_TO_PLAYER_TYPE.each_pair.map do |id, option|
|
|
22
|
+
open_bracket + id.to_s + close_bracket + space + option
|
|
23
|
+
end
|
|
24
|
+
player_options_for_display.join(comma + space)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.all
|
|
28
|
+
ID_TO_PLAYER_TYPE
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def self.open_bracket
|
|
34
|
+
"("
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.close_bracket
|
|
38
|
+
")"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.space
|
|
42
|
+
" "
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.comma
|
|
46
|
+
","
|
|
47
|
+
end
|
|
48
|
+
end
|