twisty_puzzles 0.0.9 → 0.0.10

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
  SHA256:
3
- metadata.gz: 3dfb23949825572c531ac7bfcea491151629f8673160605069b1793a827d961a
4
- data.tar.gz: f343cc589e99ac129717f47a7b3dbe4dcb3d4a0cbcae2e0f8c42b12b22ad842c
3
+ metadata.gz: 7616a5e5bd64a5beb6ea98bed6a6f6bc2dc5ae145491db533e4693cd10d0ff6d
4
+ data.tar.gz: 8bc2cd597844fb86f9168c8e368c6bbb01cc34a82598ebef7f5dcb77c1e3713c
5
5
  SHA512:
6
- metadata.gz: 2fc20aef94e333318c53ee292b5418424ad8880cc2f8ff18c2102d0799d96728ccc9a98869269bf9c6a046174dcf5f71182cf6498021838d8772c18a7008cfe2
7
- data.tar.gz: b79344d44bf6fd32cd9443c79405dcab052867a746e23fecc0b1496bd96b36fc6c4dd09d2a8c3d33389d7e5b5daaf0ca4a0552cce8948c59ac590da458c6150d
6
+ metadata.gz: 42c3be051514680426bed25b66ca09b8c420f1423a778db10512c37663c42128136acf6f4e72847bed68d4111e8563ef5eb1cd427883bf2802e072853f1900b0
7
+ data.tar.gz: d26d1c98f90f7bbd15474ac45f200a483983daadfae40016e5f9d2f0ca44b20a652e480f8bbfc13d939f904140358a1acc741fcbbb09306f35b51a298f3a9cf1
@@ -143,6 +143,10 @@ module TwistyPuzzles
143
143
  prepend_slice_move(other, cube_size)
144
144
  end
145
145
 
146
+ def prepend_slice_move(_other, _cube_size)
147
+ raise NotImplementedError, "#{self.class}#prepend_slice_move is not implemented"
148
+ end
149
+
146
150
  private
147
151
 
148
152
  def move_count_internal(metric, slice_factor, direction_factor)
@@ -31,14 +31,14 @@ module TwistyPuzzles
31
31
  def parse_move(move_string)
32
32
  match = move_string.match(regexp)
33
33
  if !match || !match.pre_match.empty? || !match.post_match.empty?
34
- raise ArgumentError("Invalid move #{move_string}.")
34
+ raise ArgumentError, "Invalid move #{move_string}."
35
35
  end
36
36
 
37
37
  parsed_parts = parse_named_captures(match)
38
38
  move_type_creators.each do |parser|
39
39
  return parser.create(parsed_parts) if parser.applies_to?(parsed_parts)
40
40
  end
41
- raise "No move type creator applies to #{parsed_parts}"
41
+ raise ArgumentError, "No move type creator applies to #{parsed_parts}"
42
42
  end
43
43
  end
44
44
  end
@@ -4,28 +4,36 @@ require 'twisty_puzzles/cube_direction'
4
4
  require 'twisty_puzzles/rotation'
5
5
 
6
6
  module TwistyPuzzles
7
- AlgorithmTransformation =
8
- Struct.new(:rotation, :mirror, :mirror_normal_face) do
9
- def transformed(algorithm)
10
- algorithm = algorithm.mirror(mirror_normal_face) if mirror
11
- algorithm.rotate_by(rotation)
12
- end
7
+ # A transformation consisting of mirroring and rotating that can be applied to an algorithm.
8
+ class AlgorithmTransformation
9
+ def initialize(rotation, mirror, mirror_normal_face)
10
+ @rotation = rotation
11
+ @mirror = mirror
12
+ @mirror_normal_face = mirror_normal_face
13
+ end
13
14
 
14
- def identity?
15
- rotation.identity? && !mirror
16
- end
15
+ attr_reader :rotation, :mirror, :mirror_normal_face
17
16
 
