Skip to content

Commit be9396c

Browse files
committed
Improve F2L sloting
1 parent 582558a commit be9396c

File tree

3 files changed

+106
-10
lines changed

3 files changed

+106
-10
lines changed

term_timer/methods/cfop.py

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@
2626
'F2L Back Right': f2l_case_encoder(F2L_BL_MASK),
2727
}
2828

29+
# Anticipated compensation order
30+
# because check_step will perform computing using opposite top face
31+
# but keep front face, which rotate the cube like a z2 rotation.
32+
F2L_SLOTS = [
33+
'Front Left', 'Front Right',
34+
'Back Left', 'Back Right',
35+
]
36+
2937

3038
class CFOPAnalyser(Analyser):
3139
"""
@@ -332,15 +340,11 @@ def compute_progress(self, facelets: str,
332340

333341
if not self.check_step('OLL', facelets, self.orientation_faces):
334342
name = ['F2L 1', 'F2L 2', 'F2L 3', 'F2L 4']
335-
# Anticipated compensation
336-
# because check_step will perform computing using opposite top face
337-
# but keep front face, which rotate the cube like a z2 rotation.
338-
pair = ['Front Left', 'Front Right', 'Back Left', 'Back Right']
339343

340344
score = 1
341345
pairs: list[str] = []
342346

343-
for n, p in zip(name, pair, strict=True):
347+
for n, p in zip(name, F2L_SLOTS, strict=True):
344348
result = self.check_step(n, facelets, self.orientation_faces)
345349
if result:
346350
score += 1
@@ -393,12 +397,37 @@ def correct_summary(self, summary: list[StepSummary]) -> None: # noqa: C901, PL
393397
if 'OLL' in info['name']:
394398
info['name'] = 'F2L 4'
395399
info['case_infos'] = sorted(
396-
{
397-
'Front Left', 'Front Right',
398-
'Back Left', 'Back Right',
399-
} - set(case_infos),
400+
set(F2L_SLOTS) - set(case_infos),
400401
)
401402

403+
# Merge remaining F2L pairs into the last F2L entry
404+
f2l_covered: set[int] = set()
405+
last_f2l_idx = -1
406+
407+
for i, info in enumerate(summary):
408+
if 'Cross' in info['name']:
409+
f2l_covered.update(range(1, info['name'].count('X') + 1))
410+
elif 'F2L ' in info['name']:
411+
last_f2l_idx = i
412+
for part in info['name'].replace('F2L ', '').split('+'):
413+
if part.isdigit():
414+
f2l_covered.add(int(part))
415+
416+
if last_f2l_idx >= 0 and len(f2l_covered) < 4:
417+
last = summary[last_f2l_idx]
418+
missing = sorted({1, 2, 3, 4} - f2l_covered)
419+
if missing:
420+
current = [
421+
int(p)
422+
for p in last['name'].replace('F2L ', '').split('+')
423+
if p.isdigit()
424+
]
425+
all_nums = sorted(current + missing)
426+
last['name'] = 'F2L ' + '+'.join(map(str, all_nums))
427+
last['case_infos'] = sorted(
428+
set(F2L_SLOTS) - set(case_infos),
429+
)
430+
402431
self.correct_summary_cfop(summary)
403432

404433
if 'Cross' not in summary[0]['name']:

term_timer/tests/test_solve_108.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def test_summary(self) -> None:
5252
outputs = [
5353
('XXCross', 'step'),
5454
('F2L', 'virtual'),
55-
('F2L 4', 'substep'),
55+
('F2L 3+4', 'substep'),
5656
('OLL', 'skipped'),
5757
('PLL', 'step'),
5858
]

term_timer/tests/test_solve_32.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,70 @@ def test_summary(self) -> None:
193193
source['type'],
194194
expected[1],
195195
)
196+
197+
198+
class TestSolve32RFOrientationCF4OP(TestSolve32):
199+
"""Test Solve with broken result for checking output in CF4OP."""
200+
201+
def setUp(self) -> None:
202+
"""Test setup."""
203+
super().setUp()
204+
self.solve.method_name = 'cf4op'
205+
self.solve.orientation = 'RF'
206+
207+
def test_summary(self) -> None:
208+
"""Test summary."""
209+
method_applied = get_method_applied(self.solve)
210+
inputs = method_applied.summary
211+
outputs = [
212+
('Cross', 'step'),
213+
('F2L', 'virtual'),
214+
('F2L 1+2', 'substep'),
215+
('F2L 3+4', 'substep'),
216+
('OLL', 'skipped'),
217+
('PLL', 'skipped'),
218+
]
219+
220+
for source, expected in zip(inputs, outputs, strict=True):
221+
with self.subTest(name=source['name']):
222+
self.assertEqual(
223+
source['name'],
224+
expected[0],
225+
)
226+
self.assertEqual(
227+
source['type'],
228+
expected[1],
229+
)
230+
231+
232+
class TestSolve32UROrientationCF4OP(TestSolve32):
233+
"""Test Solve with broken result for checking output in CF4OP."""
234+
235+
def setUp(self) -> None:
236+
"""Test setup."""
237+
super().setUp()
238+
self.solve.method_name = 'cf4op'
239+
self.solve.orientation = 'UR'
240+
241+
def test_summary(self) -> None:
242+
"""Test summary."""
243+
method_applied = get_method_applied(self.solve)
244+
inputs = method_applied.summary
245+
outputs = [
246+
('XCross', 'step'),
247+
('F2L', 'virtual'),
248+
('F2L 2+3+4', 'substep'),
249+
('OLL', 'skipped'),
250+
('PLL', 'skipped'),
251+
]
252+
253+
for source, expected in zip(inputs, outputs, strict=True):
254+
with self.subTest(name=source['name']):
255+
self.assertEqual(
256+
source['name'],
257+
expected[0],
258+
)
259+
self.assertEqual(
260+
source['type'],
261+
expected[1],
262+
)

0 commit comments

Comments
 (0)