rora 0.0.5 → 0.0.6

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.
@@ -1,14 +1,86 @@
1
1
  #
2
- #
2
+ # A poker table where players compete for pots.
3
3
  #
4
4
  class Table
5
- attr_reader :board, :deck, :pot, :seats
5
+ attr_reader :board, :deck, :pot
6
6
 
7
7
  def initialize seats=nil
8
- @seats = Array.new(seats.nil? ? 9 : seats)
8
+ seats = seats.nil? ? 9 : seats
9
+ raise ArgumentError, "A table must have at least two seats" if seats < 2
10
+ @seats = Array.new seats
9
11
  @board = Board.new
10
12
  @pot = Pot.new
11
13
  @deck = Deck.new
14
+
15
+ @seats.each_index {|index| @seats[index] = Seat.new(index + 1)}
16
+ @seats.each_index do |index|
17
+ @seats[index].next = @seats[index == (seats - 1) ? 0 : index + 1]
18
+ @seats[index].prev = @seats[index == 0 ? seats - 1 : index - 1]
19
+ end
20
+ end
21
+
22
+ def pass_the_buck
23
+ index = the_button.number - 1
24
+ @seats[index].button = nil
25
+ the_seat_after(@seats[index]).button = true
26
+ end
27
+
28
+ def the_button
29
+ raise RuntimeError, "There are fewer than two players at the table" if players.size < 2
30
+ @seats.each_index do |x|
31
+ return @seats[x] if @seats[x].button?
32
+ end
33
+ @seats.each_index do |x|
34
+ return @seats[x] if @seats[x].taken?
35
+ end
36
+ end
37
+
38
+ def the_small_blind
39
+ raise RuntimeError, "There are fewer than two players at the table" if players.size < 2
40
+ players.size == 2 ? the_button : the_seat_after(the_button)
41
+ end
42
+
43
+ def the_big_blind
44
+ raise RuntimeError, "There are fewer than two players at the table" if players.size < 2
45
+ the_seat_after the_small_blind
46
+ end
47
+
48
+ def under_the_gun
49
+ raise RuntimeError, "There are fewer than two players at the table" if players.size < 2
50
+ the_seat_after(the_big_blind)
51
+ end
52
+
53
+ def the_seat_after seat
54
+ raise RuntimeError, "There are fewer than two players at the table" if players.size < 2
55
+ this_seat = seat.next
56
+ return this_seat.taken? ? this_seat : the_seat_after(this_seat)
57
+ end
58
+
59
+ def the_seat_before seat
60
+ raise RuntimeError, "There are fewer than two players at the table" if players.size < 2
61
+ this_seat = seat.prev
62
+ return this_seat.taken? ? this_seat : the_seat_before(this_seat)
63
+ end
64
+
65
+ def with argument
66
+ if argument.kind_of? Deck
67
+ @deck = argument
68
+ end
69
+ if argument.kind_of? Pot
70
+ @pot = argument
71
+ end
72
+ if argument.kind_of? Board
73
+ @board = argument
74
+ end
75
+ self
76
+ end
77
+
78
+ def seat i
79
+ @seats[i - 1]
80
+ end
81
+
82
+ def size
83
+ @seats.size
12
84
  end
13
85
 
14
86
  def reset
@@ -17,24 +89,45 @@ class Table
17
89
  @deck = Deck.new
18
90
  end
19
91
 
92
+ def players
93
+ players = []
94
+ @seats.each do |seat|
95
+ players << seat.player if seat.taken?
96
+ end
97
+ players
98
+ end
99
+
100
+ def full?
101
+ @seats.select{|x| !x.taken?}.empty?
102
+ end
103
+
104
+ def empty?
105
+ @seats.select{|x| x.taken?}.empty?
106
+ end
107
+
20
108
  def add player, seat_number=nil
21
- if !location.nil?
22
- raise ArgumentException, "Seat #{seat_number} is already taken by another player." if @seats[seat_number - 1] != nil
23
- @seats[seat_number - 1] = player
24
- else
25
- @seats.each_index do |x|
26
- if @seats[x].nil?
27
- @seats[x] = player
28
- return
29
- end
109
+ raise RuntimeError, "Cannot add player, the table is full" if full?
110
+ if !seat_number.nil?
111
+ raise ArgumentError, "Seat number #{seat_number} does not exist at this table" if seat_number > @seats.size || seat_number < 1
112
+ raise ArgumentError, "Seat number #{seat_number} is already taken by another player" if @seats[seat_number - 1].taken?
113
+ @seats[seat_number - 1].player = player
114
+ return self
115
+ end
116
+ @seats.each_index do |x|
117
+ if !@seats[x].taken?
118
+ @seats[x].player = player
119
+ return self
30
120
  end