18
- # Returns algorithm transformations that mirror an algorithm and rotate it around a face.
19
- def self.around_face(face)
20
- around_face_rotations = CubeDirection::ALL_DIRECTIONS.map { |d| Rotation.new(face, d) }
21
- mirror_normal_face = face.neighbors.first
22
- around_face_rotations.product([true, false]).map do |r, m|
23
- AlgorithmTransformation.new(r, m, mirror_normal_face)
24
- end
25
- end
17
+ def transformed(algorithm)
18
+ algorithm = algorithm.mirror(mirror_normal_face) if mirror
19
+ algorithm.rotate_by(rotation)
20
+ end
26
21
 
27
- def self.around_face_without_identity(face)
28
- around_face(face).reject(&:identity?)
22
+ def identity?
23
+ rotation.identity? && !mirror
24
+ end
25
+
26
+ # Returns algorithm transformations that mirror an algorithm and rotate it around a face.
27
+ def self.around_face(face)
28
+ around_face_rotations = CubeDirection::ALL_DIRECTIONS.map { |d| Rotation.new(face, d) }
29
+ mirror_normal_face = face.neighbors.first
30
+ around_face_rotations.product([true, false]).map do |r, m|
31
+ AlgorithmTransformation.new(r, m, mirror_normal_face)
29
32
  end
30
33
  end
34
+
35
+ def self.around_face_without_identity(face)
36
+ around_face(face).reject(&:identity?)
37
+ end
38
+ end
31
39
  end
@@ -55,7 +55,9 @@ module TwistyPuzzles
55
55
  self
56
56
  else
57
57
  rotation_neighbors = rotation.axis_face.neighbors
58
- face_index = rotation_neighbors.index(@axis_face) || raise
58
+ face_index = rotation_neighbors.index(@axis_face)
59
+ raise unless face_index
60
+
59
61
  new_axis_face =
60
62
  rotation_neighbors[(face_index + rotation.direction.value) % rotation_neighbors.length]
61
63
  fields = replace_once(identifying_fields, @axis_face, new_axis_face)
@@ -37,7 +37,7 @@ module TwistyPuzzles
37
37
  end
38
38
 
39
39
  def part_for_colors(part_type, colors)
40
- raise ArgumentError unless part_type.is_a?(Class)
40
+ raise ArgumentError unless part_type.is_a?(Class) && (part_type < Part)
41
41
 
42
42
  part_type.for_face_symbols(colors.map { |c| face_symbol(c) })
43
43
  end
@@ -95,10 +95,12 @@ module TwistyPuzzles
95
95
 
96
96
  def chirality_corner_source_and_unknown_index(obvious_turned_face_symbols_to_colors)
97
97
  corner_matcher =
98
- CornerMatcher.new(CHIRALITY_FACE_SYMBOLS.map do |s|
99
- # This will return nil for exactly one face that we don't know yet.
100
- @colors_to_face_symbols[obvious_turned_face_symbols_to_colors[s]]
101
- end)
98
+ CornerMatcher.new(
99
+ CHIRALITY_FACE_SYMBOLS.map do |s|
100
+ # This will return nil for exactly one face that we don't know yet.
101
+ @colors_to_face_symbols[obvious_turned_face_symbols_to_colors[s]]
102
+ end
103
+ )
102
104
 
103
105
  # There should be exactly one corner that gets mapped to the chirality corner.
104
106
  chirality_corner_source =
@@ -10,6 +10,10 @@ module TwistyPuzzles
10
10
  def cancellations(other, cube_size, metric = :htm)
11
11
  algorithm.cancellations(other.algorithm, cube_size, metric)
12
12
  end
13
+
14
+ def algorithm
15
+ raise NotImplementedError
16
+ end
13
17
  end
14
18
 
15
19
  # Algorithm that is used like a commutator but actually isn't one.
@@ -6,7 +6,6 @@ require 'twisty_puzzles/native'
6
6
 
7
7
  module TwistyPuzzles
8
8
  # Coordinate of a sticker on the cube.
9
- # rubocop:disable Metrics/ClassLength
10
9
  class Coordinate
