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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6a652941a37584d1c3448d3a904eaf7568a96c7d
4
- data.tar.gz: 25df3f4619cefcffc64c38c6e2ccf0931d5fb4f3
3
+ metadata.gz: fabb7610908ffb7ed90de11e7a43d592b94f3855
4
+ data.tar.gz: fa87a6420ff5b3274df8d33e9de3beb7c47ed41c
5
5
  SHA512:
6
- metadata.gz: 2fc08be188d77cd15ae9e2a990e25e232cebda974ad3a5cd6ec57387878e0ec03c315e26cb18ab46e1b9923140e3ca7822c6aa6f488efb2268ac9f617aabeefd
7
- data.tar.gz: cd2b521698896e634c979d39361c81fc68dfa7f160677587945a4aa834afa2bb0d9ae6937f223d41f8be95d59aeeadb50d01aeafdd43fe5b81f4167e05909fbd
6
+ metadata.gz: 45de02e0328b9ec03bfa44e5235326abfa5bc300e056989ea1c39f1e5f4e909a6dcbf90dc174afc946b6d953055af9303b9e8aa862df82bcf0bb3b8b0d1e3f3a
7
+ data.tar.gz: e4ea11adbd062eafea5e496f639f30b7743726358be839258170b603f4d6207b9b0675cc4c9a903b1b4a0c974fe4f1cf3e73ae96fe8966aaca8d18ca285c38ce
@@ -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.1'
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
@@ -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
- # @return [Fixnum] the unique identifier of the square.
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 [Point]
90
- def point
91
- Point.new(x, y)
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.two_squares_away_from(self).in_direction_of(piece, self).unoccupied.select do |s|
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.one_square_away_from(self).in_direction_of(piece, self).unoccupied
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 'forwardable'
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.first.class == Square
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.map { |s| Square.new(s) }
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).direction_y == piece.direction
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
@@ -1,4 +1,4 @@
1
1
  module JustCheckers
2
2
  # :nodoc:
3
- VERSION = "0.3.3"
3
+ VERSION = "1.0.0"
4
4
  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.3.3
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: 2017-12-28 00:00:00.000000000 Z
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.1'
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
@@ -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