goose_game 1.0.0
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.
- 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: []
|