ang_ttt_gem 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []