games_bfox 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +4 -0
  6. data/README.md +36 -0
  7. data/Rakefile +6 -0
  8. data/exe/mastermind +8 -0
  9. data/exe/setup +8 -0
  10. data/exe/tictactoe +8 -0
  11. data/games.gemspec +36 -0
  12. data/lib/games/mastermind/board.rb +43 -0
  13. data/lib/games/mastermind/board_builder.rb +9 -0
  14. data/lib/games/mastermind/board_presenter_terminal.rb +69 -0
  15. data/lib/games/mastermind/colors.rb +14 -0
  16. data/lib/games/mastermind/game.rb +64 -0
  17. data/lib/games/mastermind/game_config.rb +48 -0
  18. data/lib/games/mastermind/game_resetter.rb +19 -0
  19. data/lib/games/mastermind/game_state_changer.rb +41 -0
  20. data/lib/games/mastermind/guess_evaluator.rb +85 -0
  21. data/lib/games/mastermind/input_helper.rb +54 -0
  22. data/lib/games/mastermind/move_generator.rb +46 -0
  23. data/lib/games/mastermind/peg.rb +15 -0
  24. data/lib/games/mastermind/pegs.rb +50 -0
  25. data/lib/games/mastermind/pegs_factory.rb +26 -0
  26. data/lib/games/mastermind/players_factory.rb +15 -0
  27. data/lib/games/mastermind.rb +13 -0
  28. data/lib/games/shared/array_iterator.rb +28 -0
  29. data/lib/games/shared/game.rb +155 -0
  30. data/lib/games/shared/input_helper.rb +74 -0
  31. data/lib/games/shared/io_terminal.rb +25 -0
  32. data/lib/games/shared/player.rb +15 -0
  33. data/lib/games/shared/version.rb +3 -0
  34. data/lib/games/tictactoe/board.rb +40 -0
  35. data/lib/games/tictactoe/board_builder.rb +10 -0
  36. data/lib/games/tictactoe/board_presenter_terminal.rb +28 -0
  37. data/lib/games/tictactoe/game.rb +60 -0
  38. data/lib/games/tictactoe/game_config.rb +73 -0
  39. data/lib/games/tictactoe/game_resetter.rb +16 -0
  40. data/lib/games/tictactoe/game_state_changer.rb +17 -0
  41. data/lib/games/tictactoe/input_helper.rb +80 -0
  42. data/lib/games/tictactoe/minimax.rb +81 -0
  43. data/lib/games/tictactoe/move_generator.rb +68 -0
  44. data/lib/games/tictactoe/player.rb +11 -0
  45. data/lib/games/tictactoe/players_factory.rb +11 -0
  46. data/lib/games/tictactoe/square.rb +30 -0
  47. data/lib/games/tictactoe/squares.rb +129 -0
  48. data/lib/games/tictactoe/squares_factory.rb +56 -0
  49. data/lib/games/tictactoe.rb +13 -0
  50. data/lib/games/version.rb +3 -0
  51. data/lib/games.rb +5 -0
  52. metadata +173 -0
