tundengine 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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +21 -0
  4. data/README.md +29 -0
  5. data/Rakefile +8 -0
  6. data/lib/tundengine.rb +67 -0
  7. data/lib/tundengine/algebraic_data_type.rb +33 -0
  8. data/lib/tundengine/card_percolator.rb +9 -0
  9. data/lib/tundengine/cards/card.rb +63 -0
  10. data/lib/tundengine/cards/null.rb +18 -0
  11. data/lib/tundengine/dealer.rb +52 -0
  12. data/lib/tundengine/deck.rb +41 -0
  13. data/lib/tundengine/declarations/base.rb +24 -0
  14. data/lib/tundengine/declarations/las_cuarenta.rb +15 -0
  15. data/lib/tundengine/declarations/las_veinte.rb +29 -0
  16. data/lib/tundengine/declarations/null.rb +18 -0
  17. data/lib/tundengine/declarations/tute.rb +23 -0
  18. data/lib/tundengine/declarations/void.rb +15 -0
  19. data/lib/tundengine/hand.rb +35 -0
  20. data/lib/tundengine/move.rb +13 -0
  21. data/lib/tundengine/null_move.rb +13 -0
  22. data/lib/tundengine/player/in_match.rb +29 -0
  23. data/lib/tundengine/player/in_round.rb +71 -0
  24. data/lib/tundengine/player/in_turn.rb +31 -0
  25. data/lib/tundengine/ranks/base.rb +31 -0
  26. data/lib/tundengine/ranks/cinco.rb +10 -0
  27. data/lib/tundengine/ranks/cuatro.rb +10 -0
  28. data/lib/tundengine/ranks/diez.rb +10 -0
  29. data/lib/tundengine/ranks/doce.rb +10 -0
  30. data/lib/tundengine/ranks/dos.rb +10 -0
  31. data/lib/tundengine/ranks/null.rb +10 -0
  32. data/lib/tundengine/ranks/once.rb +10 -0
  33. data/lib/tundengine/ranks/seis.rb +10 -0
  34. data/lib/tundengine/ranks/siete.rb +10 -0
  35. data/lib/tundengine/ranks/tres.rb +10 -0
  36. data/lib/tundengine/ranks/uno.rb +10 -0
  37. data/lib/tundengine/ranks/white.rb +9 -0
  38. data/lib/tundengine/round_analyzer.rb +67 -0
  39. data/lib/tundengine/stages/base.rb +74 -0
  40. data/lib/tundengine/stages/match.rb +80 -0
  41. data/lib/tundengine/stages/null.rb +13 -0
  42. data/lib/tundengine/stages/round.rb +85 -0
  43. data/lib/tundengine/stages/tournament.rb +72 -0
  44. data/lib/tundengine/stages/trick.rb +90 -0
  45. data/lib/tundengine/stages/turn.rb +44 -0
  46. data/lib/tundengine/strategies/automatic.rb +27 -0
  47. data/lib/tundengine/strategies/base.rb +8 -0
  48. data/lib/tundengine/strategies/manual.rb +33 -0
  49. data/lib/tundengine/strategies/random.rb +15 -0
  50. data/lib/tundengine/stringifiable_by_class.rb +9 -0
  51. data/lib/tundengine/suits/base.rb +19 -0
  52. data/lib/tundengine/suits/basto.rb +7 -0
  53. data/lib/tundengine/suits/copa.rb +7 -0
  54. data/lib/tundengine/suits/espada.rb +7 -0
  55. data/lib/tundengine/suits/null.rb +14 -0
  56. data/lib/tundengine/suits/oro.rb +7 -0
  57. data/lib/tundengine/tute_values/base.rb +17 -0
  58. data/lib/tundengine/tute_values/capotes.rb +22 -0
  59. data/lib/tundengine/tute_values/nothing.rb +13 -0
  60. data/lib/tundengine/tute_values/victory.rb +17 -0
  61. data/lib/tundengine/version.rb +17 -0
  62. data/test/test_card_strength.rb +58 -0
  63. data/test/test_helper.rb +35 -0
  64. data/test/test_playable_cards.rb +66 -0
  65. data/test/test_random_tournaments.rb +31 -0
  66. data/tundengine.gemspec +28 -0
  67. metadata +154 -0