31
121
  end
32
122
  self
33
123
  end
34
124
 
35
125
  def remove player
36
- @seats.delete player
37
- self
126
+ @seats.each_index do |x|
127
+ if @seats[x].player == player
128
+ @seats[x].player = nil
129
+ end
130
+ end
38
131
  end
39
132
 
40
133
  end
@@ -0,0 +1,19 @@
1
+ class GameLogger
2
+
3
+ def initialize
4
+ @log = Logger.new(STDOUT)
5
+ @log.sev_threshold = Logger::INFO
6
+ @log.formatter = proc do |severity, datetime, progname, msg|
7
+ "#{datetime}: #{msg}\n"
8
+ end
9
+ end
10
+
11
+ def debug message
12
+ @log.debug(message)
13
+ end
14
+
15
+ def info message
16
+ @log.info(message)
17
+ end
18
+
19
+ end
data/lib/rora.rb CHANGED
@@ -1,12 +1,17 @@
1
+ require 'rora/utils/game_logger'
1
2
  require 'rora/model/board'
2
3
  require 'rora/model/card'
3
4
  require 'rora/model/deck'
5
+ require 'rora/model/game'
4
6
  require 'rora/model/hand'
5
7
  require 'rora/model/hand_type'
8
+ require 'rora/model/player'
6
9
  require 'rora/model/pot'
7
10
  require 'rora/model/rank'
11
+ require 'rora/model/seat'
8
12
  require 'rora/model/starting_hand'
9
13
  require 'rora/model/suit'
10
-
14
+ require 'rora/model/table'
11
15
  require 'rora/repository/hand_repository'
12
- require 'rora/repository/starting_hand_repository'
16
+ require 'rora/repository/starting_hand_repository'
17
+ require 'logger'
@@ -2,6 +2,10 @@ require File.expand_path("../../rora_test", File.dirname(__FILE__))
2
2
 
3
3
  class BoardTest < ActiveSupport::TestCase
4
4
 
5
+ def setup
6
+ @board = Board.new "AS,KS,QS,JS,TS"
7
+ end
8
+
5
9
  test "should raise an error when a board is created with less than 3 cards" do
6
10
  assert_raise ArgumentError do
7
11
  Board.new "AS,KS"
@@ -26,6 +30,8 @@ class BoardTest < ActiveSupport::TestCase
26
30
 
27
31
  test "the board should have three cards if the board was initialized with the flop" do
28
32
  assert_equal 3, Board.new("AS,KS,QS").cards.size
33
+ b = Board.new("AS,KS,QS")
34
+ puts b.flop
29
35
  end
30
36
 
31
37
  test "the board should have four cards if the board was initialized with the flop and turn" do
@@ -111,27 +117,23 @@ class BoardTest < ActiveSupport::TestCase
111
117
  end
112
118
 
113
119
  test "should return false if the board does not contain the given card" do
114
- board = Board.new "AS,KS,QS,JS,TS"
115
- assert_equal false, board.contains?("3D")
116
- assert_equal false, board.contains?(Card.new("3D"))
120
+ assert_equal false, @board.contains?("3D")
121
+ assert_equal false, @board.contains?(Card.new("3D"))
117
122
  end
118
123
 
119
124
  test "should return true if the boad does contain the given card" do
120
- board = Board.new "AS,KS,QS,JS,TS"
121
- assert_equal true, board.contains?("TS")
122
- assert_equal true, board.contains?(Card.new("AS"))
125
+ assert_equal true, @board.contains?("TS")
126
+ assert_equal true, @board.contains?(Card.new("AS"))
123
127
  end
124
128
 
125
129
  test "should return false if the board does not contain any of the given cards" do
126
- board = Board.new "AS,KS,QS,JS,TS"
127
- assert_equal false, board.contains_any?(Card.to_cards("AH,KH,QH"))
128
- assert_equal false, board.contains_any?("AH,KH,QH")
130
+ assert_equal false, @board.contains_any?(Card.to_cards("AH,KH,QH"))
131
+ assert_equal false, @board.contains_any?("AH,KH,QH")
129
132
  end