@@ -0,0 +1,80 @@
1
+ require_relative '../shared/input_helper'
2
+
3
+ module TTT
4
+ class InputHelper < Shared::InputHelper
5
+ def get_number_of_rows_cols_max_3
6
+ get_user_input("Please choose how many squares you would like in each row.", "Please choose number between 2 and 3.") do |input|
7
+ input.to_i >=2 && input.to_i <=3
8
+ end
9
+ end
10
+
11
+ def get_number_of_rows_cols_max_9
12
+ get_user_input("Please choose how many squares you would like in each row.", "Please choose number between 2 and 3.") do |input|
13
+ input.to_i >=2 && input.to_i <=9
14
+ end
15
+ end
16
+
17
+ def get_player_1_value(player_name = "Player 1")
18
+ user_choice = get_user_input("#{player_name}, please enter a value of either X or O", "Must be X or O. Please re-enter.") do |input|
19
+ input == 'x' || input == 'X' || input == 'o' || input == 'O'
20
+ end
21
+ user_choice.upcase
22
+ end
23
+
24
+ def get_player_2_name
25
+ user_choice = get_user_input("Player 2, please enter your name", "Please re-enter your name, using only letters") do |input|
26
+ input =~ /^[a-zA-Z]+$/
27
+ end
28
+ user_choice.capitalize
29
+ end
30
+
31
+ def get_player_2_type
32
+ user_choice = get_user_input("Please enter \"C\" if you would like to play the Computer. Enter \"H\" if you would like to play the human sitting next to you.", "Invalid character. Please enter either C(Computer) or H(Human).") do |input|
33
+ input == 'c' || input == 'C' || input == 'h' || input == 'H'
34
+ end
35
+ user_choice = user_choice.upcase
36
+ if user_choice == "C"
37
+ :computer
38
+ elsif user_choice == "H"
39
+ :human
40
+ end
41
+ end
42
+
43
+ def get_computer_difficulty_level
44
+ user_choice = get_user_input("Please enter \"E\" if you would like to play an easy Computer. Enter \"D\" if you would like to play an extremely difficult computer.", "Invalid character. Please enter either E (Easy) or D (Difficult).") do |input|
45
+ input == 'd' || input == 'D' || input == 'e' || input == 'E'
46
+ end
47
+ user_choice = user_choice.upcase
48
+ if user_choice == "D"
49
+ :difficult
50
+ elsif user_choice == "E"
51
+ :easy
52
+ end
53
+ end
54
+
55
+ def get_player_2_value(taken_value)
56
+ user_choice = get_user_input("Player 2, please enter your value", "Must not be #{taken_value}, please re-enter") do |input|
57
+ input.upcase != taken_value.upcase
58
+ end
59
+ user_choice.upcase
60
+ end
61
+
62
+ def get_player_choice(game)
63
+ get_user_input("#{game.current_player_name}, please enter the number of the square that you would like to change.", "Invalid entry. Please try again.") do |input|
64
+ game.available_choices.include?(input)
65
+ end
66
+ end
67
+
68
+ def draw_prompt
69
+ io.present_with_new_line("Draw! Please try again.")
70
+ end
71
+
72
+ def winning_prompt(current_player_name)
73
+ io.present_with_new_line("#{current_player_name} wins!")
74
+ end
75
+
76
+ def no_winner_prompt
77
+ io.present_with_new_line("Draw!")
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,81 @@
1
+ require 'logging'
2
+
3
+ module TTT
4
+ class Minimax
5
+ attr_accessor :board, :number_of_turns_taken, :human_value, :computer_value, :choice
6
+
7
+ def initialize(board, number_of_turns_taken, human_value, computer_value)
8
+ @board = board
9
+ @number_of_turns_taken = number_of_turns_taken
10
+ @human_value = human_value
11
+ @computer_value = computer_value
12
+ end
13
+
14
+ def run_minimax
15
+ scores = []
16
+ choices = []
17
+
18
+ board_won = board.won?
19
+ board_full = board.full?
20
+
21
+ if board_won || board_full
22
+ #rewind one player to see which player took last turn and therefore won the game
23
+ self.number_of_turns_taken -= 1
24
+ return score(board_won)
25
+ end
26
+
27
+ # @logger.debug "avaliable choices collection: #{available_choices}"
28
+
29
+ available_choices.each do |available_choice|
30
+ board_copy = Marshal.load(Marshal.dump(board))
31
+ board_copy.change_square(available_choice, player_value)
32
+ choices.push(available_choice)
33
+ minimax = TTT::Minimax.new(board_copy, number_of_turns_taken + 1, human_value, computer_value)
34
+ scores.push minimax.run_minimax
35
+ end
36
+
37
+ if computer_current_player?
38
+ #https://stackoverflow.com/questions/2149802/in-ruby-what-is-the-cleanest-way-of-obtaining-the-index-of-the-largest-value-in
39
+ max_score_index = scores.each_with_index.max[1]
40
+ self.choice = choices[max_score_index]
41
+ return scores[max_score_index]
42
+ else
43
+ # This is the min calculation
44
+ min_score_index = scores.each_with_index.min[1]
45
+ self.choice = choices[min_score_index]
46
+ return scores[min_score_index]
47
+ end
48
+ end
49
+
50
+
51
+ private
52
+ def available_choices
53
+ board.available_choices
54
+ end
55
+
56
+ def player_value
57
+ if computer_current_player?
58
+ computer_value
59
+ else
60
+ human_value
61
+ end
62
+ end
63
+
64
+ def computer_current_player?
65
+ #computer goes second, when number of turns taken is always odd
66
+ number_of_turns_taken.odd?
67
+ end
68
+
69
+ def score(board_won)
70
+ if board_won && computer_current_player?
71
+ return +1
72
+ elsif board_won && !computer_current_player?
73
+ return -1
74
+ else
75
+ return 0
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+
@@ -0,0 +1,68 @@
1
+ require_relative 'minimax'
2
+
3
+ module TTT
4
+ class MoveGenerator
5
+
6
+ attr_accessor :game
7
+
8
+ def get_player_choice(game)
9
+ @game = game
10
+ get_move
11
+ end
12
+
13
+ def get_move
14
+ if human?
15
+ input_helper.get_player_choice(game)
16
+ elsif computer?
17
+ input_helper.computer_choosing_graphic
18
+ if difficult?
19
+ perfect_move
20
+ elsif easy?
21
+ random_move
22
+ end
23
+ end
24
+ end
25
+
26
+ def perfect_move
27
+ minimax = game_module::Minimax.new(game.board, game.number_of_turns_taken, game.player_1_value, game.player_2_value)
28
+ minimax.run_minimax
29
+ minimax.choice
30
+ end
31
+
32
+ def random_move
33
+ available_choices.sample
34
+ end
35
+
36
+ def available_choices
37
+ game.available_choices
38
+ end
39
+
40
+ def game_module
41
+ game.game_module
42
+ end
43
+
44
+ def current_player
45
+ game.current_player
46
+ end
47
+
48
+ def input_helper
49
+ game.input_helper
50
+ end
51
+
52
+ def human?
53
+ game.current_player_human?
54
+ end
55
+
56
+ def computer?
57
+ game.current_player_computer?
58
+ end
59
+
60
+ def difficult?
61
+ game.current_player_difficult_computer?
62
+ end
63
+
64
+ def easy?
65
+ game.current_player_easy_computer?
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../shared/player'
2
+
3
+ module TTT
4
+ class Player < Shared::Player
5
+ attr_accessor :value
6
+
7
+ def post_initialize(args = {})
8
+ @value = args.fetch(:value, "X")
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'player'
2
+
3
+ module TTT
4
+ class PlayersFactory
5
+ def generate_players(config)
6
+ player_1 = TTT::Player.new(value: config.player_1_value, name: config.player_1_name, type: :human)
7
+ player_2 = TTT::Player.new(value: config.player_2_value, name: config.player_2_name, type: config.player_2_type, difficulty_level: config.computer_difficulty_level)
8
+ [player_1, player_2]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ module TTT
2
+ class Square
3
+ attr_accessor :value, :display_value
4
+ attr_reader :row, :col
5
+
6
+ def initialize(args)
7
+ @value = args[:value]
8
+ @display_value = args[:display_value]
9
+ @row = args[:row]
10
+ @col = args[:col]
11
+ end
12
+
13
+ def change_value(new_value)
14
+ self.value = new_value
15
+ self.display_value = new_value
16
+ end
17
+
18
+ def empty?
19
+ return true unless full?
20
+ end
21
+
22
+ def full?
23
+ if value != nil
24
+ return true
25
+ else
26
+ return false
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,129 @@
1
+ module TTT
2
+ class Squares
3
+ attr_reader :collection_of_squares
4
+
5
+ #collection_of_squares is a multi-dimensional array
6
+
7
+ def initialize(args)
8
+ @collection_of_squares = args[:collection_of_squares]
9
+ end
10
+
11
+ def retrieve_square(display_value)
12
+ row = (display_value - 1) / number_of_rows_cols
13
+ col = (display_value - 1) % number_of_rows_cols
14
+ if row >= number_of_rows_cols || col >= number_of_rows_cols
15
+ return nil
16
+ else
17
+ return collection_of_squares[row][col]
18
+ end
19
+ end
20
+
21
+ def display_values
22
+ collection_of_squares.map do |row|
23
+ row.map do |square|
24
+ square.display_value
25
+ end
26
+ end
27
+ end
28
+
29
+ def available_choices
30
+ available_choices = Array.new
31
+ collection_of_squares.each do |row|
32
+ row.each do |square|
33
+ if square.empty?
34
+ available_choices.push(square.display_value)
35
+ end
36
+ end
37
+ end
38
+ available_choices
39
+ end
40
+
41
+ def full?
42
+ collection_of_squares.each do |row|
43
+ return false if row.all? { |square| square.full? } == false
44
+ end
45
+ return true
46
+ end
47
+
48
+ def any_combination_won?
49
+ possible_winning_combinations.any? do |possible_winning_combination|
50
+ won?(possible_winning_combination)
51
+ end
52
+ end
53
+
54
+ def won?(array)
55
+ #https://stackoverflow.com/questions/3233278/how-do-i-test-if-all-items-in-an-array-are-identical
56
+ return false if array[0].value == nil
57
+ array.all? {|square| square.value == array[0].value}
58
+ end
59
+
60
+ def number_of_rows_cols
61
+ collection_of_squares.length
62
+ end
63
+
64
+ private
65
+ def cols
66
+ number_of_rows_cols = collection_of_squares.size
67
+ cols = Array.new
68
+ col = 0
69
+ while col < number_of_rows_cols
70
+ cols.push (
71
+ collection_of_squares.map do |row|
72
+ row[col]
73
+ end
74
+ )
75
+ col += 1
76
+ end
77
+ cols
78
+ end
79
+
80
+ #return collection_of_squares because set up as multidimensional array consisting of rows
81
+ def rows
82
+ collection_of_squares
83
+ end
84
+
85
+ def l_to_r_diag
86
+ number_of_rows_cols = collection_of_squares.size
87
+ diag = Array.new
88
+ row = 0
89
+ col = 0
90
+ while row < number_of_rows_cols
91
+ diag.push (
92
+ collection_of_squares[row][col]
93
+ )
94
+ row += 1
95
+ col += 1
96
+ end
97
+ diag
98
+ end
99
+
100
+ def r_to_l_diag
101
+ number_of_rows_cols = collection_of_squares.size
102
+ diag = Array.new
103
+ row = 0
104
+ col = number_of_rows_cols - 1
105
+ while row < number_of_rows_cols
106
+ diag.push (
107
+ collection_of_squares[row][col]
108
+ )
109
+ row += 1
110
+ col -= 1
111
+ end
112
+ diag
113
+ end
114
+
115
+ def possible_winning_combinations
116
+ winning_combinations = Array.new
117
+ winning_combinations.push(l_to_r_diag, r_to_l_diag)
118
+
119
+ rows.each do |row|
120
+ winning_combinations.push(row)
121
+ end
122
+
123
+ cols.each do |col|
124
+ winning_combinations.push(col)
125
+ end
126
+ winning_combinations
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,56 @@
1
+ require_relative 'squares'
2
+ require_relative 'square'
3
+
4
+ module TTT
5
+ module SquaresFactory
6
+ def self.build_custom_squares(config, squares_class = Squares)
7
+
8
+ rows_and_cols = config.length
9
+
10
+ #create multi-dimensional array
11
+ squares = Array.new(rows_and_cols) do
12
+ Array.new(rows_and_cols)
13
+ end
14
+
15
+ squares.each_with_index do |element, row|
16
+ element.each_index do |col|
17
+ squares[row][col] = create_custom_square(config[row][col][0],config[row][col][1], row, col)
18
+ end
19
+ end
20
+
21
+ squares_class.new(collection_of_squares: squares)
22
+
23
+ end
24
+
25
+
26
+ def self.create_custom_square(display_value, value, row, col, square_class = Square)
27
+ square_class.new(display_value: display_value,
28
+ value: value,
29
+ row: row,
30
+ col: col )
31
+ end
32
+
33
+ def self.build_empty_squares(rows_and_cols, squares_class = Squares)
34
+ squares = Array.new(rows_and_cols) do
35
+ Array.new(rows_and_cols)
36
+ end
37
+
38
+ i = 1
39
+ squares.each_with_index do |element, row|
40
+ element.each_index do |col|
41
+ squares[row][col] = create_empty_square(i, row, col)
42
+ i += 1
43
+ end
44
+ end
45
+
46
+ squares_class.new(collection_of_squares: squares)
47
+ end
48
+
49
+ def self.create_empty_square(display_value, row, col, square_class = Square)
50
+ square_class.new(display_value: display_value,
51
+ value: nil,
52
+ row: row,
53
+ col: col )
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,13 @@
1
+ Dir[File.join(File.expand_path(File.dirname(__FILE__)), 'shared', '*.rb')].each {|file| require file }
2
+ Dir[File.join(File.expand_path(File.dirname(__FILE__)), 'tictactoe', '*.rb')].each {|file| require file }
3
+
4
+ class TicTacToe
5
+ def self.run
6
+ io = Shared::IOTerminal.new
7
+ board_presenter = TTT::BoardPresenterTerminal.new
8
+
9
+ game = TTT::Game.new(game_module: TTT, io: io, board_presenter: board_presenter)
10
+ # game.setup
11
+ game.play
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module Games
2
+ VERSION = "0.2.0"
3
+ end
data/lib/games.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "games/version"
2
+
3
+ module Games
4
+ # Your code goes here...
5
+ end
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: games_bfox
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Brett Fox
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-10-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.14'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.10.4
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.10.4
69
+ - !ruby/object:Gem::Dependency
70
+ name: logging
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.2'
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 2.2.2
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: '2.2'
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 2.2.2
89
+ description: In order to play, download the gem, and type \"tictactoe\" or \"mastermind\"
90
+ at your terminal.
91
+ email:
92
+ - brettfox11@gmail.com
93
+ executables:
94
+ - mastermind
95
+ - setup
96
+ - tictactoe
97
+ extensions: []
98
+ extra_rdoc_files: []
99
+ files:
100
+ - ".gitignore"
101
+ - ".rspec"
102
+ - ".travis.yml"
103
+ - Gemfile
104
+ - README.md
105
+ - Rakefile
106
+ - exe/mastermind
107
+ - exe/setup
108
+ - exe/tictactoe
109
+ - games.gemspec
110
+ - lib/games.rb
111
+ - lib/games/mastermind.rb
112
+ - lib/games/mastermind/board.rb
113
+ - lib/games/mastermind/board_builder.rb
114
+ - lib/games/mastermind/board_presenter_terminal.rb
115
+ - lib/games/mastermind/colors.rb
116
+ - lib/games/mastermind/game.rb
117
+ - lib/games/mastermind/game_config.rb
118
+ - lib/games/mastermind/game_resetter.rb
119
+ - lib/games/mastermind/game_state_changer.rb
120
+ - lib/games/mastermind/guess_evaluator.rb
121
+ - lib/games/mastermind/input_helper.rb
122
+ - lib/games/mastermind/move_generator.rb
123
+ - lib/games/mastermind/peg.rb
124
+ - lib/games/mastermind/pegs.rb
125
+ - lib/games/mastermind/pegs_factory.rb
126
+ - lib/games/mastermind/players_factory.rb
127
+ - lib/games/shared/array_iterator.rb
128
+ - lib/games/shared/game.rb
129
+ - lib/games/shared/input_helper.rb
130
+ - lib/games/shared/io_terminal.rb
131
+ - lib/games/shared/player.rb
132
+ - lib/games/shared/version.rb
133
+ - lib/games/tictactoe.rb
134
+ - lib/games/tictactoe/board.rb
135
+ - lib/games/tictactoe/board_builder.rb
136
+ - lib/games/tictactoe/board_presenter_terminal.rb
137
+ - lib/games/tictactoe/game.rb
138
+ - lib/games/tictactoe/game_config.rb
139
+ - lib/games/tictactoe/game_resetter.rb
140
+ - lib/games/tictactoe/game_state_changer.rb
141
+ - lib/games/tictactoe/input_helper.rb
142
+ - lib/games/tictactoe/minimax.rb
143
+ - lib/games/tictactoe/move_generator.rb
144
+ - lib/games/tictactoe/player.rb
145
+ - lib/games/tictactoe/players_factory.rb
146
+ - lib/games/tictactoe/square.rb
147
+ - lib/games/tictactoe/squares.rb
148
+ - lib/games/tictactoe/squares_factory.rb
149
+ - lib/games/version.rb
150
+ homepage: https://github.com/brett11/games
151
+ licenses: []
152
+ metadata: {}
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubyforge_project:
169
+ rubygems_version: 2.6.10
170
+ signing_key:
171
+ specification_version: 4
172
+ summary: Play tic tac toe and mastermind on the command line
173
+ test_files: []