liarsdice_cbarcroft 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/bin/liarsdice +20 -0
- data/lib/features/liars_dice.feature +65 -0
- data/lib/features/step_definitions/liars_dice-steps.rb +131 -0
- data/lib/liars_dice.rb +254 -0
- metadata +49 -0
data/bin/liarsdice
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'liars_dice.rb'
|
3
|
+
|
4
|
+
@game = LiarsDice.new
|
5
|
+
puts @game.welcome_player
|
6
|
+
|
7
|
+
until @game.over?
|
8
|
+
case @game.current_player
|
9
|
+
when "Computer"
|
10
|
+
@game.computer_move
|
11
|
+
when @game.player
|
12
|
+
@game.indicate_player_turn
|
13
|
+
@game.player_move
|
14
|
+
end
|
15
|
+
@game.current_state
|
16
|
+
@game.determine_winner
|
17
|
+
end
|
18
|
+
|
19
|
+
puts "You win!" if @game.player_won?
|
20
|
+
puts "Computer wins!" if @game.computer_won?
|
@@ -0,0 +1,65 @@
|
|
1
|
+
Feature: Liar's Dice Game
|
2
|
+
As a Ruby student I need a final project
|
3
|
+
In order to pass the class
|
4
|
+
I would like to play the computer at Liars Dice
|
5
|
+
|
6
|
+
Scenario: Start Game
|
7
|
+
Given I start a new game
|
8
|
+
When I enter my name as Chris
|
9
|
+
Then the computer welcomes me to the game with "Welcome, Chris!"
|
10
|
+
And randomly chooses who goes first
|
11
|
+
And rolls five random dice for each player
|
12
|
+
|
13
|
+
Scenario: My Turn
|
14
|
+
Given I have a started a game
|
15
|
+
And it is my turn
|
16
|
+
And the computer knows my name is Chris
|
17
|
+
Then the computer prints "Chris's turn:"
|
18
|
+
And waits for my input of "FACE 2"
|
19
|
+
|
20
|
+
Scenario: Computer's Turn
|
21
|
+
Given I have a started a game
|
22
|
+
And it is the computer's turn
|
23
|
+
Then the computer randomly chooses an open position for its move
|
24
|
+
And the board should have an X on it
|
25
|
+
|
26
|
+
Scenario: Making Moves
|
27
|
+
Given I have a started a game
|
28
|
+
And it is my turn
|
29
|
+
When I enter a bet of "FACE 2"
|
30
|
+
And "FACE 2" is a legal bet
|
31
|
+
Then the face bet should now be 2
|
32
|
+
And it is now the computer's turn
|
33
|
+
|
34
|
+
Scenario: Making Bad Moves
|
35
|
+
Given I have a started Tic-Tac-Toe game
|
36
|
+
And it is my turn
|
37
|
+
And I am playing X
|
38
|
+
When I enter a position "A1" on the board
|
39
|
+
And "A1" is taken
|
40
|
+
Then computer should ask me for another position "B2"
|
41
|
+
And it is now the computer's turn
|
42
|
+
|
43
|
+
Scenario: Calling a bet successfully
|
44
|
+
Given I have a started a game
|
45
|
+
And it is my turn
|
46
|
+
And the current bet is face 2, count 4
|
47
|
+
And there are three twos
|
48
|
+
When I enter a bet of "OVER"
|
49
|
+
And "OVER" is a legal bet
|
50
|
+
Then the over bet is successful
|
51
|
+
And it is now the computer's turn
|
52
|
+
|
53
|
+
Scenario: Winning the Game
|
54
|
+
Given I have a started Tic-Tac-Toe game
|
55
|
+
And I am playing X
|
56
|
+
When there are three X's in a row
|
57
|
+
Then I am declared the winner
|
58
|
+
And the game ends
|
59
|
+
|
60
|
+
Scenario: Game is a draw
|
61
|
+
Given I have a started Tic-Tac-Toe game
|
62
|
+
And there are not three symbols in a row
|
63
|
+
When there are no open spaces left on the board
|
64
|
+
Then the game is declared a draw
|
65
|
+
And the game ends
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'rspec/mocks/standalone'
|
2
|
+
require '../../liars_dice.rb'
|
3
|
+
|
4
|
+
Given /^I start a new game$/ do
|
5
|
+
@game = LiarsDice.new
|
6
|
+
end
|
7
|
+
|
8
|
+
When /^I enter my name as (\w+)$/ do |name|
|
9
|
+
@game.player = name
|
10
|
+
end
|
11
|
+
|
12
|
+
Then /^the computer welcomes me to the game with "(.*?)"$/ do |arg1|
|
13
|
+
@game.welcome_player.should eq arg1
|
14
|
+
end
|
15
|
+
|
16
|
+
Then /^randomly chooses who goes first$/ do
|
17
|
+
[@game.player, "Computer"].should include @game.current_player
|
18
|
+
end
|
19
|
+
|
20
|
+
Then /^rolls five random dice for each player$/ do
|
21
|
+
(@game.dice[:player] + @game.dice[:computer]).length.should eq 10
|
22
|
+
end
|
23
|
+
|
24
|
+
Given /^I have a started a game$/ do
|
25
|
+
@game = LiarsDice.new(:player)
|
26
|
+
@game.player = "Chris"
|
27
|
+
end
|
28
|
+
|
29
|
+
Given /^it is my turn$/ do
|
30
|
+
@game.current_player.should eq "Chris"
|
31
|
+
end
|
32
|
+
|
33
|
+
Given /^the computer knows my name is Chris/ do
|
34
|
+
@game.player.should eq "Chris"
|
35
|
+
end
|
36
|
+
|
37
|
+
Then /^the computer prints "(.*?)"$/ do |arg1|
|
38
|
+
@game.should_receive(:puts).with(arg1)
|
39
|
+
@game.indicate_player_turn
|
40
|
+
end
|
41
|
+
|
42
|
+
Then /^waits for my input of "(.*?)"$/ do |arg1|
|
43
|
+
@game.should_receive(:gets).and_return(arg1)
|
44
|
+
@game.get_player_move
|
45
|
+
end
|
46
|
+
|
47
|
+
Given /^it is the computer's turn$/ do
|
48
|
+
@game = LiarsDice.new(:computer)
|
49
|
+
@game.current_player.should eq "Computer"
|
50
|
+
end
|
51
|
+
|
52
|
+
Then /^the computer randomly chooses an open position for its move$/ do
|
53
|
+
open_spots = @game.open_spots
|
54
|
+
@com_move = @game.computer_move
|
55
|
+
open_spots.should include(@com_move)
|
56
|
+
end
|
57
|
+
|
58
|
+
Given /^the computer is playing X$/ do
|
59
|
+
@game.computer_symbol.should eq :X
|
60
|
+
end
|
61
|
+
|
62
|
+
Then /^the board should have an X on it$/ do
|
63
|
+
@game.current_state.should include 'X'
|
64
|
+
end
|
65
|
+
|
66
|
+
Then /^the (.*?) bet should now be (.*?)$/ do |arg1, arg2|
|
67
|
+
@game.current_bet[arg1.to_sym].should eq arg2
|
68
|
+
end
|
69
|
+
|
70
|
+
When /^I enter a bet of "(.*?)"/ do |arg1|
|
71
|
+
@game.should_receive(:get_player_move).and_return(arg1)
|
72
|
+
end
|
73
|
+
|
74
|
+
When /^"(.*?)" is a legal bet/ do |arg1|
|
75
|
+
@game.validate_player_move(arg1.split(" ")).should eq true
|
76
|
+
end
|
77
|
+
|
78
|
+
When /^the current bet is face (.*?), count (.*?)/ do |arg1, arg2|
|
79
|
+
@game.current_bet[:face] = arg1
|
80
|
+
@game.current_bet[:count] = arg2
|
81
|
+
end
|
82
|
+
|
83
|
+
When /^there are three twos/ do
|
84
|
+
@game.dice[:player] = [1,2,3,4,5]
|
85
|
+
@game.dice[:computer] = [1,2,2,3,4]
|
86
|
+
end
|
87
|
+
|
88
|
+
Then /^it is now the computer's turn$/ do
|
89
|
+
@game.current_player.should eq "Computer"
|
90
|
+
end
|
91
|
+
|
92
|
+
When /^the over bet is successful$/ do
|
93
|
+
@game.dice_remaining[:computer].should eq 4
|
94
|
+
end
|
95
|
+
|
96
|
+
Then /^I am declared the winner$/ do
|
97
|
+
@game.determine_winner
|
98
|
+
@game.player_won?.should be_true
|
99
|
+
end
|
100
|
+
|
101
|
+
Then /^the game ends$/ do
|
102
|
+
@game.over?.should be_true
|
103
|
+
end
|
104
|
+
|
105
|
+
Given /^there are not three symbols in a row$/ do
|
106
|
+
@game.board = {
|
107
|
+
:A1 => :X, :A2 => :O, :A3 => :X,
|
108
|
+
:B1 => :X, :B2 => :O, :B3 => :X,
|
109
|
+
:C1 => :O, :C2 => :X, :C3 => :O
|
110
|
+
}
|
111
|
+
@game.determine_winner
|
112
|
+
end
|
113
|
+
|
114
|
+
When /^there are no open spaces left on the board$/ do
|
115
|
+
@game.spots_open?.should be_false
|
116
|
+
end
|
117
|
+
|
118
|
+
Then /^the game is declared a draw$/ do
|
119
|
+
@game.draw?.should be_true
|
120
|
+
end
|
121
|
+
|
122
|
+
When /^"(.*?)" is taken$/ do |arg1|
|
123
|
+
@game.board[arg1.to_sym] = :O
|
124
|
+
@taken_spot = arg1.to_sym
|
125
|
+
end
|
126
|
+
|
127
|
+
Then /^computer should ask me for another position "(.*?)"$/ do |arg1|
|
128
|
+
@game.board[arg1.to_sym] = ' '
|
129
|
+
@game.should_receive(:get_player_move).twice.and_return(@taken_spot, arg1)
|
130
|
+
@game.player_move.should eq arg1.to_sym
|
131
|
+
end
|
data/lib/liars_dice.rb
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
class LiarsDice
|
2
|
+
attr_reader :player_move, :computer_won, :player_won, :over, :current_bet, :waiting_player
|
3
|
+
attr_accessor :current_state, :dice, :dice_remaining
|
4
|
+
|
5
|
+
COMMANDS = ["FACE", "COUNT", "OVER", "SPOTON"]
|
6
|
+
|
7
|
+
def initialize( first_turn = false)
|
8
|
+
system("clear")
|
9
|
+
@players = {:player => "Player", :computer => "Computer"}
|
10
|
+
@current_player = first_turn
|
11
|
+
if first_turn == false
|
12
|
+
@current_player = [:computer, :player].sample
|
13
|
+
end
|
14
|
+
@waiting_player = [:computer, :player].select{|player| player != @current_player}[0]
|
15
|
+
@current_bet = {:face => 1, :count => 1}
|
16
|
+
@dice = {:player => [], :computer => []}
|
17
|
+
@dice_remaining = {:player => 5, :computer => 5}
|
18
|
+
@computer_won = false
|
19
|
+
@player_won = false
|
20
|
+
@over = false
|
21
|
+
self.roll_dice
|
22
|
+
self.current_state
|
23
|
+
end
|
24
|
+
|
25
|
+
def current_player
|
26
|
+
@players[@current_player]
|
27
|
+
end
|
28
|
+
|
29
|
+
def player=(str)
|
30
|
+
@players[:player] = str
|
31
|
+
end
|
32
|
+
|
33
|
+
def player
|
34
|
+
@players[:player]
|
35
|
+
end
|
36
|
+
|
37
|
+
def welcome_player
|
38
|
+
"Welcome, #{@players[:player]}!"
|
39
|
+
end
|
40
|
+
|
41
|
+
def indicate_player_turn
|
42
|
+
puts "#{@players[@current_player]}'s turn:"
|
43
|
+
end
|
44
|
+
|
45
|
+
def switch_turns
|
46
|
+
temp = @current_player
|
47
|
+
@current_player = @waiting_player
|
48
|
+
@waiting_player = temp
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_player_move
|
52
|
+
gets.chomp
|
53
|
+
end
|
54
|
+
|
55
|
+
def player_move
|
56
|
+
move = self.get_player_move.split(" ")
|
57
|
+
until (self.validate_player_move(move))
|
58
|
+
move = self.get_player_move.split(" ")
|
59
|
+
end
|
60
|
+
|
61
|
+
case move[0].upcase
|
62
|
+
when "FACE"
|
63
|
+
puts "You have raised the face value to #{move[1]}"
|
64
|
+
@current_bet[:face] = move[1]
|
65
|
+
when "COUNT"
|
66
|
+
puts "You have raised the count to #{move[1]}"
|
67
|
+
@current_bet[:count] = move[1]
|
68
|
+
when "SPOTON"
|
69
|
+
puts "You think the bet is spot on."
|
70
|
+
self.check_spoton
|
71
|
+
when "OVER"
|
72
|
+
puts "You think the computer's bet is too high."
|
73
|
+
self.check_over
|
74
|
+
end
|
75
|
+
self.switch_turns
|
76
|
+
end
|
77
|
+
|
78
|
+
def computer_move
|
79
|
+
puts "Computer's Turn:"
|
80
|
+
sleep(1)
|
81
|
+
move = self.smart_select.split(" ")
|
82
|
+
|
83
|
+
case move[0]
|
84
|
+
when "FACE"
|
85
|
+
puts "Computer has raised the face value to #{move[1]}"
|
86
|
+
@current_bet[:face] = move[1]
|
87
|
+
when "COUNT"
|
88
|
+
puts "Computer has raised the count to #{move[1]}"
|
89
|
+
@current_bet[:count] = move[1]
|
90
|
+
when "SPOTON"
|
91
|
+
puts "Computer thinks the bet is spot on."
|
92
|
+
self.check_spoton
|
93
|
+
when "OVER"
|
94
|
+
puts "Computer challenges your bet."
|
95
|
+
self.check_over
|
96
|
+
end
|
97
|
+
self.switch_turns
|
98
|
+
end
|
99
|
+
|
100
|
+
def smart_select
|
101
|
+
comp_dice = self.get_dice_total
|
102
|
+
if comp_dice[@current_bet[:face].to_i] == @current_bet[:count] then #if computer has the current bet showing in its own dice
|
103
|
+
if @dice_remaining[:player] <= 2 then #and the player has two or less dice of their own
|
104
|
+
return "SPOTON"
|
105
|
+
else
|
106
|
+
return "COUNT #{@current_bet[:count].to_i + 1}" #increment count by one
|
107
|
+
end
|
108
|
+
elsif (comp_dice[@current_bet[:face].to_i]).to_i < @current_bet[:count].to_i then #if computer has less dice of the current face than the bet
|
109
|
+
if (@current_bet[:count].to_i - comp_dice[@current_bet[:face].to_i].to_i) >= 2 then
|
110
|
+
return "OVER"
|
111
|
+
else
|
112
|
+
return "COUNT #{@current_bet[:count].to_i + 1}"
|
113
|
+
end
|
114
|
+
elsif comp_dice[@current_bet[:face].to_i].to_i > @current_bet[:count].to_i then #if computer has more dice of the current face than the bet
|
115
|
+
if (comp_dice[@current_bet[:face].to_i].to_i - @current_bet[:count].to_i) >= 2 then
|
116
|
+
return "COUNT #{@current_bet[:count].to_i + 2}"
|
117
|
+
else
|
118
|
+
return "COUNT #{@current_bet[:count].to_i + 1}"
|
119
|
+
end
|
120
|
+
else
|
121
|
+
return "OVER" #default bet, but this should never happen
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def validate_player_move(move)
|
126
|
+
valid = true
|
127
|
+
if !COMMANDS.include? move[0].upcase
|
128
|
+
puts "Unrecognized command #{move[0].upcase}"
|
129
|
+
valid = false
|
130
|
+
end
|
131
|
+
if move[0].upcase == "FACE" then
|
132
|
+
if move[1] == nil || move[1].to_i < 1 || move[1].to_i > 6 then
|
133
|
+
puts "Invalid value(#{move[1]}) for FACE"
|
134
|
+
valid = false
|
135
|
+
elsif !(move[1].to_i > @current_bet[:face].to_i)
|
136
|
+
puts "Face bet must be higher than the current bet: #{@current_bet[:face]}"
|
137
|
+
valid = false
|
138
|
+
end
|
139
|
+
end
|
140
|
+
if move[0].upcase == "COUNT" then
|
141
|
+
if move[1].to_i == nil || move[1].to_i < 1 || move[1].to_i > 10 then
|
142
|
+
puts "Invalid value(#{move[1]}) for FACE"
|
143
|
+
valid = false
|
144
|
+
elsif !(move[1].to_i > @current_bet[:count].to_i)
|
145
|
+
puts "Count bet must be higher than the current bet: #{@current_bet[:count]}"
|
146
|
+
valid = false
|
147
|
+
end
|
148
|
+
end
|
149
|
+
valid
|
150
|
+
end
|
151
|
+
|
152
|
+
def roll_dice
|
153
|
+
@players.each do |player, name|
|
154
|
+
@dice[player] = []
|
155
|
+
@dice[player] = @dice_remaining[player].times.map{ rand(1..6) }
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def check_spoton
|
160
|
+
puts self.print_dice(true)
|
161
|
+
totals = get_dice_totals
|
162
|
+
if totals[@current_bet[:face].to_i] == @current_bet[:count]
|
163
|
+
puts "#{@players[@current_player]} is correct! #{@players[@waiting_player]} loses one die!"
|
164
|
+
@dice_remaining[@waiting_player] -= 1
|
165
|
+
else
|
166
|
+
puts "#{@players[@current_player]} is wrong, and loses one die! "
|
167
|
+
@dice_remaining[@current_player] -= 1
|
168
|
+
end
|
169
|
+
|
170
|
+
self.reset
|
171
|
+
end
|
172
|
+
|
173
|
+
def check_over
|
174
|
+
puts self.print_dice(true)
|
175
|
+
totals = get_dice_totals
|
176
|
+
if totals[@current_bet[:face].to_i].to_i < @current_bet[:count].to_i
|
177
|
+
puts "#{@players[@current_player]} is correct! #{@players[@waiting_player]} loses one die!"
|
178
|
+
@dice_remaining[@waiting_player] -= 1
|
179
|
+
else
|
180
|
+
puts "#{@players[@current_player]} is wrong, and loses one die! "
|
181
|
+
@dice_remaining[@current_player] -= 1
|
182
|
+
end
|
183
|
+
|
184
|
+
self.reset
|
185
|
+
end
|
186
|
+
|
187
|
+
def reset
|
188
|
+
self.roll_dice
|
189
|
+
@current_bet[:face] = 1
|
190
|
+
@current_bet[:count] = 1
|
191
|
+
end
|
192
|
+
|
193
|
+
def get_dice_totals
|
194
|
+
totals = {1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0}
|
195
|
+
(@dice[:player] + @dice[:computer]).flatten.each do |die|
|
196
|
+
totals[die] += 1
|
197
|
+
end
|
198
|
+
totals
|
199
|
+
end
|
200
|
+
|
201
|
+
def get_dice_total
|
202
|
+
totals = {1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0}
|
203
|
+
@dice[:computer].each do |die|
|
204
|
+
totals[die] += 1
|
205
|
+
end
|
206
|
+
totals
|
207
|
+
end
|
208
|
+
|
209
|
+
def current_state
|
210
|
+
puts "Current Bet: Face => #{@current_bet[:face]} Count => #{@current_bet[:count]}"
|
211
|
+
puts self.print_dice
|
212
|
+
end
|
213
|
+
|
214
|
+
def print_dice(show_computer = false)
|
215
|
+
@dice[:player].each do |die|
|
216
|
+
print "|#{die}| "
|
217
|
+
end
|
218
|
+
print " ************ "
|
219
|
+
if show_computer then
|
220
|
+
@dice[:computer].each do |die|
|
221
|
+
print "|#{die}| "
|
222
|
+
end
|
223
|
+
else
|
224
|
+
@dice[:computer].each do |die|
|
225
|
+
print "|X| "
|
226
|
+
end
|
227
|
+
end
|
228
|
+
print "\n"
|
229
|
+
end
|
230
|
+
|
231
|
+
def dice_remaining?
|
232
|
+
@dice_remaining[:player].to_i > 0 ? true : false
|
233
|
+
end
|
234
|
+
|
235
|
+
def computer_dice_remaining?
|
236
|
+
@dice_remaining[:computer].to_i > 0 ? true : false
|
237
|
+
end
|
238
|
+
|
239
|
+
def over?
|
240
|
+
(self.player_won? || self.computer_won?)? true : false
|
241
|
+
end
|
242
|
+
|
243
|
+
def player_won?
|
244
|
+
self.computer_dice_remaining? ? false : true
|
245
|
+
end
|
246
|
+
|
247
|
+
def computer_won?
|
248
|
+
self.dice_remaining? ? false : true
|
249
|
+
end
|
250
|
+
|
251
|
+
def determine_winner
|
252
|
+
@over = self.over?
|
253
|
+
end
|
254
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: liarsdice_cbarcroft
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chris Barcroft
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-11 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Test your wits against a ... challenged computer
|
15
|
+
email: ChrisABarcroft@gmail.com
|
16
|
+
executables:
|
17
|
+
- liarsdice
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/features/liars_dice.feature
|
22
|
+
- lib/liars_dice.rb
|
23
|
+
- lib/features/step_definitions/liars_dice-steps.rb
|
24
|
+
- bin/liarsdice
|
25
|
+
homepage: http://www.google.com
|
26
|
+
licenses: []
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
none: false
|
33
|
+
requirements:
|
34
|
+
- - ! '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
requirements: []
|
44
|
+
rubyforge_project:
|
45
|
+
rubygems_version: 1.8.24
|
46
|
+
signing_key:
|
47
|
+
specification_version: 3
|
48
|
+
summary: Liar's dice game against an amazing computer opponent
|
49
|
+
test_files: []
|