130
133
 
131
134
  test "should return true if the board contains at least one of the given cards" do
132
- board = Board.new "AS,KS,QS,JS,TS"
133
- assert_equal true, board.contains_any?(Card.to_cards("AH,KH,QH,JH,KS"))
134
- assert_equal true, board.contains_any?("AH,KH,QH,JH,KS")
135
+ assert_equal true, @board.contains_any?(Card.to_cards("AH,KH,QH,JH,KS"))
136
+ assert_equal true, @board.contains_any?("AH,KH,QH,JH,KS")
135
137
  end
136
138
 
137
139
  end
@@ -2,6 +2,10 @@ require File.expand_path("../../rora_test", File.dirname(__FILE__))
2
2
 
3
3
  class CardTest < ActiveSupport::TestCase
4
4
 
5
+ def setup
6
+ @card = Card.new("AS")
7
+ end
8
+
5
9
  test "should be able to create a card with the specified rank and suit" do
6
10
  card = Card.new(Rank::ACE, Suit::SPADE)
7
11
  assert_equal card.rank, Rank::ACE
@@ -18,20 +22,25 @@ class CardTest < ActiveSupport::TestCase
18
22
  assert_raise ArgumentError do
19
23
  card = Card.new("A")
20
24
  end
25
+ assert_raise ArgumentError do
26
+ card = Card.new("ASK")
27
+ end
28
+ end
29
+
30
+ test "a card should have an id" do
31
+ assert_equal 1927, @card.id
21
32
  end
22
33
 
23
34
  test "a card id should be equal to the product of the card suit id and rank id" do
24
- card = Card.new(Rank::ACE, Suit::SPADE)
25
- assert_equal card.id, (Rank::ACE.id * Suit::SPADE.id)
35
+ assert_equal @card.id, (Rank::ACE.id * Suit::SPADE.id)
26
36
  end
27
37
 
28
- test "a card value should be equal to the concatenation of the card suit value and rank value" do
29
- card = Card.new(Rank::ACE, Suit::SPADE)
30
- assert_equal card.value, (Rank::ACE.value + Suit::SPADE.value)
38
+ test "a card should have a key" do
39
+ assert_equal "AS", @card.key
31
40
  end
32
41
 
33
42
  test "a card key should be equal to the concatenation of the card suit key and rank key" do
34
- assert_equal "AS", Card.new("AS").key
43
+ assert_equal "AS", (Rank::ACE.key + Suit::SPADE.key)
35
44
  end
36
45
 
37
46
  test "a card should have a name" do
@@ -39,7 +48,7 @@ class CardTest < ActiveSupport::TestCase
39
48
  end
40
49
 
41
50
  test "should generate a readable string representation" do
42
- assert_equal "Card: name='Ace of Spades' value='AS' id=1927", Card.new("AS").to_s
51
+ assert_equal "Card: Ace of Spades", Card.new("AS").to_s
43
52
  end
44
53
 
45
54
  test "should convert an arbitrarily long string of characters into an array of cards" do
@@ -0,0 +1,23 @@
1
+ require File.expand_path("../../rora_test", File.dirname(__FILE__))
2
+
3
+ class GameTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ @game = Game.new
7
+ end
8
+
9
+ test "play the game" do
10
+ for i in 0..5 do
11
+ player = Player.new("Player #{i}", 100000)
12
+ @game.add player
13
+ player.start_session
14
+ end
15
+
16
+ @game.shuffle_deck
17
+ @game.assign_button
18
+ @game.post_small_blind
19
+ @game.post_big_blind
20
+ @game.deal_pocket_cards
21
+ @game.run_preflop_betting_round
22
+ end
23
+ end
@@ -16,19 +16,19 @@ class HandTypeTest < ActiveSupport::TestCase
16
16
 
17
17
  test "should raise an error when performing a lookup with an invalid key" do
18
18
  assert_raise ArgumentError do
19
- HandType.get("L")
19
+ HandType.get "L"
20
20
  end
21
21
  end
22
22
 
23
23
  test "should raise an error when performing a lookup with an empty key" do
24
24
  assert_raise ArgumentError do
25
- HandType.get("")
25
+ HandType.get ""
26
26
  end
