ta-te-ti 0.0.2

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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - jruby-18mode # JRuby in 1.8 mode
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - rbx-18mode
7
+ - rbx-19mode
8
+ - 1.8.7
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in ta_te_ti.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { "spec" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/README ADDED
@@ -0,0 +1,17 @@
1
+ Practica de Laboratorio #9: Creacion de una Gema
2
+
3
+ Tic-Tac-Toe (Tres en raya)
4
+
5
+ Clases para implementar el juego de tres en raya
6
+ Utiliza el concepto de herencia.
7
+ Hay modulos y mixins.
8
+
9
+ Clase desarrollada con rspec siguiendo la filosofia TDD
10
+ Contiene tambien pruebas unitarias Unit Testing
11
+ La clase se compila con la herramienta Travis de integracion continua.
12
+ Se comprueba la portabilidad entre distintas plataformas y versiones de Ruby.
13
+
14
+ Se deben poner los ficheros en spec para que se ejecuten ante
15
+ cualquier modificacion
16
+
17
+ Se ha creado una Gema con bundle
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/clean'
3
+
4
+ CLEAN.include('*.swp')
5
+ CLOBBER.include('pkg/*.gem')
6
+
7
+ task :default => [:spec,:test]
8
+
9
+ desc "Run ta_te_ti.rb"
10
+ task :bin do
11
+ sh "ruby -Ilib bin/ta_te_ti.rb"
12
+ end
13
+
14
+ desc "Run rspec for ta_te_ti.rb development"
15
+ task :spec do
16
+ sh "rspec -Ilib spec/ta_te_ti_spec.rb"
17
+ end
18
+
19
+ desc "Run test/tc_ta_te_ti.rb"
20
+ task :test do
21
+ sh "ruby -Ilib test/tc_ta_te_ti.rb"
22
+ end
23
+
24
+ desc "Uninstall gem ta-te-ti"
25
+ task :uninstall do
26
+ sh "gem uninstall ta-te-ti"
27
+ end
28
+
29
+ desc "Hide gem ta-te-ti in rubygems.org"
30
+ task :unpublish, :version do |args|
31
+ sh "gem yank ta-te-ti -v #{args[:version]}"
32
+ end
33
+
34
+ desc "Show all published versions of gem ta-te-ti"
35
+ task :published do
36
+ sh "gem list ta-te-ti --remote --all"
37
+ end
38
+
data/bin/ta_te_ti.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'ta_te_ti'
2
+
3
+ if ARGV.size > 0 and ARGV[0] == "-d"
4
+ game = TaTeTi::Game.new TaTeTi::HumanPlayer, TaTeTi::DumbPlayer
5
+ else
6
+ game = TaTeTi::Game.new TaTeTi::HumanPlayer, TaTeTi::SmartPlayer
7
+ end
8
+ game.play
data/lib/ta_te_ti.rb ADDED
@@ -0,0 +1,20 @@
1
+ require "ta_te_ti/board"
2
+ require "ta_te_ti/player"
3
+ require "ta_te_ti/human_player"
4
+ require "ta_te_ti/dumb_player"
5
+ require "ta_te_ti/smart_player"
6
+ require "ta_te_ti/game"
7
+
8
+ require "ta_te_ti/version"
9
+
10
+ module TaTeTi
11
+ end
12
+
13
+ if __FILE__ == $0
14
+ if ARGV.size > 0 and ARGV[0] == "-d"
15
+ game = TaTeTi::Game.new TaTeTi::HumanPlayer, TaTeTi::DumbPlayer
16
+ else
17
+ game = TaTeTi::Game.new TaTeTi::HumanPlayer, TaTeTi::SmartPlayer
18
+ end
19
+ game.play
20
+ end
@@ -0,0 +1,108 @@
1
+ require 'ta_te_ti/squares_container'
2
+
3
+ module TaTeTi
4
+ class Board
5
+ attr_reader :squares
6
+
7
+ class Row
8
+ attr_reader :squares, :names
9
+
10
+ def initialize( squares, names )
11
+ @squares = squares
12
+ @names = names
13
+ end
14
+
15
+ include SquaresContainer
16
+
17
+ def to_board_name( index )
18
+ Board.index_to_name(@names[index])
19
+ end
20
+
21
+ def ==(other)
22
+ (@squares == other.squares) && (@names == other.names)
23
+ end
24
+ end
25
+
26
+ MOVES = %w{a1 a2 a3 b1 b2 b3 c1 c2 c3}
27
+ # Define constant INDICES
28
+ INDICES = Hash.new { |h, k| h[k] = MOVES.find_index(k) }
29
+
30
+ def self.name_to_index( name )# Receives "b2" and returns 4
31
+ INDICES[name]
32
+ end
33
+
34
+ def self.index_to_name( index ) # Receives the index, like 4 and returns "b2"
35
+ MOVES[index]
36
+ end
37
+
38
+ def initialize( squares )
39
+ @squares = squares # An array of Strings: [ " ", " ", " ", " ", "X", " ", " ", " ", "O"]
40
+ end
41
+
42
+ include SquaresContainer
43
+
44
+ def []( *indices )
45
+ if indices.size == 2 # board[1,2] is @squares[7]
46
+ super indices[0] + indices[1] * 3 # calls SquaresContainer [] method
47
+ elsif indices[0].is_a? Fixnum # board[7]
48
+ super indices[0]
49
+ else # board["b2"]
50
+ super Board.name_to_index(indices[0].to_s)
51
+ end
52
+ end
53
+
54
+ def []=(indice, value) # board["b2"] = "X"
55
+ m = Board.name_to_index(indice)
56
+ @squares[m] = value
57
+ end
58
+
59
+ HORIZONTALS = [ [0, 1, 2], [3, 4, 5], [6, 7, 8] ]
60
+ COLUMNS = [ [0, 3, 6], [1, 4, 7], [2, 5, 8] ]
61
+ DIAGONALS = [ [0, 4, 8], [2, 4, 6] ]
62
+ ROWS = HORIZONTALS + COLUMNS + DIAGONALS
63
+
64
+ def each_row
65
+ ROWS.each do |e|
66
+ yield Row.new(@squares.values_at(*e), e)
67
+ end
68
+ end
69
+
70
+ def moves
71
+ moves = [ ]
72
+ @squares.each_with_index do |s, i|
73
+ moves << Board.index_to_name(i) if s == " "
74
+ end
75
+ moves # returns the set of feasible moves [ "b3", "c2", ... ]
76
+ end
77
+
78
+ def won?
79
+ each_row do |row|
80
+ return "X" if row.xs == 3 # "X" wins
81
+ return "O" if row.os == 3 # "O" wins
82
+ end
83
+ return " " if blanks == 0 # tie
84
+ false
85
+ end
86
+
87
+ BOARD =<<EOS
88
+
89
+ +---+---+---+
90
+ a | 0 | 1 | 2 |
91
+ +---+---+---+
92
+ b | 3 | 4 | 5 |
93
+ +---+---+---+
94
+ c | 6 | 7 | 8 |
95
+ +---+---+---+
96
+ 1 2 3
97
+
98
+ EOS
99
+ def to_s
100
+ BOARD.gsub(/(\d)(?= \|)/) { |i| @squares[i.to_i] }
101
+ end
102
+
103
+ def ==(other)
104
+ (@squares == other.squares)
105
+ end
106
+
107
+ end
108
+ end
@@ -0,0 +1,25 @@
1
+ module TaTeTi
2
+ class DumbPlayer < Player
3
+ def move( board )
4
+ moves = board.moves
5
+ moves[rand(moves.size)]
6
+ end
7
+
8
+ def finish( final_board )
9
+ # print final_board
10
+
11
+ if final_board.won? == @mark
12
+ # print "Congratulations, you win.\n\n"
13
+ win = 1
14
+ elsif final_board.won? == " "
15
+ # print "Tie game.\n\n"
16
+ win = 0
17
+ else
18
+ # print "You lost tic-tac-toe?!\n\n"
19
+ win = -1
20
+ end
21
+ win
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ require 'ta_te_ti/board'
2
+
3
+ module TaTeTi
4
+ class Game
5
+ def initialize( player1, player2, random = true )
6
+ if random and rand(2) == 1
7
+ @x_player = player2.new("X")
8
+ @o_player = player1.new("O")
9
+ else
10
+ @x_player = player1.new("X")
11
+ @o_player = player2.new("O")
12
+ end
13
+
14
+ @board = Board.new([" "] * 9)
15
+ end
16
+
17
+ attr_reader :x_player, :o_player
18
+
19
+ def play
20
+ until @board.won?
21
+ @board[@x_player.move(@board)] = @x_player.mark
22
+ break if @board.won?
23
+
24
+ @board[@o_player.move(@board)] = @o_player.mark
25
+ end
26
+
27
+ @o_player.finish @board
28
+ @x_player.finish @board
29
+
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ module TaTeTi
2
+ class HumanPlayer < Player
3
+ def move( board )
4
+ print board
5
+
6
+ moves = board.moves
7
+ print "Your move? (format: b3) "
8
+ move = $stdin.gets
9
+ until moves.include?(move.chomp.downcase)
10
+ print "Invalid move. Try again. "
11
+ move = $stdin.gets
12
+ end
13
+ move.chomp
14
+ end
15
+
16
+ def finish( final_board )
17
+ print final_board
18
+
19
+ if final_board.won? == @mark
20
+ print "Congratulations, you win.\n\n"
21
+ elsif final_board.won? == " "
22
+ print "Tie game.\n\n"
23
+ else
24
+ print "You lost tic-tac-toe?!\n\n"
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ module TaTeTi
2
+ class Player
3
+ def initialize( mark )
4
+ @mark = mark # "X" or "O" or " "
5
+ end
6
+
7
+ attr_reader :mark
8
+
9
+ def move( board )
10
+ raise NotImplementedError, "Player subclasses must define move()."
11
+ end
12
+
13
+ def finish( final_board )
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,57 @@
1
+ module TaTeTi
2
+ class SmartPlayer < Player
3
+ def move( board )
4
+ moves = board.moves
5
+
6
+ # If I have a win, take it. If he is threatening to win, stop it.
7
+ board.each_row do |row|
8
+ if row.blanks == 1 and (row.xs == 2 or row.os == 2)
9
+ (0..2).each do |e|
10
+ return row.to_board_name(e) if row[e] == " "
11
+ end
12
+ end
13
+ end
14
+
15
+ # Take the center if open.
16
+ return "b2" if moves.include? "b2"
17
+
18
+ # Defend opposite corners.
19
+ if board[0] != @mark and board[0] != " " and board[8] == " "
20
+ return "c3"
21
+ elsif board[8] != @mark and board[8] != " " and board[0] == " "
22
+ return "a1"
23
+ elsif board[2] != @mark and board[2] != " " and board[6] == " "
24
+ return "c1"
25
+ elsif board[6] != @mark and board[6] != " " and board[2] == " "
26
+ return "a3"
27
+ end
28
+
29
+ # Defend against the special case XOX on a diagonal.
30
+ if board.xs == 2 and board.os == 1 and board[4] == "O" and
31
+ (board[0] == "X" and board[8] == "X") or
32
+ (board[2] == "X" and board[6] == "X")
33
+ return %w{a2 b1 b3 c2}[rand(4)]
34
+ end
35
+
36
+ # Or make a random move.
37
+ moves[rand(moves.size)]
38
+ end
39
+
40
+ def finish( final_board )
41
+ print final_board
42
+
43
+ if final_board.won? == @mark
44
+ print "Congratulations, you win.\n\n"
45
+ win = 1
46
+ elsif final_board.won? == " "
47
+ print "Tie game.\n\n"
48
+ win = 0
49
+ else
50
+ print "You lost tic-tac-toe?!\n\n"
51
+ win = -1
52
+ end
53
+ win
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,7 @@
1
+ module SquaresContainer
2
+ def []( index ) @squares[index] end
3
+
4
+ def blanks() @squares.find_all { |s| s == " " }.size end
5
+ def os() @squares.find_all { |s| s == "O" }.size end
6
+ def xs() @squares.find_all { |s| s == "X" }.size end
7
+ end
@@ -0,0 +1,3 @@
1
+ module TaTeTi
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,36 @@
1
+ require 'ta_te_ti'
2
+
3
+ describe do
4
+ before :all do
5
+ @fila = TaTeTi::Board::Row.new(["0","X",""],[0,1,2])
6
+ @board = TaTeTi::Board.new([ " ", " ", " ", " ", "X", " ", " ", " ","O"])
7
+ @human_player = TaTeTi::HumanPlayer.new("X")
8
+ @dumb_player = TaTeTi::DumbPlayer.new("0")
9
+ @smart_player = TaTeTi::SmartPlayer.new("0")
10
+ @gameD = TaTeTi::Game.new TaTeTi::SmartPlayer, TaTeTi::DumbPlayer
11
+ end
12
+
13
+ it "Debe existir una clase para representar una fila del tablero" do
14
+ @fila.should == TaTeTi::Board::Row.new(["0","X",""],[0,1,2])
15
+ end
16
+
17
+ it "Debe existir una clase para representar al tablero" do
18
+ @board.should == TaTeTi::Board.new([ " ", " ", " ", " ", "X", " ", " ", " ","O"])
19
+ end
20
+
21
+ it "Debe existir una clase para representar al jugador humano" do
22
+ @human_player.mark.should == "X"
23
+ end
24
+
25
+ it "Debe existir una clase para representar un juego simple de la maquina" do
26
+ @dumb_player.mark.should == "0"
27
+ end
28
+
29
+ it "Debe existir una clase para representar un juego inteligente de la maquina" do
30
+ @smart_player.mark.should == "0"
31
+ end
32
+
33
+ it "Debe existir una clase para representar un juego" do
34
+ [-1,0,1].should include(@gameD.play)
35
+ end
36
+ end
data/ta_te_ti.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "ta_te_ti/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "ta-te-ti"
7
+ s.version = TaTeTi::VERSION
8
+ s.authors = ["Coromoto Leon"]
9
+ s.email = ["cleon@ull.es"]
10
+ s.homepage = ""
11
+ s.summary = %q{Gema para jugar al tres en raya}
12
+ s.description = %q{Juego del tres en raya}
13
+
14
+ s.rubyforge_project = "ta_te_ti"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency "rspec"
23
+ # s.add_runtime_dependency "rest-client"
24
+ end
@@ -0,0 +1,23 @@
1
+ require 'ta_te_ti'
2
+
3
+ require 'test/unit'
4
+
5
+ class JuegoTaTeTi < Test::Unit::TestCase
6
+
7
+ def setup
8
+ # si se define una variable de instancia, el juego no se actualiza aleatoriamente porqu solo hay una
9
+ end
10
+
11
+ def teardown
12
+ #nada, la memoria se libera automaticamente
13
+ end
14
+
15
+ def test_play
16
+ score = []
17
+ 30.times do
18
+ ter_obj = TaTeTi::Game.new TaTeTi::DumbPlayer, TaTeTi::DumbPlayer
19
+ score.push ter_obj.play
20
+ end
21
+ assert(score.uniq.length == 3, "score.uniq.length = #{score.uniq.length} score.length = #{score.length}")
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ta-te-ti
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Coromoto Leon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &77550420 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *77550420
25
+ description: Juego del tres en raya
26
+ email:
27
+ - cleon@ull.es
28
+ executables:
29
+ - ta_te_ti.rb
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - .gitignore
34
+ - .travis.yml
35
+ - Gemfile
36
+ - Guardfile
37
+ - README
38
+ - Rakefile
39
+ - bin/ta_te_ti.rb
40
+ - lib/ta_te_ti.rb
41
+ - lib/ta_te_ti/board.rb
42
+ - lib/ta_te_ti/dumb_player.rb
43
+ - lib/ta_te_ti/game.rb
44
+ - lib/ta_te_ti/human_player.rb
45
+ - lib/ta_te_ti/player.rb
46
+ - lib/ta_te_ti/smart_player.rb
47
+ - lib/ta_te_ti/squares_container.rb
48
+ - lib/ta_te_ti/version.rb
49
+ - spec/ta_te_ti_spec.rb
50
+ - ta_te_ti.gemspec
51
+ - test/tc_ta_te_ti.rb
52
+ homepage: ''
53
+ licenses: []
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubyforge_project: ta_te_ti
72
+ rubygems_version: 1.8.11
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Gema para jugar al tres en raya
76
+ test_files: []