goose_game 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +50 -0
- data/.travis.yml +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +22 -0
- data/LICENSE +19 -0
- data/OBJECTIVES.md +124 -0
- data/README.md +83 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/goose_game +8 -0
- data/bin/setup +8 -0
- data/goose_game.gemspec +22 -0
- data/lib/goose_game.rb +8 -0
- data/lib/goose_game/cell.rb +93 -0
- data/lib/goose_game/dice.rb +24 -0
- data/lib/goose_game/gameboard.rb +21 -0
- data/lib/goose_game/gameplay.rb +69 -0
- data/lib/goose_game/messages.rb +21 -0
- data/lib/goose_game/player.rb +27 -0
- data/lib/goose_game/version.rb +3 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4f64052a54488a4f601033db2224d893561aa9b7ec8b7aea84fa6db727681735
|
4
|
+
data.tar.gz: c69991536320fc33304f6f2eaf26b086ac699c745706aaf2a403a2266704a6ea
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b7049f937781cc2529db050a1c8adbd767c493c6bf4c83e60d6620518e5504a39d4318837021a2c22cae472c951de2a6c3f272500800ddabdeda1d8fb966f68a
|
7
|
+
data.tar.gz: b6082175df2a8a3df33f1c2d04dc7b93bfbc2bdc239af0e0106ec2ee80972652a0f286039926c0815566740aa91c1d21a702f3a62214458806b89d079dbd7c68
|
data/.gitignore
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
# Used by dotenv library to load environment variables.
|
14
|
+
# .env
|
15
|
+
|
16
|
+
## Specific to RubyMotion:
|
17
|
+
.dat*
|
18
|
+
.repl_history
|
19
|
+
build/
|
20
|
+
*.bridgesupport
|
21
|
+
build-iPhoneOS/
|
22
|
+
build-iPhoneSimulator/
|
23
|
+
|
24
|
+
## Specific to RubyMotion (use of CocoaPods):
|
25
|
+
#
|
26
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
27
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
28
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
29
|
+
#
|
30
|
+
# vendor/Pods/
|
31
|
+
|
32
|
+
## Documentation cache and generated files:
|
33
|
+
/.yardoc/
|
34
|
+
/_yardoc/
|
35
|
+
/doc/
|
36
|
+
/rdoc/
|
37
|
+
|
38
|
+
## Environment normalization:
|
39
|
+
/.bundle/
|
40
|
+
/vendor/bundle
|
41
|
+
/lib/bundler/man/
|
42
|
+
|
43
|
+
# for a library or gem, you might want to ignore these files since the code is
|
44
|
+
# intended to run in multiple environments; otherwise, check them in:
|
45
|
+
# Gemfile.lock
|
46
|
+
# .ruby-version
|
47
|
+
# .ruby-gemset
|
48
|
+
|
49
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
50
|
+
.rvmrc
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
goose_game (1.0.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
minitest (5.11.3)
|
10
|
+
rake (12.3.3)
|
11
|
+
|
12
|
+
PLATFORMS
|
13
|
+
ruby
|
14
|
+
|
15
|
+
DEPENDENCIES
|
16
|
+
bundler (~> 2.0)
|
17
|
+
goose_game!
|
18
|
+
minitest (~> 5.11)
|
19
|
+
rake (~> 12.3)
|
20
|
+
|
21
|
+
BUNDLED WITH
|
22
|
+
2.0.2
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2019 The Python Packaging Authority
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/OBJECTIVES.md
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# The Goose Game Kata
|
2
|
+
Goose game is a game where two or more players move pieces around a track by rolling a die. The aim of the game is to reach square number sixty-three before any of the other players and avoid obstacles. ([wikipedia](https://en.wikipedia.org/wiki/Game_of_the_Goose))
|
3
|
+
|
4
|
+
This kata has been invented by [Matteo Vaccari](https://github.com/xpmatteo), you can find the original slides [here](https://www.slideshare.net/pierodibello/il-dilettevole-giuoco-delloca-coding-dojo).
|
5
|
+
|
6
|
+
## General requirements
|
7
|
+
- You may use whatever programming language you prefer. Use something that you know well.
|
8
|
+
- You should commit your code on GitHub or any other SCM repository you prefer (e.g. bitbucket, gitlab, etc) and send us the link.
|
9
|
+
- You should release your work under an OSI-approved open-source license of your choice.
|
10
|
+
- You should deliver the sources of your application, with a README that explains how to compile and run it.
|
11
|
+
|
12
|
+
**IMPORTANT:** Implement the requirements focusing on writing the best code you can produce.
|
13
|
+
|
14
|
+
## Features
|
15
|
+
|
16
|
+
### 1. Add players
|
17
|
+
As a player, I want to add me to the game so that I can play.
|
18
|
+
|
19
|
+
**Scenarios:**
|
20
|
+
1. Add Player
|
21
|
+
```js
|
22
|
+
If there is no participant
|
23
|
+
the user writes: "add player Pippo"
|
24
|
+
the system responds: "players: Pippo"
|
25
|
+
the user writes: "add player Pluto"
|
26
|
+
the system responds: "players: Pippo, Pluto"
|
27
|
+
```
|
28
|
+
|
29
|
+
2. Duplicated Player
|
30
|
+
```js
|
31
|
+
If there is already a participant "Pippo"
|
32
|
+
the user writes: "add player Pippo"
|
33
|
+
the system responds: "Pippo: already existing player"
|
34
|
+
```
|
35
|
+
|
36
|
+
### 2. Move a player
|
37
|
+
As a player, I want to move the marker on the board to make the game progress
|
38
|
+
|
39
|
+
**Scenarios:**
|
40
|
+
1. Start
|
41
|
+
```js
|
42
|
+
If there are two participants "Pippo" and "Pluto" on space "Start"
|
43
|
+
the user writes: "move Pippo 4, 2"
|
44
|
+
the system responds: "Pippo rolls 4, 2. Pippo moves from Start to 6"
|
45
|
+
the user writes: "move Pluto 2, 2"
|
46
|
+
the system responds: "Pluto rolls 2, 2. Pluto moves from Start to 4"
|
47
|
+
the user writes: "move Pippo 2, 3"
|
48
|
+
the system responds: "Pippo rolls 2, 3. Pippo moves from 6 to 11"
|
49
|
+
```
|
50
|
+
|
51
|
+
### 3. Win
|
52
|
+
As a player, I win the game if I land on space "63"
|
53
|
+
|
54
|
+
**Scenarios:**
|
55
|
+
1. Victory
|
56
|
+
```js
|
57
|
+
If there is one participant "Pippo" on space "60"
|
58
|
+
the user writes: "move Pippo 1, 2"
|
59
|
+
the system responds: "Pippo rolls 1, 2. Pippo moves from 60 to 63. Pippo Wins!!"
|
60
|
+
```
|
61
|
+
|
62
|
+
2. Winning with the exact dice shooting
|
63
|
+
```js
|
64
|
+
If there is one participant "Pippo" on space "60"
|
65
|
+
the user writes: "move Pippo 3, 2"
|
66
|
+
the system responds: "Pippo rolls 3, 2. Pippo moves from 60 to 63. Pippo bounces! Pippo returns to 61"
|
67
|
+
```
|
68
|
+
### 4. The game throws the dice
|
69
|
+
As a player, I want the game throws the dice for me to save effort
|
70
|
+
|
71
|
+
**Scenarios:**
|
72
|
+
1. Dice roll
|
73
|
+
```js
|
74
|
+
If there is one participant "Pippo" on space "4"
|
75
|
+
assuming that the dice get 1 and 2
|
76
|
+
when the user writes: "move Pippo"
|
77
|
+
the system responds: "Pippo rolls 1, 2. Pippo moves from 4 to 7"
|
78
|
+
```
|
79
|
+
|
80
|
+
### 5. Space "6" is "The Bridge"
|
81
|
+
As a player, when I get to the space "The Bridge", I jump to the space "12"
|
82
|
+
|
83
|
+
**Scenarios:**
|
84
|
+
1. Get to "The Bridge"
|
85
|
+
```js
|
86
|
+
If there is one participant "Pippo" on space "4"
|
87
|
+
assuming that the dice get 1 and 1
|
88
|
+
when the user writes: "move Pippo"
|
89
|
+
the system responds: "Pippo rolls 1, 1. Pippo moves from 4 to The Bridge. Pippo jumps to 12"
|
90
|
+
```
|
91
|
+
|
92
|
+
### 6. If you land on "The Goose", move again
|
93
|
+
As a player, when I get to a space with a picture of "The Goose", I move forward again by the sum of the two dice rolled before
|
94
|
+
|
95
|
+
The spaces 5, 9, 14, 18, 23, 27 have a picture of "The Goose"
|
96
|
+
|
97
|
+
**Scenarios:**
|
98
|
+
1. Single Jump
|
99
|
+
```js
|
100
|
+
If there is one participant "Pippo" on space "3"
|
101
|
+
assuming that the dice get 1 and 1
|
102
|
+
when the user writes: "move Pippo"
|
103
|
+
the system responds: "Pippo rolls 1, 1. Pippo moves from 3 to 5, The Goose. Pippo moves again and goes to 7"
|
104
|
+
```
|
105
|
+
|
106
|
+
2. Multiple Jump
|
107
|
+
```js
|
108
|
+
If there is one participant "Pippo" on space "10"
|
109
|
+
assuming that the dice get 2 and 2
|
110
|
+
when the user writes: "move Pippo"
|
111
|
+
the system responds: "Pippo rolls 2, 2. Pippo moves from 10 to 14, The Goose. Pippo moves again and goes to 18, The Goose. Pippo moves again and goes to 22"
|
112
|
+
```
|
113
|
+
|
114
|
+
### 7. Prank (Optional Step)
|
115
|
+
As a player, when I land on a space occupied by another player, I send him to my previous position so that the game can be more entertaining.
|
116
|
+
|
117
|
+
**Scenarios:**
|
118
|
+
1. Prank
|
119
|
+
```js
|
120
|
+
If there are two participants "Pippo" and "Pluto" respectively on spaces "15" and "17"
|
121
|
+
assuming that the dice get 1 and 1
|
122
|
+
when the user writes: "move Pippo"
|
123
|
+
the system responds: "Pippo rolls 1, 1. Pippo moves from 15 to 17. On 17 there is Pluto, who returns to 15"
|
124
|
+
```
|
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# Table of Contents
|
2
|
+
* [Scope](#scope)
|
3
|
+
* [Design](#design)
|
4
|
+
* [Cell](#cell)
|
5
|
+
* [Dice](#dice)
|
6
|
+
* [GameBoard](#gameboard)
|
7
|
+
* [Gameplay](#gameplay)
|
8
|
+
* [Player](#player)
|
9
|
+
* [Installation](#installation)
|
10
|
+
* [Runtime](#runtime)
|
11
|
+
* [Dependencies](#dependencies)
|
12
|
+
* [Testing](#testing)
|
13
|
+
* [Gem](#gem)
|
14
|
+
* [Usage](#usage)
|
15
|
+
* [CLI](#cli)
|
16
|
+
* [Help](help)
|
17
|
+
|
18
|
+
# Scope
|
19
|
+
This gem is the Ruby implementation of the `Goose Game` code-kata (for more information refer to the [OBJECTIVES](https://github.com/costajob/goose_game/blob/master/OBJECTIVES.md)).
|
20
|
+
|
21
|
+
# Design
|
22
|
+
The code design follows the single responsibility principle by using a dedicated class/module for any specific task. Each class exposes a minimal public API, when meaningful by using the `call` method, thus behaving like a plain `Proc` object.
|
23
|
+
|
24
|
+
## Cell
|
25
|
+
The cell of the game board. They are responsible to compute the position of the player and properly display the output messages. Polymorphism is used to reduce conditional logic.
|
26
|
+
|
27
|
+
## Dice
|
28
|
+
The class represents the two dice used to move players (creating a single Die class brings little benefit to the design). A factory class rolls dice with random values (within 1 to 6), constructor accepts any convertible integers, the absolute value is taken and limited to 6.
|
29
|
+
|
30
|
+
## Gameboard
|
31
|
+
The board class uses a `Hash` for its data representation: this data structure grants quick access by key.
|
32
|
+
|
33
|
+
## Gameplay
|
34
|
+
The main interface with the game core logic is enclosed within the `Gameplay` class: it recognizes input commands, performs actions by creating players, rolling dice and printing appropriate messages to the terminal. The whole game runs within an endless loop.
|
35
|
+
|
36
|
+
## Player
|
37
|
+
The player of the game, record both current and previous position.
|
38
|
+
|
39
|
+
# Installation
|
40
|
+
|
41
|
+
## Runtime
|
42
|
+
This library supports from `Ruby 2.4.1` on.
|
43
|
+
|
44
|
+
## Dependencies
|
45
|
+
There are no runtime dependencies, but some developments ones (testing).
|
46
|
+
Just clone the repository, move to the directory and use `bundler`:
|
47
|
+
```shell
|
48
|
+
bundle install
|
49
|
+
```
|
50
|
+
|
51
|
+
## Testing
|
52
|
+
The code is covered by fast, isolated unit testing.
|
53
|
+
Move to the installation path and run them by:
|
54
|
+
```shell
|
55
|
+
bundle exec rake
|
56
|
+
```
|
57
|
+
|
58
|
+
## Gem
|
59
|
+
The library is packaged as a `gem`. Build and install it by:
|
60
|
+
```shell
|
61
|
+
gem build goose_game.gemspec
|
62
|
+
...
|
63
|
+
gem install --local ./goose_game.gem
|
64
|
+
```
|
65
|
+
|
66
|
+
# Usage
|
67
|
+
|
68
|
+
## CLI
|
69
|
+
The gem provides a CLI interface, once installed you will be able to start the game from the terminal:
|
70
|
+
```shell
|
71
|
+
goose_game
|
72
|
+
```
|
73
|
+
|
74
|
+
## Help
|
75
|
+
The game starts with no prompts, type `help` to see the available commands:
|
76
|
+
```shell
|
77
|
+
available commands:
|
78
|
+
* add player <player_name>
|
79
|
+
* move <player_name> 4, 5
|
80
|
+
* move <player_name>
|
81
|
+
* help
|
82
|
+
* exit
|
83
|
+
```
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "goose_game"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/goose_game
ADDED
data/bin/setup
ADDED
data/goose_game.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "goose_game/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "goose_game"
|
8
|
+
s.version = GooseGame::VERSION
|
9
|
+
s.authors = ["costajob"]
|
10
|
+
s.email = ["costajob@gmail.com"]
|
11
|
+
s.license = "MIT"
|
12
|
+
s.summary = "Implementation of the Goose Game code kata"
|
13
|
+
s.homepage = "https://github.com/costajob/goose_game.git"
|
14
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
15
|
+
s.bindir = "bin"
|
16
|
+
s.executables << "goose_game"
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.required_ruby_version = ">= 2.4.1"
|
19
|
+
s.add_development_dependency "bundler", "~> 2.0"
|
20
|
+
s.add_development_dependency "rake", "~> 12.3"
|
21
|
+
s.add_development_dependency "minitest", "~> 5.11"
|
22
|
+
end
|
data/lib/goose_game.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module GooseGame
|
2
|
+
module Cell
|
3
|
+
class Base
|
4
|
+
attr_reader :num, :gameboard
|
5
|
+
|
6
|
+
def initialize(num, gameboard)
|
7
|
+
@num = num.to_i
|
8
|
+
@gameboard = gameboard
|
9
|
+
@tokens = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(player, dice)
|
13
|
+
position.tap do |pos|
|
14
|
+
player.move(pos)
|
15
|
+
@tokens.clear
|
16
|
+
@tokens << "#{player} rolls #{dice.d1}, #{dice.d2}"
|
17
|
+
@tokens << "#{player} moves from #{player.prev} to #{dest}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
@tokens.join(". ")
|
23
|
+
end
|
24
|
+
|
25
|
+
private def position
|
26
|
+
num
|
27
|
+
end
|
28
|
+
|
29
|
+
private def dest
|
30
|
+
num
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Bounce < Base
|
35
|
+
def call(player, dice)
|
36
|
+
super.tap do |pos|
|
37
|
+
@tokens << "#{player} bounces! #{player} returns to #{pos}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private def position
|
42
|
+
FINISH - num % FINISH
|
43
|
+
end
|
44
|
+
|
45
|
+
private def dest
|
46
|
+
FINISH
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Winning < Base
|
51
|
+
def call(player, dice)
|
52
|
+
super.tap do |pos|
|
53
|
+
@tokens << "#{player} Wins!!"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Bridge < Base
|
59
|
+
def call(player, dice)
|
60
|
+
super.tap do |pos|
|
61
|
+
@tokens << "#{player} jumps to #{pos}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private def position
|
66
|
+
num * 2
|
67
|
+
end
|
68
|
+
|
69
|
+
private def dest
|
70
|
+
"The Bridge"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Goose < Base
|
75
|
+
def call(player, dice)
|
76
|
+
tokens = []
|
77
|
+
super.tap do |pos|
|
78
|
+
while goose?(pos)
|
79
|
+
pos += dice.to_i
|
80
|
+
tokens << "The Goose. #{player} moves again and goes to #{pos}"
|
81
|
+
end
|
82
|
+
@tokens << tokens.join(", ")
|
83
|
+
player.position = pos
|
84
|
+
return pos
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private def goose?(n)
|
89
|
+
gameboard[n].instance_of? Goose
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module GooseGame
|
2
|
+
class Dice
|
3
|
+
QTY = 2
|
4
|
+
MAX = 6
|
5
|
+
|
6
|
+
attr_reader :d1, :d2
|
7
|
+
|
8
|
+
def self.roll
|
9
|
+
new(*QTY.times.map { |_| rand(MAX) + 1 })
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(d1 = 0, d2 = 0)
|
13
|
+
@d1, @d2 = *check_args(d1, d2)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_i
|
17
|
+
[d1, d2].sum
|
18
|
+
end
|
19
|
+
|
20
|
+
private def check_args(*args)
|
21
|
+
args.map { |arg| [arg.to_i.abs, MAX].min }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "goose_game/cell"
|
2
|
+
|
3
|
+
module GooseGame
|
4
|
+
class GameBoard
|
5
|
+
WINNING_CELLS = [63]
|
6
|
+
BRIDGE_CELLS = [6]
|
7
|
+
GOOSE_CELLS = [5, 9, 14, 18, 23, 27]
|
8
|
+
|
9
|
+
def [](n)
|
10
|
+
cells.fetch(n) { Cell::Bounce.new(n, self) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def cells
|
14
|
+
@cells ||= (0..FINISH).reduce({}) { |acc, n| acc[n] = Cell::Base.new(n, self); acc }.tap do |cells|
|
15
|
+
WINNING_CELLS.each { |n| cells[n] = Cell::Winning.new(n, self) }
|
16
|
+
BRIDGE_CELLS.each { |n| cells[n] = Cell::Bridge.new(n, self) }
|
17
|
+
GOOSE_CELLS.each { |n| cells[n] = Cell::Goose.new(n, self) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "goose_game/dice"
|
2
|
+
require "goose_game/gameboard"
|
3
|
+
require "goose_game/messages"
|
4
|
+
require "goose_game/player"
|
5
|
+
|
6
|
+
module GooseGame
|
7
|
+
class GamePlay
|
8
|
+
include Messages
|
9
|
+
|
10
|
+
attr_reader :players, :round_player, :gameboard, :dice
|
11
|
+
|
12
|
+
def initialize(players: [], gameboard: GameBoard.new, output: STDOUT)
|
13
|
+
@players = players
|
14
|
+
@gameboard = gameboard
|
15
|
+
@output = output
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
loop do
|
20
|
+
res = play(STDIN.gets)
|
21
|
+
break if res == :exit
|
22
|
+
break if players.any?(&:won?)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private def play(stdin)
|
27
|
+
case stdin.chomp
|
28
|
+
when In::HELP
|
29
|
+
@output.puts Out::HELP
|
30
|
+
when In::PLAYER
|
31
|
+
@output.puts add_player($~[:name])
|
32
|
+
when In::MOVE, In::MOVE_ROLL
|
33
|
+
@dice = (%w[d1 d2] - $~.names).empty? ? Dice.new($~[:d1], $~[:d2]) : Dice.roll
|
34
|
+
@round_player = player($~[:name])
|
35
|
+
@output.puts move($~[:name])
|
36
|
+
when In::EXIT
|
37
|
+
return :exit
|
38
|
+
else
|
39
|
+
@output.puts Out::UNKNOWN
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private def add_player(name)
|
44
|
+
existing_player = player(name)
|
45
|
+
return Out::EXISTING.call(existing_player) if existing_player
|
46
|
+
players << Player.new(name)
|
47
|
+
Out::PLAYERS.call(players)
|
48
|
+
end
|
49
|
+
|
50
|
+
private def player(name)
|
51
|
+
players.detect { |p| p.name == name }
|
52
|
+
end
|
53
|
+
|
54
|
+
private def prank_check
|
55
|
+
prank = players.detect { |p| p.name != round_player.name && p.position == round_player.position }
|
56
|
+
return "" unless prank
|
57
|
+
prank.move(round_player.prev)
|
58
|
+
Out::PRANK.call(round_player, prank)
|
59
|
+
end
|
60
|
+
|
61
|
+
private def move(name)
|
62
|
+
return Out::NO_PLAYER.call(name) unless round_player
|
63
|
+
n = round_player.position.to_i + dice.to_i
|
64
|
+
cell = gameboard[n]
|
65
|
+
cell.call(round_player, dice)
|
66
|
+
cell.to_s << prank_check
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module GooseGame
|
2
|
+
module Messages
|
3
|
+
module In
|
4
|
+
PLAYER = /add player (?<name>\w+)/i
|
5
|
+
MOVE = /move (?<name>\w+) (?<d1>\d+), (?<d2>\d+)/i
|
6
|
+
MOVE_ROLL = /move (?<name>\w+)/i
|
7
|
+
HELP = /help/i
|
8
|
+
EXIT = /exit/i
|
9
|
+
end
|
10
|
+
|
11
|
+
module Out
|
12
|
+
HELP = ["available commands:", "* add player <player_name>", "* move <player_name> 4, 5", "* move <player_name>", "* help", "* exit"].join("\n")
|
13
|
+
UNKNOWN = "can you repeat please?"
|
14
|
+
NO_PLAYER = -> (player) { "#{player}: not an existing player"}
|
15
|
+
PLAYERS = -> (players) { "players: #{players.join(', ')}" }
|
16
|
+
EXISTING = -> (player) { "#{player}: already existing player" }
|
17
|
+
ROLL = -> (player, dice) { "#{player} rolls #{dice.d1}, #{dice.d2}" }
|
18
|
+
PRANK = -> (player, prank) { ". On #{player.position} there is #{prank}, who returns to #{player.prev}" }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module GooseGame
|
2
|
+
class Player
|
3
|
+
attr_reader :name
|
4
|
+
attr_accessor :position
|
5
|
+
|
6
|
+
def initialize(name)
|
7
|
+
@name = name
|
8
|
+
@position = START
|
9
|
+
@prev = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method :to_s, :name
|
13
|
+
|
14
|
+
def move(pos)
|
15
|
+
return if pos == @position
|
16
|
+
@prev, @position = @position, pos.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
def won?
|
20
|
+
@position == FINISH
|
21
|
+
end
|
22
|
+
|
23
|
+
def prev
|
24
|
+
@prev.to_i.zero? ? START : @prev
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: goose_game
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- costajob
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-09-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '12.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.11'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.11'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- costajob@gmail.com
|
58
|
+
executables:
|
59
|
+
- goose_game
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".travis.yml"
|
65
|
+
- Gemfile
|
66
|
+
- Gemfile.lock
|
67
|
+
- LICENSE
|
68
|
+
- OBJECTIVES.md
|
69
|
+
- README.md
|
70
|
+
- Rakefile
|
71
|
+
- bin/console
|
72
|
+
- bin/goose_game
|
73
|
+
- bin/setup
|
74
|
+
- goose_game.gemspec
|
75
|
+
- lib/goose_game.rb
|
76
|
+
- lib/goose_game/cell.rb
|
77
|
+
- lib/goose_game/dice.rb
|
78
|
+
- lib/goose_game/gameboard.rb
|
79
|
+
- lib/goose_game/gameplay.rb
|
80
|
+
- lib/goose_game/messages.rb
|
81
|
+
- lib/goose_game/player.rb
|
82
|
+
- lib/goose_game/version.rb
|
83
|
+
homepage: https://github.com/costajob/goose_game.git
|
84
|
+
licenses:
|
85
|
+
- MIT
|
86
|
+
metadata: {}
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 2.4.1
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubygems_version: 3.0.3
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: Implementation of the Goose Game code kata
|
106
|
+
test_files: []
|