@@ -389,6 +389,66 @@ def test_naked_triple_clears_unit() -> None:
389389 assert cand [target [0 ]][target [1 ]] == before [target ] - {removed }
390390
391391
392+ def test_naked_triple_column_elimination () -> None :
393+ grid = _empty_grid ()
394+ cand = candidates (grid )
395+ digits = (1 , 2 , 3 , 4 )
396+ for d in digits :
397+ _clear_digit (cand , d )
398+ column = 5
399+ triple_cells = ((0 , column ), (1 , column ), (2 , column ))
400+ _set_candidates (cand , 0 , column , {1 , 2 })
401+ _set_candidates (cand , 1 , column , {1 , 3 })
402+ _set_candidates (cand , 2 , column , {2 , 3 })
403+ _set_candidates (cand , 3 , column , {1 , 4 })
404+
405+ before = {pos : cand [pos [0 ]][pos [1 ]].copy () for pos in (* triple_cells , (3 , column ))}
406+
407+ move = apply_naked_triple (grid , cand )
408+
409+ assert move is not None
410+ assert move ["strategy" ] == "naked_triple"
411+ assert move ["unit" ] == "col"
412+ assert move ["unit_index" ] == column
413+ target = (move ["r" ], move ["c" ])
414+ removed = move ["v" ]
415+
416+ assert target [1 ] == column
417+ assert target in before
418+ assert removed in {1 , 2 , 3 }
419+ assert removed in before [target ]
420+ assert cand [target [0 ]][target [1 ]] == before [target ] - {removed }
421+
422+
423+ def test_naked_triple_box_elimination () -> None :
424+ grid = _empty_grid ()
425+ cand = candidates (grid )
426+ digits = (1 , 2 , 3 , 4 )
427+ for d in digits :
428+ _clear_digit (cand , d )
429+ triple_cells = ((0 , 0 ), (1 , 1 ), (2 , 2 ))
430+ _set_candidates (cand , 0 , 0 , {1 , 2 })
431+ _set_candidates (cand , 1 , 1 , {1 , 3 })
432+ _set_candidates (cand , 2 , 2 , {2 , 3 })
433+ _set_candidates (cand , 2 , 0 , {1 , 4 })
434+
435+ before = {pos : cand [pos [0 ]][pos [1 ]].copy () for pos in (* triple_cells , (2 , 0 ))}
436+
437+ move = apply_naked_triple (grid , cand )
438+
439+ assert move is not None
440+ assert move ["strategy" ] == "naked_triple"
441+ assert move ["unit" ] == "box"
442+ assert move ["unit_index" ] == 0
443+ target = (move ["r" ], move ["c" ])
444+ removed = move ["v" ]
445+
446+ assert target in before
447+ assert removed in {1 , 2 , 3 }
448+ assert removed in before [target ]
449+ assert cand [target [0 ]][target [1 ]] == before [target ] - {removed }
450+
451+
392452def test_hidden_triple_culls_extras () -> None :
393453 grid = _empty_grid ()
394454 cand = candidates (grid )
@@ -408,6 +468,29 @@ def test_hidden_triple_culls_extras() -> None:
408468 assert extra not in cand [3 ][0 ]
409469
410470
471+ def test_hidden_triple_column_culls_extras () -> None :
472+ grid = _empty_grid ()
473+ cand = candidates (grid )
474+ triple = (4 , 5 , 6 )
475+ extra = 7
476+ for d in (* triple , extra ):
477+ _clear_digit (cand , d )
478+ column = 6
479+ _set_candidates (cand , 0 , column , {4 , 5 , 6 , extra })
480+ _set_candidates (cand , 3 , column , {4 , 5 })
481+ _set_candidates (cand , 7 , column , {5 , 6 })
482+
483+ move = apply_hidden_triple (grid , cand )
484+
485+ assert move is not None
486+ assert move ["strategy" ] == "hidden_triple"
487+ assert move ["unit" ] == "col"
488+ assert move ["unit_index" ] == column
489+ assert move ["r" ] == 0 and move ["c" ] == column
490+ assert move ["remove" ] == extra
491+ assert cand [0 ][column ] == set (triple )
492+
493+
411494def test_x_wing_rows_then_cols () -> None :
412495 grid = _empty_grid ()
413496 cand = candidates (grid )
0 commit comments