11
10
  def self.highest_coordinate(cube_size)
12
11
  cube_size - 1
@@ -122,23 +121,6 @@ module TwistyPuzzles
122
121
  from_indices(face, cube_size, m, m)
123
122
  end
124
123
 
125
- def self.face(face, cube_size)
126
- neighbor_a, neighbor_b = face.neighbors[0..1]
127
- coordinate_range(cube_size).collect_concat do |x|
128
- coordinate_range(cube_size).map do |y|
129
- from_face_distances(face, cube_size, neighbor_a => x, neighbor_b => y)
130
- end
131
- end
132
- end
133
-
134
- def self.layer(face, cube_size)
135
- face.neighbors.zip(face.neighbors.rotate(1)).collect_concat do |neighbor, next_neighbor|
136
- coordinate_range(cube_size).map do |i|
137
- from_face_distances(neighbor, cube_size, face => 0, next_neighbor => i)
138
- end
139
- end + self.face(face, cube_size)
140
- end
141
-
142
124
  def self.edges_outside(face, cube_size)
143
125
  face.neighbors.zip(face.neighbors.rotate(1)).collect_concat do |neighbor, next_neighbor|
144
126
  1.upto(cube_size - 2).map do |i|
@@ -279,7 +261,6 @@ module TwistyPuzzles
279
261
  rots
280
262
  end
281
263
  end
282
- # rubocop:enable Metrics/ClassLength
283
264
 
284
265
  # Coordinate of a sticker on the Skewb.
285
266
  class SkewbCoordinate
@@ -64,10 +64,18 @@ module TwistyPuzzles
64
64
  true
65
65
  end
66
66
 
67
+ def num_incarnations(_cube_size)
68
+ 1
69
+ end
70
+
67
71
  def base_index_on_face(cube_size, incarnation_index)
68
72
  base_index_on_other_face(solved_face, cube_size, incarnation_index)
69
73
  end
70
74
 
75
+ def base_index_on_other_face(face, cube_size, incarnation_index)
76
+ raise NotImplementedError
77
+ end
78
+
71
79
  def self.for_face_symbols_internal(face_symbols)
72
80
  raise unless face_symbols.length == self::FACES
73
81
 
@@ -82,6 +90,10 @@ module TwistyPuzzles
82
90
  self::ELEMENTS[index]
83
91
  end
84
92
 
93
+ def self.valid?(_face_symbols)
94
+ false
95
+ end
96
+
85
97
  def <=>(other)
86
98
  @piece_index <=> other.piece_index
87
99
  end
@@ -110,7 +122,7 @@ module TwistyPuzzles
110
122
  # Rotate a piece such that the given face symbol is the first face symbol.
111
123
  def rotate_face_symbol_up(face_symbol)
112
124
  index = @face_symbols.index(face_symbol)
113
- raise "Part #{self} doesn't have face symbol #{c}." unless index
125
+ raise "Part #{self} doesn't have face symbol #{face_symbol}." unless index
114
126
 
115
127
  rotate_by(index)
116
128
  end
@@ -133,10 +145,6 @@ module TwistyPuzzles
133
145
  (0...@face_symbols.length).map { |i| rotate_by(i) }
134
146
  end
135
147
 
136
- def self.create_for_face_symbols(face_symbols)
137
- new(face_symbols)
138
- end
139
-
140
148
  def self.parse(piece_description)
141
149
  face_symbols =
142
150
  piece_description.upcase.strip.split('').map do |e|
@@ -338,10 +346,6 @@ module TwistyPuzzles
338
346
  find_only(self::ELEMENTS) { |e| e.corresponding_part == corresponding_part }
339
347
  end
340
348
 
341
- def self.create_for_face_symbols(face_symbols)
342
- new(self::CORRESPONDING_PART_CLASS.create_for_face_symbols(face_symbols))
343
- end
344
-
345
349
  def face_symbol
346
350
  @face_symbols[0]
347
351
  end