@@ -0,0 +1,27 @@
1
+ module Tundengine
2
+ module Strategies
3
+ class Automatic < Base
4
+
5
+ def play!(player_in_turn, card)
6
+ selected_card = card.self_or_yield do
7
+ play(player_in_turn)
8
+ end
9
+
10
+ player_in_turn.after_playing!(selected_card)
11
+ end
12
+
13
+ def declare!(player_in_round, declaration)
14
+ selected_declaration = declaration.self_or_yield do
15
+ declare(player_in_round)
16
+ end
17
+
18
+ player_in_round.after_declaring!(selected_declaration)
19
+ end
20
+
21
+ def on_winning_trick!(player_in_round)
22
+ player_in_round.declare!
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,8 @@
1
+ module Tundengine
2
+ module Strategies
3
+ class Base
4
+
5
+
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,33 @@
1
+ module Tundengine
2
+ module Strategies
3
+ class Manual < Base
4
+
5
+ def play!(player_in_turn, card)
6
+ card.yield_self_or_lock!(player_in_turn.turn) do |c|
7
+ do_play!(player_in_turn, c)
8
+ end
9
+ end
10
+
11
+ def declare!(player_in_round, declaration)
12
+ declaration.yield_self_or_lock!(player_in_round.round) do |d|
13
+ do_declare!(player_in_round, d)
14
+ end
15
+ end
16
+
17
+ def on_winning_trick!(player_in_round)
18
+ # do nothing
19
+ end
20
+
21
+ protected
22
+
23
+ def do_play!(player_in_turn, card)
24
+ player_in_turn.after_playing!(card)
25
+ end
26
+
27
+ def do_declare!(player_in_round, declaration)
28
+ player_in_round.after_declaring!(declaration)
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ module Tundengine
2
+ module Strategies
3
+ class Random < Automatic
4
+
5
+ def play(player_in_turn)
6
+ player_in_turn.hand.playable_cards(player_in_turn.turn.trick).first.first
7
+ end
8
+
9
+ def declare(player_in_round)
10
+ Declarations::Void.instance
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module Tundengine
2
+ module StringifiableByClass
3
+
4
+ def to_s
5
+ self.class.name.split('::').last
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ module Tundengine
2
+ module Suits
3
+ class Base
4
+
5
+ include Singleton
6
+ include StringifiableByClass
7
+ include CardPercolator
8
+
9
+ protected
10
+
11
+ def is_of_this_suit?(card)
12
+ card.suit == self
13
+ end
14
+ alias_method :passes_card_percolator?, :is_of_this_suit?
15
+
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,7 @@
1
+ module Tundengine
2
+ module Suits
3
+ class Basto < Base
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Tundengine
2
+ module Suits
3
+ class Copa < Base
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Tundengine
2
+ module Suits
3
+ class Espada < Base
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ module Tundengine
2
+ module Suits
3
+ class Null < Base
4
+
5
+ protected
6
+
7
+ def is_of_this_suit?(card)
8
+ true
9
+ end
10
+ alias_method :passes_card_percolator?, :is_of_this_suit?
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ module Tundengine
2
+ module Suits
3
+ class Oro < Base
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ module Tundengine
2
+ module TuteValues
3
+ class Base
4
+
5
+ include StringifiableByClass
6
+
7
+ def has_effect?
8
+ true
9
+ end
10
+
11
+ def finishes_round?
12
+ false
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ module Tundengine
2
+ module TuteValues
3
+ class Capotes < Base
4
+
5
+ include AlgebraicDataType
6
+
7
+ def initialize(points)
8
+ @points = points
9
+ super()
10
+ end
11
+
12
+ def points_for_loser(loser, max_points)
13
+ [@points, max_points].min
14
+ end
15
+
16
+ def identifier
17
+ [@points]
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ module Tundengine
2
+ module TuteValues
3
+ class Nothing < Base
4
+
5
+ include Singleton
6
+
7
+ def has_effect?
8
+ false
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module Tundengine
2
+ module TuteValues
3
+ class Victory < Base
4
+
5
+ include Singleton
6
+
7
+ def finishes_round?
8
+ true
9
+ end
10
+
11
+ def points_for_loser(loser, max_points)
12
+ max_points - loser.match_points
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Tundengine
2
+ class Version
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ PATCH = 1
6
+ PRE = nil
7
+
8
+ class << self
9
+
10
+ def to_s
11
+ [MAJOR, MINOR, PATCH, PRE].compact.join('.')
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,58 @@
1
+ require 'minitest/autorun'
2
+ require 'tundengine'
3
+
4
+ class TestCardStrength < Minitest::Test
5
+
6
+ def setup
7
+ @all_suits = Tundengine::Deck::SUITS
8
+ @all_cards = Tundengine::Deck::CARDS
9
+ end
10
+
11
+ def test_that_null_always_loses
12
+
13
+ null_card = Tundengine::Cards::Null.instance
14
+
15
+ @all_suits.each do |trump_suit|
16
+ @all_cards.each do |card|
17
+ assert_equal(true, card.beats?(null_card, trump_suit))
18
+ assert_equal(false, null_card.beats?(card, trump_suit))
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ def test_that_trump_always_wins_against_no_trump
25
+
26
+ @all_suits.each do |trump_suit|
27
+ trump_cards, no_trump_cards = trump_suit.percolate(@all_cards, :partition)
28
+ pairs = trump_cards.product(no_trump_cards)
29
+
30
+ pairs.each do |trump_card, no_trump_card|
31
+ assert_equal(true, trump_card.beats?(no_trump_card, trump_suit))
32
+ assert_equal(false, no_trump_card.beats?(trump_card, trump_suit))
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ def test_strength_with_no_trumps
39
+
40
+ @all_suits.each do |trump_suit|
41
+ _, no_trump_cards = trump_suit.percolate(@all_cards, :partition)
42
+ pairs = no_trump_cards.product(no_trump_cards)
43
+ same_suit, different_suits = pairs.partition { |c1, c2| c1.suit == c2.suit }
44
+
45
+ same_suit.each do |c1, c2|
46
+ assert_equal(c1.rank > c2.rank, c1.beats?(c2, trump_suit))
47
+ assert_equal(c1.rank < c2.rank, c2.beats?(c1, trump_suit))
48
+ end
49
+
50
+ different_suits.each do |c1, c2|
51
+ assert_equal(false, c1.beats?(c2, trump_suit))
52
+ assert_equal(false, c2.beats?(c1, trump_suit))
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,35 @@
1
+ require 'tundengine'
2
+
3
+ module TestHelper
4
+
5
+ def setup!(strategies = :all_automatic)
6
+ strategy = Tundengine::Strategies::Random.new if strategies == :all_automatic
7
+ strategy = Tundengine::Strategies::Manual.new if strategies == :all_manual
8
+
9
+ @@all_ranks = Tundengine::Deck::RANKS
10
+ @@all_suits = Tundengine::Deck::SUITS
11
+ @@all_cards = Tundengine::Deck::CARDS
12
+
13
+ @@players = %w(Mati Mar Pablito Mary Euge).map do |name|
14
+ Tundengine::Player::InMatch.new(name, strategy)
15
+ end
16
+
17
+ @@tournament_options = {
18
+ max_matches: 1,
19
+ match_settings: {
20
+ max_points: 4,
21
+ tute_value: Tundengine::TuteValues::Nothing.instance,
22
+ losing_position: :second # the alternative is :not_first_or_last
23
+ }
24
+ }
25
+
26
+ @@new_tournament = Tundengine::Stages::Tournament.new(@@players, @@tournament_options)
27
+ @@new_match = @@new_tournament.current_match
28
+ @@new_round = @@new_match.current_round
29
+ @@new_trick = @@new_round.current_trick
30
+ @@new_turn = @@new_trick.current_turn
31
+ @@new_player = @@new_turn.player
32
+ @@new_hand = @@new_player.hand
33
+ end
34
+
35
+ end
@@ -0,0 +1,66 @@
1
+ require 'minitest/autorun'
2
+ require 'tundengine'
3
+ require_relative './test_helper'
4
+
5
+ class TestPlayableCards < Minitest::Test
6
+
7
+ include TestHelper
8
+
9
+ def test_starting_first_trick
10
+
11
+ setup!
12
+
13
+ expected = [@@new_hand, true]
14
+ actual = @@new_hand.playable_cards(@@new_trick)
15
+
16
+ assert_equal expected, actual
17
+ end
18
+
19
+ def test_starting_last_trick
20
+
21
+ setup!
22
+
23
+ @@all_cards.each do |card|
24
+ hand = Tundengine::Hand.new([card])
25
+
26
+ expected = [hand, true]
27
+ actual = hand.playable_cards(@@new_trick)
28
+
29
+ assert_equal expected, actual
30
+ end
31
+
32
+ end
33
+
34
+ def test_in_trick_with_one_card
35
+
36
+ setup!(:all_manual)
37
+
38
+ trick = @@new_trick
39
+
40
+ hand = Tundengine::Hand.new([
41
+ Tundengine::Ranks::Cinco.de(Tundengine::Suits::Oro),
42
+ Tundengine::Ranks::Diez .de(Tundengine::Suits::Oro),
43
+ Tundengine::Ranks::Cinco.de(Tundengine::Suits::Copa),
44
+ Tundengine::Ranks::Diez .de(Tundengine::Suits::Copa),
45
+ Tundengine::Ranks::Cinco.de(Tundengine::Suits::Espada),
46
+ Tundengine::Ranks::Diez .de(Tundengine::Suits::Espada),
47
+ Tundengine::Ranks::Cinco.de(Tundengine::Suits::Basto),
48
+ Tundengine::Ranks::Diez. de(Tundengine::Suits::Basto)
49
+ ])
50
+
51
+ @@new_hand << Tundengine::Ranks::Dos.de(Tundengine::Suits::Copa)
52
+ trick.play!( Tundengine::Ranks::Dos.de(Tundengine::Suits::Copa))
53
+
54
+ expected = [Tundengine::Hand.new([
55
+ Tundengine::Ranks::Cinco.de(Tundengine::Suits::Copa),
56
+ Tundengine::Ranks::Diez .de(Tundengine::Suits::Copa)
57
+ ]), true]
58
+
59
+ actual = hand.playable_cards(trick)
60
+
61
+ assert_equal expected, actual
62
+ end
63
+
64
+
65
+
66
+ end
@@ -0,0 +1,31 @@
1
+ require 'minitest/autorun'
2
+ require 'tundengine'
3
+ require_relative './test_helper'
4
+
5
+ class TestRandomTournaments < Minitest::Test
6
+
7
+ include TestHelper
8
+
9
+ def test_three_players
10
+ play_with 3
11
+ end
12
+
13
+ def test_four_players
14
+ play_with 4
15
+ end
16
+
17
+ def test_five_players
18
+ play_with 5
19
+ end
20
+
21
+ protected
22
+
23
+ def play_with(number_of_players)
24
+ setup!
25
+
26
+ players = @@players.take number_of_players
27
+ tournament = Tundengine::Stages::Tournament.new(players, @@tournament_options)
28
+ tournament.play!
29
+ end
30
+
31
+ end