27
27
  end
28
28
 
29
29
  test "should raise an error when performing a lookup with a nil key" do
30
30
  assert_raise TypeError do
31
- HandType.get(nil)
31
+ HandType.get nil
32
32
  end
33
33
  end
34
34
 
@@ -0,0 +1,108 @@
1
+ require File.expand_path("../../rora_test", File.dirname(__FILE__))
2
+
3
+ class PlayerTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ @game = Game.new
7
+ @player = Player.new "Frank", 100000
8
+ RSpec::Mocks::setup(self)
9
+ end
10
+
11
+ test "a player should have a name" do
12
+ assert_equal "foo", Player.new("foo", 999).name
13
+ end
14
+
15
+ test "a player should have a stack" do
16
+ assert_equal 1000, Player.new("feff", 1000).stack
17
+ end
18
+
19
+ test "should raise an error if the player name is nil" do
20
+ assert_raise_message "The player name cannot be nil", ArgumentError do
21
+ Player.new nil, 2000
22
+ end
23
+ end
24
+
25
+ test "a player should be able to join a poker game" do
26
+ @player.join_game @game
27
+ assert_equal @player, @game.table.seat(1).player
28
+ end
29
+
30
+ test "a player should be able to join a poker game at a seat of their choosing" do
31
+ @player.join_game @game, 3
32
+ assert_equal @player, @game.table.seat(3).player
33
+ end
34
+
35
+ test "a player should not be able to join a poker game when the poker table is full" do
36
+ @game.table.stub(:full?).and_return(true)
37
+ assert_raise_message "Frank cannot join this game, the table is full", ArgumentError do
38
+ @player.join_game @game
39
+ end
40
+ end
41
+
42
+ test "a player should not be able to join more than one game" do
43
+ @player.join_game @game
44
+ assert_raise_message "Frank cannot join this game, this player is already playing another game", ArgumentError do
45
+ @player.join_game @game
46
+ end
47
+ end
48
+
49
+ test "a player should not be able to start a session at a table if they do not have a seat at the table" do
50
+ assert_raise_message "Frank is not sitting at a table", ArgumentError do
51
+ @player.start_session
52
+ end
53
+ end
54
+
55
+ test "a player should be able to start a session at the poker table" do
56
+ @player.join_game @game
57
+ @player.start_session
58
+ assert_equal false, @player.sitting_out?
59
+ end
60
+
61
+ test "a player should be able to leave a game" do
62
+ @player.join_game @game
63
+ @player.start_session
64
+ @player.leave_game
65
+ assert_equal nil, @player.game
66
+ end
67
+
68
+ test "a player should not be able to post a small blind if the player has not joined a game" do
69
+ assert_raise_message "Frank has not joined a game, cannot post the small blind", ArgumentError do
70
+ @player.post_small_blind
71
+ end
72
+ end
73
+
74
+ test "a player should not be able to post a big blind if the player has not joined a game" do
75
+ assert_raise_message "Frank has not joined a game, cannot post the big blind", ArgumentError do
76
+ @player.post_big_blind
77
+ end
78
+ end
79
+
80
+ test "a player should not be able to post a small blind if the player is sitting out" do
81
+ @player.join_game @game
82
+ assert_raise_message "Frank is sitting out, cannot post the small blind", ArgumentError do
83
+ @player.post_small_blind
84
+ end
85
+ end
86
+
87
+ test "a player should not be able to post a big blind if the player is sitting out" do
88
+ @player.join_game @game
89
+ assert_raise_message "Frank is sitting out, cannot post the big blind", ArgumentError do
90
+ @player.post_big_blind
91
+ end
92
+ end
93
+
94
+ test "a player should be able to post a small blind" do
95
+ @player.join_game @game
96
+ @player.start_session
97
+ @player.post_small_blind
98
+ assert_equal 0.25, @game.pot.value
99
+ end
100
+
101
+ test "a player should be able to post a big blind" do
102
+ @player.join_game @game
103
+ @player.start_session
104
+ @player.post_big_blind
105
+ assert_equal 0.50, @game.pot.value
106
+ end
107
+
108
+ end
@@ -2,27 +2,34 @@ require File.expand_path("../../rora_test", File.dirname(__FILE__))
2
2
 
3
3
  class PotTest < ActiveSupport::TestCase
4
4
 
