just_checkers 0.3.3 → 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 +4 -4
- data/just_checkers.gemspec +2 -1
- data/lib/just_checkers/square.rb +8 -57
- data/lib/just_checkers/square_set.rb +7 -148
- data/lib/just_checkers/version.rb +1 -1
- metadata +17 -5
- data/lib/just_checkers/direction.rb +0 -42
- data/lib/just_checkers/vector.rb +0 -95
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fabb7610908ffb7ed90de11e7a43d592b94f3855
|
4
|
+
data.tar.gz: fa87a6420ff5b3274df8d33e9de3beb7c47ed41c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45de02e0328b9ec03bfa44e5235326abfa5bc300e056989ea1c39f1e5f4e909a6dcbf90dc174afc946b6d953055af9303b9e8aa862df82bcf0bb3b8b0d1e3f3a
|
7
|
+
data.tar.gz: e4ea11adbd062eafea5e496f639f30b7743726358be839258170b603f4d6207b9b0675cc4c9a903b1b4a0c974fe4f1cf3e73ae96fe8966aaca8d18ca285c38ce
|
data/just_checkers.gemspec
CHANGED
@@ -19,9 +19,10 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.required_ruby_version = '>= 2.
|
22
|
+
spec.required_ruby_version = '>= 2.2'
|
23
23
|
|
24
24
|
spec.add_development_dependency "bundler", "~> 1.11"
|
25
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
26
26
|
spec.add_development_dependency 'minitest', '~> 5.8'
|
27
|
+
spec.add_development_dependency 'board_game_grid', '~> 0.1'
|
27
28
|
end
|
data/lib/just_checkers/square.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'just_checkers/piece'
|
2
2
|
require 'just_checkers/point'
|
3
|
+
require 'board_game_grid'
|
3
4
|
|
4
5
|
module JustCheckers
|
5
6
|
|
6
7
|
# = Square
|
7
8
|
#
|
8
9
|
# A Square on a board of checkers
|
9
|
-
class Square
|
10
|
+
class Square < BoardGameGrid::Square
|
10
11
|
|
11
12
|
# New objects can be instantiated by passing in a hash with
|
12
13
|
#
|
@@ -41,54 +42,11 @@ module JustCheckers
|
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
44
|
-
#
|
45
|
-
attr_reader :id
|
46
|
-
|
47
|
-
# @return [Fixnum] the x co-ordinate of the square.
|
48
|
-
attr_reader :x
|
49
|
-
|
50
|
-
# @return [Fixnum] the y co-ordinate of the square.
|
51
|
-
attr_reader :y
|
52
|
-
|
53
|
-
# @return [Piece,NilClass] The piece on the square if any.
|
54
|
-
attr_accessor :piece
|
55
|
-
|
56
|
-
# checks if the square matches the attributes passed.
|
57
|
-
#
|
58
|
-
# @param [Symbol] attribute
|
59
|
-
# the square's attribute.
|
60
|
-
#
|
61
|
-
# @param [Object,Hash] value
|
62
|
-
# a value to match on. Can be a hash of attribute/value pairs for deep matching
|
63
|
-
#
|
64
|
-
# ==== Example:
|
65
|
-
# # Check if square has a piece owned by player 1
|
66
|
-
# square.attribute_match?(:piece, player_number: 1)
|
67
|
-
def attribute_match?(attribute, value)
|
68
|
-
hash_obj_matcher = lambda do |obj, k, v|
|
69
|
-
value = obj.send(k)
|
70
|
-
if !value.nil? && v.is_a?(Hash)
|
71
|
-
v.all? { |k2,v2| hash_obj_matcher.call(value, k2, v2) }
|
72
|
-
else
|
73
|
-
value == v
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
hash_obj_matcher.call(self, attribute, value)
|
78
|
-
end
|
79
|
-
|
80
|
-
# Is the square unoccupied by a piece?
|
81
|
-
#
|
82
|
-
# @return [Boolean]
|
83
|
-
def unoccupied?
|
84
|
-
piece.nil?
|
85
|
-
end
|
86
|
-
|
87
|
-
# A point object with the square's co-ordinates.
|
45
|
+
# A serialized version of the square as a hash
|
88
46
|
#
|
89
|
-
# @return [
|
90
|
-
def
|
91
|
-
|
47
|
+
# @return [Hash]
|
48
|
+
def as_json
|
49
|
+
{ id: id, x: x, y: y, piece: piece && piece.as_json }
|
92
50
|
end
|
93
51
|
|
94
52
|
# All squares that a piece on this square could jump to, given the board.
|
@@ -101,7 +59,7 @@ module JustCheckers
|
|
101
59
|
#
|
102
60
|
# @return [SquareSet]
|
103
61
|
def possible_jumps(piece, squares)
|
104
|
-
squares.
|
62
|
+
squares.at_range(self, 2).in_direction_of(piece, self).unoccupied.select do |s|
|
105
63
|
squares.between(self, s).occupied_by_opponent_of(piece.player_number).any?
|
106
64
|
end
|
107
65
|
end
|
@@ -116,7 +74,7 @@ module JustCheckers
|
|
116
74
|
#
|
117
75
|
# @return [SquareSet]
|
118
76
|
def possible_moves(piece, squares)
|
119
|
-
squares.
|
77
|
+
squares.at_range(self, 1).in_direction_of(piece, self).unoccupied
|
120
78
|
end
|
121
79
|
|
122
80
|
# Checks if the piece on the square can promote.
|
@@ -139,12 +97,5 @@ module JustCheckers
|
|
139
97
|
def promote
|
140
98
|
piece && piece.promote
|
141
99
|
end
|
142
|
-
|
143
|
-
# A serialized version of the square as a hash
|
144
|
-
#
|
145
|
-
# @return [Hash]
|
146
|
-
def as_json
|
147
|
-
{ id: id, x: x, y: y, piece: piece && piece.as_json }
|
148
|
-
end
|
149
100
|
end
|
150
101
|
end
|
@@ -1,14 +1,12 @@
|
|
1
|
-
require '
|
1
|
+
require 'board_game_grid'
|
2
2
|
require 'just_checkers/square'
|
3
|
-
require 'just_checkers/vector'
|
4
3
|
|
5
4
|
module JustCheckers
|
6
5
|
|
7
6
|
# = Square Set
|
8
7
|
#
|
9
8
|
# A collection of Squares with useful filtering functions
|
10
|
-
class SquareSet
|
11
|
-
extend Forwardable
|
9
|
+
class SquareSet < BoardGameGrid::SquareSet
|
12
10
|
|
13
11
|
# New objects can be instantiated by passing in a hash with squares.
|
14
12
|
# They can be square objects or hashes.
|
@@ -24,104 +22,15 @@ module JustCheckers
|
|
24
22
|
# ]
|
25
23
|
# })
|
26
24
|
def initialize(squares: [])
|
27
|
-
@squares = if squares.
|
25
|
+
@squares = if squares.all? { |element| element.instance_of?(Hash) }
|
26
|
+
squares.map { |args| JustCheckers::Square.new(args) }
|
27
|
+
elsif squares.all? { |element| element.instance_of?(JustCheckers::Square) }
|
28
28
|
squares
|
29
29
|
else
|
30
|
-
squares
|
30
|
+
raise ArgumentError, "all squares must have the same class"
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
# @return [Array<Square>] The squares in the set.
|
35
|
-
attr_reader :squares
|
36
|
-
|
37
|
-
def_delegator :squares, :first
|
38
|
-
def_delegator :squares, :size
|
39
|
-
def_delegator :squares, :include?
|
40
|
-
def_delegator :squares, :any?
|
41
|
-
def_delegator :squares, :none?
|
42
|
-
def_delegator :squares, :empty?
|
43
|
-
|
44
|
-
# Iterate over the squares with a block and behaves like Enumerable#each.
|
45
|
-
#
|
46
|
-
# @return [Enumerable]
|
47
|
-
def each(&block)
|
48
|
-
squares.each(&block)
|
49
|
-
end
|
50
|
-
|
51
|
-
# Filter the squares with a block and behaves like Enumerable#select.
|
52
|
-
# It returns a SquareSet with the filtered squares.
|
53
|
-
#
|
54
|
-
# @return [SquareSet]
|
55
|
-
def select(&block)
|
56
|
-
self.class.new(squares: squares.select(&block))
|
57
|
-
end
|
58
|
-
|
59
|
-
# Filter the squares with a hash of attribute and matching values.
|
60
|
-
#
|
61
|
-
# @param [Hash] hash
|
62
|
-
# attributes to query for.
|
63
|
-
#
|
64
|
-
# @return [SquareSet]
|
65
|
-
#
|
66
|
-
# ==== Example:
|
67
|
-
# # Find all squares where piece is nil
|
68
|
-
# square_set.where(piece: nil)
|
69
|
-
def where(hash)
|
70
|
-
res = hash.inject(squares) do |memo, (attribute, value)|
|
71
|
-
memo.select { |square| square.attribute_match?(attribute, value) }
|
72
|
-
end
|
73
|
-
self.class.new(squares: res)
|
74
|
-
end
|
75
|
-
|
76
|
-
# Find the square with the matching x and y co-ordinates
|
77
|
-
#
|
78
|
-
# @param [Fixnum] x
|
79
|
-
# the x co-ordinate.
|
80
|
-
#
|
81
|
-
# @param [Fixnum] y
|
82
|
-
# the y co-ordinate.
|
83
|
-
#
|
84
|
-
# @return [Square]
|
85
|
-
# ==== Example:
|
86
|
-
# # Find the square at 4,2
|
87
|
-
# square_set.find_by_x_and_y(4, 2)
|
88
|
-
def find_by_x_and_y(x, y)
|
89
|
-
select { |s| s.x == x && s.y == y }.first
|
90
|
-
end
|
91
|
-
|
92
|
-
# Find the square with the matching unique identifier
|
93
|
-
#
|
94
|
-
# @param [Fixnum] id
|
95
|
-
# the unique identifier.
|
96
|
-
#
|
97
|
-
# @return [Square]
|
98
|
-
# ==== Example:
|
99
|
-
# # Find the square with id 4
|
100
|
-
# square_set.find_by_id(4)
|
101
|
-
def find_by_id(id)
|
102
|
-
select { |s| s.id == id }.first
|
103
|
-
end
|
104
|
-
|
105
|
-
# Return all squares that are one square away from the passed square.
|
106
|
-
#
|
107
|
-
# @param [Square] square
|
108
|
-
# the square in question.
|
109
|
-
#
|
110
|
-
# @return [SquareSet]
|
111
|
-
def one_square_away_from(square)
|
112
|
-
select { |s| Vector.new(square, s).magnitude == 1 }
|
113
|
-
end
|
114
|
-
|
115
|
-
# Return all squares that are two squares away from the passed square.
|
116
|
-
#
|
117
|
-
# @param [Square] square
|
118
|
-
# the square in question.
|
119
|
-
#
|
120
|
-
# @return [SquareSet]
|
121
|
-
def two_squares_away_from(square)
|
122
|
-
select { |s| Vector.new(square, s).magnitude == 2 }
|
123
|
-
end
|
124
|
-
|
125
34
|
# Find squares in the direction of the piece from the square
|
126
35
|
# If the piece is normal, it returns squares in front of it.
|
127
36
|
# If the piece is king, it returns all squares.
|
@@ -139,51 +48,10 @@ module JustCheckers
|
|
139
48
|
# square_set.in_direction_of(piece, square)
|
140
49
|
def in_direction_of(piece, square)
|
141
50
|
select do |s|
|
142
|
-
piece.king? || Vector.new(square, s).
|
51
|
+
piece.king? || BoardGameGrid::Vector.new(square, s).direction.y == piece.direction
|
143
52
|
end
|
144
53
|
end
|
145
54
|
|
146
|
-
# Find all squares without pieces on them.
|
147
|
-
#
|
148
|
-
# @return [SquareSet]
|
149
|
-
def unoccupied
|
150
|
-
select(&:unoccupied?)
|
151
|
-
end
|
152
|
-
|
153
|
-
# Returns squares between a and b.
|
154
|
-
# Only squares that are in the same diagonal will return squares.
|
155
|
-
#
|
156
|
-
# @param [Square] a
|
157
|
-
# a square.
|
158
|
-
#
|
159
|
-
# @param [Square] b
|
160
|
-
# another square.
|
161
|
-
#
|
162
|
-
# @return [SquareSet]
|
163
|
-
#
|
164
|
-
# ==== Example:
|
165
|
-
# # Get all squares between square_a and square_b
|
166
|
-
# square_set.between(square_a, square_b)
|
167
|
-
def between(a, b)
|
168
|
-
vector = Vector.new(a, b)
|
169
|
-
if vector.diagonal
|
170
|
-
point_counter = a.point
|
171
|
-
direction = vector.direction
|
172
|
-
squares = []
|
173
|
-
|
174
|
-
while point_counter != b.point
|
175
|
-
point_counter = point_counter + direction
|
176
|
-
square = find_by_x_and_y(point_counter.x, point_counter.y)
|
177
|
-
if square && square.point != b.point
|
178
|
-
squares.push(square)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
else
|
182
|
-
squares = []
|
183
|
-
end
|
184
|
-
self.class.new(squares: squares)
|
185
|
-
end
|
186
|
-
|
187
55
|
# Takes a player number and returns all squares occupied by the opponent of the player
|
188
56
|
#
|
189
57
|
# @param [Fixnum] player_number
|
@@ -203,14 +71,5 @@ module JustCheckers
|
|
203
71
|
def occupied_by(player_number)
|
204
72
|
select { |s| s.piece && s.piece.player_number == player_number }
|
205
73
|
end
|
206
|
-
|
207
|
-
attr_reader :squares
|
208
|
-
|
209
|
-
# serializes the squares as a hash
|
210
|
-
#
|
211
|
-
# @return [Hash]
|
212
|
-
def as_json
|
213
|
-
squares.map(&:as_json)
|
214
|
-
end
|
215
74
|
end
|
216
75
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: just_checkers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Humphreys
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '5.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: board_game_grid
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.1'
|
55
69
|
description: Provides a representation of a checkers game complete with rules enforcement
|
56
70
|
and serialisation.
|
57
71
|
email:
|
@@ -70,7 +84,6 @@ files:
|
|
70
84
|
- bin/setup
|
71
85
|
- just_checkers.gemspec
|
72
86
|
- lib/just_checkers.rb
|
73
|
-
- lib/just_checkers/direction.rb
|
74
87
|
- lib/just_checkers/errors/empty_square_error.rb
|
75
88
|
- lib/just_checkers/errors/error.rb
|
76
89
|
- lib/just_checkers/errors/invalid_move_error.rb
|
@@ -81,7 +94,6 @@ files:
|
|
81
94
|
- lib/just_checkers/point.rb
|
82
95
|
- lib/just_checkers/square.rb
|
83
96
|
- lib/just_checkers/square_set.rb
|
84
|
-
- lib/just_checkers/vector.rb
|
85
97
|
- lib/just_checkers/version.rb
|
86
98
|
homepage: https://github.com/mrlhumphreys/just_checkers
|
87
99
|
licenses:
|
@@ -95,7 +107,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
95
107
|
requirements:
|
96
108
|
- - ">="
|
97
109
|
- !ruby/object:Gem::Version
|
98
|
-
version: '2.
|
110
|
+
version: '2.2'
|
99
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
112
|
requirements:
|
101
113
|
- - ">="
|
@@ -1,42 +0,0 @@
|
|
1
|
-
module JustCheckers
|
2
|
-
|
3
|
-
# = Direction
|
4
|
-
#
|
5
|
-
# The Direction that something is moving on a 2d plane
|
6
|
-
class Direction
|
7
|
-
|
8
|
-
# New objects can be instantiated with
|
9
|
-
#
|
10
|
-
# @param [Fixnum] x
|
11
|
-
# the x magnitude.
|
12
|
-
#
|
13
|
-
# @param [Fixnum] y
|
14
|
-
# the y magnitude.
|
15
|
-
#
|
16
|
-
# ==== Example:
|
17
|
-
# # Instantiates a new Direction
|
18
|
-
# JustCheckers::Direction.new({
|
19
|
-
# x: 1,
|
20
|
-
# y: 1
|
21
|
-
# })
|
22
|
-
def initialize(x, y)
|
23
|
-
@x, @y = x, y
|
24
|
-
end
|
25
|
-
|
26
|
-
# @return [Fixnum] the x magnitude.
|
27
|
-
attr_reader :x
|
28
|
-
|
29
|
-
# @return [Fixnum] the y magnitude.
|
30
|
-
attr_reader :y
|
31
|
-
|
32
|
-
# Check if directions are equal by seeing if their magnitudes are equal.
|
33
|
-
#
|
34
|
-
# @param [Direction] other
|
35
|
-
# the other direction to compare to.
|
36
|
-
#
|
37
|
-
# @return [Boolean]
|
38
|
-
def ==(other)
|
39
|
-
self.x == other.x && self.y == other.y
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/lib/just_checkers/vector.rb
DELETED
@@ -1,95 +0,0 @@
|
|
1
|
-
require 'just_checkers/direction'
|
2
|
-
|
3
|
-
module JustCheckers
|
4
|
-
|
5
|
-
# = Vector
|
6
|
-
#
|
7
|
-
# An element of Vector space
|
8
|
-
class Vector
|
9
|
-
|
10
|
-
# New objects can be instantiated by passing in a two points with x and y co-ordinates
|
11
|
-
#
|
12
|
-
# @param [Point] a
|
13
|
-
# the start point.
|
14
|
-
#
|
15
|
-
# @param [Point] b
|
16
|
-
# the end point.
|
17
|
-
#
|
18
|
-
# ==== Example:
|
19
|
-
# # Instantiates a new Vector
|
20
|
-
# JustCheckers::Vector.new({
|
21
|
-
# a: JustCheckers::Point.new(x: 1, y: 1),
|
22
|
-
# b: JustCheckers::Point.new(x: 3, y: 3)
|
23
|
-
# })
|
24
|
-
def initialize(a, b)
|
25
|
-
@a, @b = a, b
|
26
|
-
end
|
27
|
-
|
28
|
-
# @return [Point] the start point.
|
29
|
-
attr_reader :a
|
30
|
-
|
31
|
-
# @return [Point] the end point.
|
32
|
-
attr_reader :b
|
33
|
-
|
34
|
-
# How big the vector is if it's diagonal, otherwise, nil.
|
35
|
-
#
|
36
|
-
# @return [Fixnum,NilClass]
|
37
|
-
def magnitude
|
38
|
-
if diagonal
|
39
|
-
dx.abs
|
40
|
-
else
|
41
|
-
nil
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# The direction of the vector as a object
|
46
|
-
#
|
47
|
-
# @return [Direction]
|
48
|
-
def direction
|
49
|
-
Direction.new(direction_x, direction_y)
|
50
|
-
end
|
51
|
-
|
52
|
-
# The x component of the direction, 1 if moving down, -1 if moving up, 0 otherwise
|
53
|
-
#
|
54
|
-
# @return [Fixnum]
|
55
|
-
def direction_x
|
56
|
-
if dx > 0
|
57
|
-
1
|
58
|
-
elsif dx == 0
|
59
|
-
0
|
60
|
-
else
|
61
|
-
-1
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# The y component of the direction, 1 if moving right, -1 if moving left, 0 otherwise
|
66
|
-
#
|
67
|
-
# @return [Fixnum]
|
68
|
-
def direction_y
|
69
|
-
if dy > 0
|
70
|
-
1
|
71
|
-
elsif dy == 0
|
72
|
-
0
|
73
|
-
else
|
74
|
-
-1
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# Is the vector diagonal?
|
79
|
-
#
|
80
|
-
# @return [Boolean]
|
81
|
-
def diagonal
|
82
|
-
dx.abs == dy.abs
|
83
|
-
end
|
84
|
-
|
85
|
-
private
|
86
|
-
|
87
|
-
def dx
|
88
|
-
b.x - a.x
|
89
|
-
end
|
90
|
-
|
91
|
-
def dy
|
92
|
-
b.y - a.y
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|