tictactoe_alu3286 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.
- data/.gitignore +17 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/Guardfile +6 -0
- data/LICENSE +22 -0
- data/README.md +47 -0
- data/Rakefile +37 -0
- data/bin/tictactoe_game.rb +12 -0
- data/lib/.DS_Store +0 -0
- data/lib/tictactoe_alu3286.rb +36 -0
- data/lib/tictactoe_alu3286/board.rb +104 -0
- data/lib/tictactoe_alu3286/dumbplayer.rb +10 -0
- data/lib/tictactoe_alu3286/humanplayer.rb +30 -0
- data/lib/tictactoe_alu3286/player.rb +16 -0
- data/lib/tictactoe_alu3286/smartplayer.rb +42 -0
- data/lib/tictactoe_alu3286/version.rb +3 -0
- data/spec/dumbplayer_spec.rb +12 -0
- data/spec/humanplayer_spec.rb +15 -0
- data/spec/smartplayer_spec.rb +12 -0
- data/test/tc_dumbplayer.rb +12 -0
- data/test/tc_humanplayer.rb +16 -0
- data/test/tc_smartplayer.rb +12 -0
- data/tictactoe_alu3286.gemspec +17 -0
- metadata +75 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 alu3286
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# TictactoeAlu3286
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'tictactoe_alu3286'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install tictactoe_alu3286
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
30
|
+
|
31
|
+
Enunciado de la práctica:
|
32
|
+
|
33
|
+
Considere el desarrollo de una aplicación para jugar al tres en raya.
|
34
|
+
El objetivo de esta práctica es la creación de una Gema en Ruby para el juego de tres en raya. Para ello se ha de utilizar la herramienta Bundler (http://gembundler.com/)
|
35
|
+
1.- Utilizar bundle para crear la estructura estandar de una gema.
|
36
|
+
Véanse railcast: gems with bundler y el blog polishing rubies
|
37
|
+
bundle gem tictactoe
|
38
|
+
2.- Partiendo de la implementacion del juego que está disponible en github separar a los jugadores en diferentes ficheros y utilizarlos como plugins.
|
39
|
+
3.- Escribir un conjunto de pruebas unitarias (Unit Testing)
|
40
|
+
test/tc_tictactoe.rb
|
41
|
+
4.- Escribir un fichero de espectativas de comportamiento (BDD)
|
42
|
+
spec/tictactoe_spec.rb
|
43
|
+
5.- Realizar un seguimiento continuo de las pruebas (Continuous Testing)
|
44
|
+
guard
|
45
|
+
6.- Comprobar el correcto funcionamiento en distintas plataformas (Continuous Integration)
|
46
|
+
travis
|
47
|
+
7.- Indique la URL del repositorio github o bitbucket que ha desarrollado.
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + 'lib'
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
RSpec::Core::RakeTask.new
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
desc "Run TicTacToe game vs smart player"
|
10
|
+
task :smart do
|
11
|
+
sh "ruby -Ilib bin/tictactoe_game.rb"
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Run TicTacToe game vs dumb player"
|
15
|
+
task :dumb do
|
16
|
+
sh "ruby -Ilib bin/tictactoe_game.rb -d"
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Run rspec with --format documentation"
|
20
|
+
task :doc do
|
21
|
+
sh "rspec -Ilib spec/*.rb --format documentation"
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Run HumanPlayer tests"
|
25
|
+
task :hp_test do
|
26
|
+
sh "ruby -Ilib test/tc_humanplayer.rb"
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Run SmartPlayer tests"
|
30
|
+
task :sp_test do
|
31
|
+
sh "ruby -Ilib test/tc_smartplayer.rb"
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Run DumbPlayer tests"
|
35
|
+
task :dp_test do
|
36
|
+
sh "ruby -Ilib test/tc_dumbplayer.rb"
|
37
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "tictactoe_alu3286"
|
2
|
+
|
3
|
+
if __FILE__ == $0
|
4
|
+
if ARGV.size > 0 and ARGV[0] == "-d"
|
5
|
+
game = TictactoeAlu3286::Game.new TictactoeAlu3286::HumanPlayer,
|
6
|
+
TictactoeAlu3286::DumbPlayer
|
7
|
+
else
|
8
|
+
game = TictactoeAlu3286::Game.new TictactoeAlu3286::HumanPlayer,
|
9
|
+
TictactoeAlu3286::SmartPlayer
|
10
|
+
end
|
11
|
+
game.play
|
12
|
+
end
|
data/lib/.DS_Store
ADDED
Binary file
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "tictactoe_alu3286/version"
|
2
|
+
require "tictactoe_alu3286/humanplayer"
|
3
|
+
require "tictactoe_alu3286/smartplayer"
|
4
|
+
require "tictactoe_alu3286/dumbplayer"
|
5
|
+
require "tictactoe_alu3286/board"
|
6
|
+
|
7
|
+
module TictactoeAlu3286
|
8
|
+
class Game
|
9
|
+
def initialize( player1, player2, random = true )
|
10
|
+
if random and rand(2) == 1
|
11
|
+
@x_player = player2.new("X")
|
12
|
+
@o_player = player1.new("O")
|
13
|
+
else
|
14
|
+
@x_player = player1.new("X")
|
15
|
+
@o_player = player2.new("O")
|
16
|
+
end
|
17
|
+
|
18
|
+
@board = Board.new([" "] * 9)
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :x_player, :o_player
|
22
|
+
|
23
|
+
def play
|
24
|
+
until @board.won?
|
25
|
+
@board[@x_player.move(@board)] = @x_player.mark
|
26
|
+
break if @board.won?
|
27
|
+
|
28
|
+
@board[@o_player.move(@board)] = @o_player.mark
|
29
|
+
end
|
30
|
+
|
31
|
+
@o_player.finish @board
|
32
|
+
@x_player.finish @board
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module TictactoeAlu3286
|
2
|
+
module SquaresContainer
|
3
|
+
def []( index ) @squares[index] end
|
4
|
+
|
5
|
+
def blanks() @squares.find_all { |s| s == " " }.size end
|
6
|
+
def os() @squares.find_all { |s| s == "O" }.size end
|
7
|
+
def xs() @squares.find_all { |s| s == "X" }.size end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Board
|
11
|
+
class Row
|
12
|
+
def initialize( squares, names )
|
13
|
+
@squares = squares
|
14
|
+
@names = names
|
15
|
+
end
|
16
|
+
|
17
|
+
include SquaresContainer
|
18
|
+
|
19
|
+
def to_board_name( index )
|
20
|
+
Board.index_to_name(@names[index])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
MOVES = %w{a1 a2 a3 b1 b2 b3 c1 c2 c3}
|
25
|
+
# Define constant INDICES
|
26
|
+
INDICES = Hash.new { |h, k| h[k] = MOVES.find_index(k) }
|
27
|
+
|
28
|
+
def self.name_to_index( name )# Receives "b2" and returns 4
|
29
|
+
INDICES[name]
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.index_to_name( index ) # Receives the index, like 4 and returns "b2"
|
33
|
+
MOVES[index]
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize( squares )
|
37
|
+
@squares = squares # An array of Strings: [ " ", " ", " ", " ", "X", " ", " ", " ", "O"]
|
38
|
+
end
|
39
|
+
|
40
|
+
include SquaresContainer
|
41
|
+
|
42
|
+
def []( *indices )
|
43
|
+
if indices.size == 2 # board[1,2] is @squares[7]
|
44
|
+
super indices[0] + indices[1] * 3 # calls SquaresContainer [] method
|
45
|
+
elsif indices[0].is_a? Fixnum # board[7]
|
46
|
+
super indices[0]
|
47
|
+
else # board["b2"]
|
48
|
+
super Board.name_to_index(indices[0].to_s)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def []=(indice, value) # board["b2"] = "X"
|
53
|
+
m = Board.name_to_index(indice)
|
54
|
+
@squares[m] = value
|
55
|
+
end
|
56
|
+
|
57
|
+
HORIZONTALS = [ [0, 1, 2], [3, 4, 5], [6, 7, 8] ]
|
58
|
+
COLUMNS = [ [0, 3, 6], [1, 4, 7], [2, 5, 8] ]
|
59
|
+
DIAGONALS = [ [0, 4, 8], [2, 4, 6] ]
|
60
|
+
ROWS = HORIZONTALS + COLUMNS + DIAGONALS
|
61
|
+
|
62
|
+
def each_row
|
63
|
+
ROWS.each do |e|
|
64
|
+
yield Row.new(@squares.values_at(*e), e)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def moves
|
69
|
+
moves = [ ]
|
70
|
+
@squares.each_with_index do |s, i|
|
71
|
+
moves << Board.index_to_name(i) if s == " "
|
72
|
+
end
|
73
|
+
moves # returns the set of feasible moves [ "b3", "c2", ... ]
|
74
|
+
end
|
75
|
+
|
76
|
+
def won?
|
77
|
+
each_row do |row|
|
78
|
+
return "X" if row.xs == 3 # "X" wins
|
79
|
+
return "O" if row.os == 3 # "O" wins
|
80
|
+
end
|
81
|
+
return " " if blanks == 0 # tie
|
82
|
+
false
|
83
|
+
end
|
84
|
+
|
85
|
+
BOARD =<<EOS
|
86
|
+
|
87
|
+
+---+---+---+
|
88
|
+
a | 0 | 1 | 2 |
|
89
|
+
+---+---+---+
|
90
|
+
b | 3 | 4 | 5 |
|
91
|
+
+---+---+---+
|
92
|
+
c | 6 | 7 | 8 |
|
93
|
+
+---+---+---+
|
94
|
+
1 2 3
|
95
|
+
|
96
|
+
EOS
|
97
|
+
def to_s
|
98
|
+
BOARD.gsub(/(\d)(?= \|)/) { |i| @squares[i.to_i] }
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "tictactoe_alu3286/player"
|
2
|
+
|
3
|
+
module TictactoeAlu3286
|
4
|
+
class HumanPlayer < Player
|
5
|
+
def move( board )
|
6
|
+
print board
|
7
|
+
|
8
|
+
moves = board.moves
|
9
|
+
print "Your move? (format: b3) "
|
10
|
+
move = $stdin.gets
|
11
|
+
until moves.include?(move.chomp.downcase)
|
12
|
+
print "Invalid move. Try again. "
|
13
|
+
move = $stdin.gets
|
14
|
+
end
|
15
|
+
move.chomp
|
16
|
+
end
|
17
|
+
|
18
|
+
def finish( final_board )
|
19
|
+
print final_board
|
20
|
+
|
21
|
+
if final_board.won? == @mark
|
22
|
+
print "Congratulations, you win.\n\n"
|
23
|
+
elsif final_board.won? == " "
|
24
|
+
print "Tie game.\n\n"
|
25
|
+
else
|
26
|
+
print "You lost tic-tac-toe?!\n\n"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module TictactoeAlu3286
|
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,42 @@
|
|
1
|
+
require "tictactoe_alu3286/player"
|
2
|
+
|
3
|
+
module TictactoeAlu3286
|
4
|
+
class SmartPlayer < Player
|
5
|
+
def move( board )
|
6
|
+
moves = board.moves
|
7
|
+
|
8
|
+
# If I have a win, take it. If he is threatening to win, stop it.
|
9
|
+
board.each_row do |row|
|
10
|
+
if row.blanks == 1 and (row.xs == 2 or row.os == 2)
|
11
|
+
(0..2).each do |e|
|
12
|
+
return row.to_board_name(e) if row[e] == " "
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Take the center if open.
|
18
|
+
return "b2" if moves.include? "b2"
|
19
|
+
|
20
|
+
# Defend opposite corners.
|
21
|
+
if board[0] != @mark and board[0] != " " and board[8] == " "
|
22
|
+
return "c3"
|
23
|
+
elsif board[8] != @mark and board[8] != " " and board[0] == " "
|
24
|
+
return "a1"
|
25
|
+
elsif board[2] != @mark and board[2] != " " and board[6] == " "
|
26
|
+
return "c1"
|
27
|
+
elsif board[6] != @mark and board[6] != " " and board[2] == " "
|
28
|
+
return "a3"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Defend against the special case XOX on a diagonal.
|
32
|
+
if board.xs == 2 and board.os == 1 and board[4] == "O" and
|
33
|
+
(board[0] == "X" and board[8] == "X") or
|
34
|
+
(board[2] == "X" and board[6] == "X")
|
35
|
+
return %w{a2 b1 b3 c2}[rand(4)]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Or make a random move.
|
39
|
+
moves[rand(moves.size)]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "tictactoe_alu3286"
|
2
|
+
|
3
|
+
describe TictactoeAlu3286::HumanPlayer do
|
4
|
+
before :each do
|
5
|
+
@hp = TictactoeAlu3286::HumanPlayer.new("X")
|
6
|
+
end
|
7
|
+
|
8
|
+
it "Debe existir un metodo move" do
|
9
|
+
@hp.respond_to?("move").should == true
|
10
|
+
end
|
11
|
+
|
12
|
+
it "Debe existir un metodo finish" do
|
13
|
+
@hp.respond_to?("finish").should == true
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "tictactoe_alu3286"
|
2
|
+
require "test/unit"
|
3
|
+
|
4
|
+
class TestHumanPlayer < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@hp = TictactoeAlu3286::HumanPlayer.new("X")
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_implements_move
|
10
|
+
assert_equal true, @hp.respond_to?("move")
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_implements_finish
|
14
|
+
assert_equal true, @hp.respond_to?("finish")
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/tictactoe_alu3286/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["alu3286"]
|
6
|
+
gem.email = ["eaculed@gmail.com"]
|
7
|
+
gem.description = %q{Juego de tres en raya}
|
8
|
+
gem.summary = %q{Tres en raya}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "tictactoe_alu3286"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = TictactoeAlu3286::VERSION
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tictactoe_alu3286
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- alu3286
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-26 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Juego de tres en raya
|
15
|
+
email:
|
16
|
+
- eaculed@gmail.com
|
17
|
+
executables:
|
18
|
+
- tictactoe_game.rb
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gitignore
|
23
|
+
- .travis.yml
|
24
|
+
- Gemfile
|
25
|
+
- Guardfile
|
26
|
+
- LICENSE
|
27
|
+
- README.md
|
28
|
+
- Rakefile
|
29
|
+
- bin/tictactoe_game.rb
|
30
|
+
- lib/.DS_Store
|
31
|
+
- lib/tictactoe_alu3286.rb
|
32
|
+
- lib/tictactoe_alu3286/board.rb
|
33
|
+
- lib/tictactoe_alu3286/dumbplayer.rb
|
34
|
+
- lib/tictactoe_alu3286/humanplayer.rb
|
35
|
+
- lib/tictactoe_alu3286/player.rb
|
36
|
+
- lib/tictactoe_alu3286/smartplayer.rb
|
37
|
+
- lib/tictactoe_alu3286/version.rb
|
38
|
+
- spec/dumbplayer_spec.rb
|
39
|
+
- spec/humanplayer_spec.rb
|
40
|
+
- spec/smartplayer_spec.rb
|
41
|
+
- test/tc_dumbplayer.rb
|
42
|
+
- test/tc_humanplayer.rb
|
43
|
+
- test/tc_smartplayer.rb
|
44
|
+
- tictactoe_alu3286.gemspec
|
45
|
+
homepage: ''
|
46
|
+
licenses: []
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
requirements: []
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.8.24
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Tres en raya
|
69
|
+
test_files:
|
70
|
+
- spec/dumbplayer_spec.rb
|
71
|
+
- spec/humanplayer_spec.rb
|
72
|
+
- spec/smartplayer_spec.rb
|
73
|
+
- test/tc_dumbplayer.rb
|
74
|
+
- test/tc_humanplayer.rb
|
75
|
+
- test/tc_smartplayer.rb
|