ta-te-ti 0.0.2

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