5
+ def setup
6
+ @pot = Pot.new
7
+ end
8
+
5
9
  test "a new post should have a total of 0 dollars" do
6
- assert_equal 0, Pot.new.total
10
+ assert_equal 0, @pot.value
11
+ end
12
+
13
+ test "should raise an error when attempting to add a negative value to the pot" do
14
+ assert_raise ArgumentError do
15
+ @pot.add -0.50
16
+ end
7
17
  end
8
18
 
9
19
  test "should be able to add money to the pot" do
10
- pot = Pot.new.add 5
11
- assert_equal 5, pot.total
20
+ assert_equal 5, @pot.add(5).value
12
21
  end
13
22
 
14
23
  test "should be able to add money with decimals to the pot" do
15
- pot = Pot.new.add 5.75
16
- assert_equal 5.75, pot.total
24
+ assert_equal 5.75, @pot.add(5.75).value
17
25
  end
18
26
 
19
27
  test "should be able to perform compound addtion operations" do
20
- pot = Pot.new.add(2).add(2.25).add(2)
21
- assert_equal 6.25, pot.total
28
+ assert_equal 6.25, @pot.add(2).add(2.25).add(2).value
22
29
  end
23
30
 
24
31
  test "should return a string representation of the pot" do
25
- assert_equal "Pot: $300.00", Pot.new().add(300.00).to_s
32
+ assert_equal "Pot: $300.00", @pot.add(300.00).to_s
26
33
  end
27
34
 
28
35
  end
@@ -21,25 +21,25 @@ class RankTest < ActiveSupport::TestCase
21
21
  end
22
22
 
23
23
  test "should raise an error when performing a lookup with an invalid key" do
24
- assert_raise ArgumentError do
25
- Rank.get("L")
24
+ assert_raise_message "No rank exists for key 'L'", ArgumentError do
25
+ Rank.get "L"
26
26
  end
27
27
  end
28
28
 
29
29
  test "should raise an error when performing a lookup with an empty key" do
30
- assert_raise ArgumentError do
31
- Rank.get("")
30
+ assert_raise_message "No rank exists for key ''", ArgumentError do
31
+ Rank.get ""
32
32
  end
33
33
  end
34
34
 
35
35
  test "should raise an error when performing a lookup with a nil key" do
36
36
  assert_raise TypeError do
37
- Rank.get(nil)
37
+ Rank.get nil
38
38
  end
39
39
  end
40
40
 
41
41
  test "should generate a readable string representation" do
42
- assert_equal "Rank: id=41, key='A', value='Ace'", Rank::ACE.to_s
42
+ assert_equal "Rank: Ace", Rank::ACE.to_s
43
43
  end
44
44
 
45
45
  end
@@ -0,0 +1,41 @@
1
+ require File.expand_path("../../rora_test", File.dirname(__FILE__))
2
+
3
+ class SeatTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ @seat = Seat.new 2
7
+ end
8
+
9
+ test "should raise an error when a seat is created with a seat number less than 1" do
10
+ assert_raise ArgumentError do
11
+ Seat.new 0
12
+ end
13
+ end
14
+
15
+ test "the seat should have a seat number" do
16
+ assert_equal 2, @seat.number
17
+ end
18
+
19
+ test "the seat should not be taken when a player is not sitting in it" do
20
+ assert_equal false, @seat.taken?
21
+ end
22
+
23
+ test "the seat should be taken when a player is sitting in it" do
24
+ @seat.player = "player"
25
+ assert_equal true, @seat.taken?
26
+ end
27
+
28
+ test "the seat should not have the dealer button" do
29
+ assert_equal false, @seat.button?
30
+ end
31
+
32
+ test "the seat should have the dealer button" do
33
+ @seat.button = true
34
+ assert_equal true, @seat.button?
35
+ end
36
+
37
+ test "should return a string representation of the seat" do
38
+ assert_equal "Seat: 2", @seat.to_s
39
+ end
40
+
41
+ end
@@ -39,7 +39,7 @@ class SuitTest < ActiveSupport::TestCase
39
39
  end
40
40
 
41
41
  test "should generate a readable string representation" do
42
- assert_equal "Suit: id=47, key='S', value='Spade'", Suit::SPADE.to_s
42
+ assert_equal "Suit: Spades", Suit::SPADE.to_s
43
43
  end
44
44
 
45
45
  end