ang_ttt_gem 0.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.
@@ -0,0 +1,14 @@
1
+ $: << File.expand_path(File.dirname(__FILE__) + '/ang_ttt_gem/')
2
+ # require "board"
3
+ # class Hola
4
+ # def self.hi
5
+ # puts "Hello world!"
6
+ # board = Board.new
7
+ # puts $: << File.expand_path(File.dirname(__FILE__) + '/ang_ttt_gem/')
8
+ # # if board.nil?
9
+ # # puts "there is no board"
10
+ # # else
11
+ # # puts "there is a board"
12
+ # # end
13
+ # end
14
+ #end
@@ -0,0 +1,87 @@
1
+ require "scoring"
2
+ require "board"
3
+
4
+ class Ai
5
+
6
+ def initialize(player, board)
7
+ @board = board
8
+ @scoring = Scoring.new
9
+ @max_mark = player.mark
10
+ end
11
+
12
+ def find_opponent_mark
13
+ state = @board.current_state
14
+ min_mark = state.reject {|c| c =~ /^#{@max_mark}|\s{1}$/ }
15
+ @min_mark = min_mark[0]
16
+ end
17
+
18
+ def select_optimal_start_move
19
+ start_moves = [0, 2, 4, 6, 8]
20
+ best_move = start_moves.sample
21
+ end
22
+
23
+ def random_move
24
+ move = @board.available_spaces.sample
25
+ end
26
+
27
+ def find_best_move
28
+ if @board.available_spaces.count == 9
29
+ best_move = select_optimal_start_move
30
+ else
31
+ find_opponent_mark
32
+ move_reference, best_score = max_move
33
+ best_move = move_reference
34
+ end
35
+ best_move
36
+ end
37
+
38
+ def max_move
39
+ best_move = nil
40
+ best_score = nil
41
+ @board.available_spaces.each do |move|
42
+ @board.set(move, @max_mark)
43
+ if state_is_terminal?
44
+ score = evaluate_the_board
45
+ else
46
+ move_reference, score = min_move
47
+ end
48
+ @board.undo_move(move)
49
+ if best_score.nil? || score > best_score
50
+ best_score = score
51
+ best_move = move
52
+ end
53
+ end
54
+ return best_move, best_score
55
+ end
56
+
57
+ def min_move
58
+ best_move = nil
59
+ best_score = nil
60
+ @board.available_spaces.each do |move|
61
+ @board.set(move, @min_mark)
62
+ if state_is_terminal?
63
+ score = evaluate_the_board
64
+ else
65
+ move_reference, score = max_move
66
+ end
67
+ @board.undo_move(move)
68
+ if best_score.nil? || score < best_score
69
+ best_score = score
70
+ best_move = move
71
+ end
72
+ end
73
+ return best_move, best_score
74
+ end
75
+
76
+ def state_is_terminal?
77
+ @scoring.winner?(@board) || @scoring.draw?(@board)
78
+ end
79
+
80
+ def evaluate_the_board
81
+ decision = nil
82
+ decision = 1 if @scoring.winner?(@board) && @scoring.winning_mark(@board) == @max_mark
83
+ decision = -1 if @scoring.winner?(@board) && @scoring.winning_mark(@board) != @max_mark
84
+ decision = 0 if @scoring.draw?(@board)
85
+ decision
86
+ end
87
+ end
@@ -0,0 +1,69 @@
1
+ class Board
2
+
3
+ def initialize
4
+ @cells = Array.new(9) {" "}
5
+ end
6
+
7
+ def get(cell_number)
8
+ @cells[cell_number]
9
+ end
10
+
11
+ def set(cell_number, mark)
12
+ @cells[cell_number] = mark
13
+ end
14
+
15
+ def undo_move(cell_number)
16
+ @cells[cell_number] = " "
17
+ end
18
+
19
+ def available_spaces
20
+ available_spaces = @cells.each_with_index.select { |i, idx| i =~ / / }
21
+ available_spaces = available_spaces.map{|i| i[1] }
22
+ available_spaces
23
+ end
24
+
25
+ def cell_occupied?(cell_number)
26
+ get(cell_number.to_i - 1) != " "
27
+ end
28
+
29
+ def current_state
30
+ current_state = @cells.map {|c| c}
31
+ end
32
+
33
+ def clear_all_spaces
34
+ mark = " "
35
+ @cells.each_with_index do |cell, index|
36
+ set(index, mark)
37
+ end
38
+ end
39
+
40
+ def rows
41
+ [ @cells[0..2],
42
+ @cells[3..5],
43
+ @cells[6..8] ]
44
+ end
45
+
46
+ def columns
47
+ rows.transpose
48
+ end
49
+
50
+ def diagonal_forward
51
+ [ @cells[2],
52
+ @cells[4],
53
+ @cells[6] ]
54
+ end
55
+
56
+ def diagonal_back
57
+ [ @cells[0],
58
+ @cells[4],
59
+ @cells[8] ]
60
+ end
61
+
62
+ def possible_winning_combinations
63
+ possible_winning_combinations = []
64
+ rows.collect{|row| possible_winning_combinations << row }
65
+ columns.collect{|column| possible_winning_combinations << column }
66
+ possible_winning_combinations << diagonal_forward
67
+ possible_winning_combinations << diagonal_back
68
+ end
69
+ end
@@ -0,0 +1,17 @@
1
+ require "player"
2
+ require "ai"
3
+ require "board"
4
+
5
+ class ComputerPlayer < Player
6
+
7
+ attr_accessor :ai
8
+
9
+ def initialize(mark)
10
+ self.set_mark(mark)
11
+ end
12
+
13
+ def get_move(board)
14
+ ai = Ai.new(self, board)
15
+ cell_number = ai.find_best_move
16
+ end
17
+ end
@@ -0,0 +1,74 @@
1
+ require "board"
2
+ require "scoring"
3
+ require "validate"
4
+ require "human_player"
5
+ require "computer_player"
6
+
7
+ class Game
8
+
9
+ attr_reader :players, :board
10
+
11
+ def initialize
12
+ @board = Board.new
13
+ @scoring = Scoring.new
14
+ @validate = Validate.new
15
+ @players = []
16
+ end
17
+
18
+ def create_computer_player(mark)
19
+ @players << ComputerPlayer.new(mark)
20
+ end
21
+
22
+ def create_human_player(mark)
23
+ @players << HumanPlayer.new(mark)
24
+ end
25
+
26
+ def get_player_move(player)
27
+ index = player - 1
28
+ @players[index].get_move(@board)
29
+ end
30
+
31
+ def move_valid?(move)
32
+ (0..8).include?(move)
33
+ end
34
+
35
+ def make_move_player(player, move)
36
+ index = player - 1
37
+ mark = @players[index].mark
38
+ return false unless move_valid?(move)
39
+ @board.set(move, mark)
40
+ prepare_display_state
41
+ end
42
+
43
+ def square_taken?(cell_number)
44
+ @board.cell_occupied?(cell_number)
45
+ end
46
+
47
+ def prepare_display_state
48
+ board_display_state = []
49
+ current_state = @board.current_state
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
56
+ end
57
+ board_display_state
58
+ end
59
+
60
+ def is_over?
61
+ @scoring.winner?(@board) || @scoring.draw?(@board)
62
+ end
63
+
64
+ def result
65
+ message_key = :draw
66
+ @players.each_with_index do |player, i|
67
+ num = i + 1
68
+ if @scoring.winning_mark(@board) == player.mark
69
+ message_key = "player_#{num}_win".to_sym
70
+ end
71
+ end
72
+ message_key
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+ require "player"
2
+ require "validate"
3
+ require "board"
4
+
5
+ class HumanPlayer < Player
6
+
7
+ def initialize(mark)
8
+ self.set_mark(mark)
9
+ end
10
+
11
+ def get_move(board)
12
+ return false
13
+ end
14
+ end
@@ -0,0 +1,26 @@
1
+ class Message
2
+
3
+ def initialize
4
+
5
+ @message = {
6
+ welcome: "Welcome to Tic Tac Toe! You will create 2 players. The first player you create will go first.\n",
7
+ create_player: "Create a player.\n",
8
+ determine_player_type: "Do you want the player to be human or computer? (H/C)\n",
9
+ select_player_mark: "Please select a single letter to represent the player.\n",
10
+ invalid_selection: "That is an invalid selection, please make a valid selection.\n",
11
+ select_square: "Please select an open square.\n",
12
+ player_1_win: "Player 1 is the winner!\n",
13
+ player_2_win: "Player 2 is the winner!\n",
14
+ draw: "It's a draw.\n",
15
+ play_again?: "Would you like to play again? (Y/N)\n",
16
+ }
17
+ end
18
+
19
+ def passed(*keys)
20
+ message = String.new
21
+ keys.each do |key|
22
+ message << @message[key]
23
+ end
24
+ message
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ class Player
2
+
3
+ def set_mark(mark)
4
+ @mark = mark
5
+ end
6
+
7
+ def mark
8
+ @mark
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ require "board"
2
+
3
+ class Scoring
4
+
5
+ def winner?(board)
6
+ winner = false
7
+ board.possible_winning_combinations.each do |combo|
8
+ if combo.uniq.length == 1 && combo[0] != " "
9
+ winner = true
10
+ end
11
+ end
12
+ winner
13
+ end
14
+
15
+ def winning_mark(board)
16
+ board.possible_winning_combinations.each do |combo|
17
+ if combo.uniq.length == 1 && combo[0] != " "
18
+ return combo[0]
19
+ end
20
+ end
21
+ end
22
+
23
+ def draw?(board)
24
+ winner?(board) == false && board.available_spaces.count == 0
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ class Validate
2
+
3
+ def player_input(input)
4
+ return false unless input =~ /[Hh,Cc]/
5
+ return true
6
+ end
7
+
8
+ def mark_input(input)
9
+ return false unless input =~ /[a-zA-Z]/
10
+ return true
11
+ end
12
+
13
+ def number_input(input)
14
+ return false unless input =~ /[1-9]/
15
+ return true
16
+ end
17
+
18
+ def play_again_input(input)
19
+ return false unless input =~ /[Nn,Yy]/
20
+ return true
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ang_ttt_gem
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Angeleah Daidone
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-28 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: A Tic Tac Toe game made by Angeleah
15
+ email: angeleah@angeleah.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/ang_ttt_gem/ai.rb
21
+ - lib/ang_ttt_gem/board.rb
22
+ - lib/ang_ttt_gem/computer_player.rb
23
+ - lib/ang_ttt_gem/game.rb
24
+ - lib/ang_ttt_gem/human_player.rb
25
+ - lib/ang_ttt_gem/message.rb
26
+ - lib/ang_ttt_gem/player.rb
27
+ - lib/ang_ttt_gem/scoring.rb
28
+ - lib/ang_ttt_gem/validate.rb
29
+ - lib/ang_ttt_gem.rb
30
+ homepage: https://github.com/angeleah/tic_tac_toe_by_angeleah
31
+ licenses: []
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ - spec
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 1.8.10
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: A Tic Tac Toe Gem
55
+ test_files: []