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