@@ -514,7 +518,7 @@ module TwistyPuzzles
514
518
  end
515
519
 
516
520
  def num_incarnations(cube_size)
517
- [cube_size / 2 - 1, 0].max
521
+ cube_size > 3 ? cube_size / 2 - 1 : 0
518
522
  end
519
523
 
520
524
  # One index of such a piece on a on a NxN face.
@@ -530,14 +534,6 @@ module TwistyPuzzles
530
534
  class Corner < Part
531
535
  FACES = 3
532
536
 
533
- def self.create_for_face_symbols(face_symbols)
534
- piece_candidates =
535
- face_symbols[1..].permutation.map do |cs|
536
- new([face_symbols[0]] + cs)
537
- end
538
- find_only(piece_candidates, &:valid?)
539
- end
540
-
541
537
  def self.for_face_symbols(face_symbols)
542
538
  unless face_symbols.length == FACES
543
539
  raise "Invalid number of face_symbols to create a corner: #{face_symbols.inspect}"
@@ -621,7 +617,7 @@ module TwistyPuzzles
621
617
  ELEMENTS = generate_parts
622
618
 
623
619
  def num_incarnations(cube_size)
624
- [cube_size / 2 - 1, 0].max
620
+ cube_size > 3 ? cube_size / 2 - 1 : 0
625
621
  end
626
622
 
627
623
  # One index of such a piece on a on a NxN face.
@@ -644,10 +640,10 @@ module TwistyPuzzles
644
640
  end
645
641
 
646
642
  def num_incarnations(cube_size)
647
- if cube_size.even?
643
+ if cube_size.even? || cube_size <= 3
648
644
  0
649
645
  else
650
- [cube_size / 2 - 1, 0].max
646
+ cube_size / 2 - 1
651
647
  end
652
648
  end
653
649
 
@@ -75,6 +75,16 @@ module TwistyPuzzles
75
75
 
76
76
  alias == eql?
77
77
 
78
+ def rotation_algorithms
79
+ Rotation::ALL_ROTATIONS.combination(2).reject do |r0, r1|
80
+ r0.inverse == r1
81
+ end.map { |rs| Algorithm.new(rs) } # rubocop:disable Style/MultilineBlockChain
82
+ end
83
+
84
+ def equal_modulo_rotations?(other)
85
+ rotation_algorithms.any? { |r| r.apply_temporarily_to(self) { |state| state == other } }
86
+ end
87
+
78
88
  def hash
79
89
  @hash ||= [self.class, @native].hash
80
90
  end
@@ -35,10 +35,12 @@ module TwistyPuzzles
35
35
 
36
36
  direction = translated_direction(skewb_direction)
37
37
 
38
- Algorithm.new([
39
- Rotation.new(corner.faces[skewb_direction.value], direction),
40
- Rotation.new(corner.faces[0], direction)
41
- ])
38
+ Algorithm.new(
39
+ [
40
+ Rotation.new(corner.faces[skewb_direction.value], direction),
41
+ Rotation.new(corner.faces[0], direction)
42
+ ]
43
+ )
42
44
  end
43
45
 
44
46
  def to_s
@@ -26,10 +26,12 @@ module TwistyPuzzles
26
26
  next unless c2.face_symbols.include?(c1_rot.face_symbols.first)
27
27
 
28
28
  c2_rot = c2.rotate_face_symbol_up(c1_rot.face_symbols.first)
29
- check_parts.push([
30
- SkewbCoordinate.for_corner(c1_rot),
31
- SkewbCoordinate.for_corner(c2_rot)
32
- ])
29
+ check_parts.push(
30
+ [
31
+ SkewbCoordinate.for_corner(c1_rot),
32
+ SkewbCoordinate.for_corner(c2_rot)
33
+ ]
34
+ )
33
35
  end
34
36
  matching_corners.push(check_parts)
35
37
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TwistyPuzzles
4
- VERSION = '0.0.9'
4
+ VERSION = '0.0.10'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twisty_puzzles
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernhard F. Brodowsky