@@ -175,6 +175,66 @@ def test_naked_triple_clears_unit() -> None:
175175 assert cand [target [0 ]][target [1 ]] == before [target ] - {removed }
176176
177177
178+ def test_naked_triple_column_elimination () -> None :
179+ grid = _empty_grid ()
180+ cand = candidates (grid )
181+ digits = (1 , 2 , 3 , 4 )
182+ for d in digits :
183+ _clear_digit (cand , d )
184+ column = 5
185+ triple_cells = ((0 , column ), (1 , column ), (2 , column ))
186+ _set_candidates (cand , 0 , column , {1 , 2 })
187+ _set_candidates (cand , 1 , column , {1 , 3 })
188+ _set_candidates (cand , 2 , column , {2 , 3 })
189+ _set_candidates (cand , 3 , column , {1 , 4 })
190+
191+ before = {pos : cand [pos [0 ]][pos [1 ]].copy () for pos in (* triple_cells , (3 , column ))}
192+
193+ move = apply_naked_triple (grid , cand )
194+
195+ assert move is not None
196+ assert move ["strategy" ] == "naked_triple"
197+ assert move ["unit" ] == "col"
198+ assert move ["unit_index" ] == column
199+ target = (move ["r" ], move ["c" ])
200+ removed = move ["v" ]
201+
202+ assert target [1 ] == column
203+ assert target in before
204+ assert removed in {1 , 2 , 3 }
205+ assert removed in before [target ]
206+ assert cand [target [0 ]][target [1 ]] == before [target ] - {removed }
207+
208+
209+ def test_naked_triple_box_elimination () -> None :
210+ grid = _empty_grid ()
211+ cand = candidates (grid )
212+ digits = (1 , 2 , 3 , 4 )
213+ for d in digits :
214+ _clear_digit (cand , d )
215+ triple_cells = ((0 , 0 ), (1 , 1 ), (2 , 2 ))
216+ _set_candidates (cand , 0 , 0 , {1 , 2 })
217+ _set_candidates (cand , 1 , 1 , {1 , 3 })
218+ _set_candidates (cand , 2 , 2 , {2 , 3 })
219+ _set_candidates (cand , 2 , 0 , {1 , 4 })
220+
221+ before = {pos : cand [pos [0 ]][pos [1 ]].copy () for pos in (* triple_cells , (2 , 0 ))}
222+
223+ move = apply_naked_triple (grid , cand )
224+
225+ assert move is not None
226+ assert move ["strategy" ] == "naked_triple"
227+ assert move ["unit" ] == "box"
228+ assert move ["unit_index" ] == 0
229+ target = (move ["r" ], move ["c" ])
230+ removed = move ["v" ]
231+
232+ assert target in before
233+ assert removed in {1 , 2 , 3 }
234+ assert removed in before [target ]
235+ assert cand [target [0 ]][target [1 ]] == before [target ] - {removed }
236+
237+
178238def test_hidden_triple_culls_extras () -> None :
179239 grid = _empty_grid ()
180240 cand = candidates (grid )
@@ -194,6 +254,29 @@ def test_hidden_triple_culls_extras() -> None:
194254 assert extra not in cand [3 ][0 ]
195255
196256
257+ def test_hidden_triple_column_culls_extras () -> None :
258+ grid = _empty_grid ()
259+ cand = candidates (grid )
260+ triple = (4 , 5 , 6 )
261+ extra = 7
262+ for d in (* triple , extra ):
263+ _clear_digit (cand , d )
264+ column = 6
265+ _set_candidates (cand , 0 , column , {4 , 5 , 6 , extra })
266+ _set_candidates (cand , 3 , column , {4 , 5 })
267+ _set_candidates (cand , 7 , column , {5 , 6 })
268+
269+ move = apply_hidden_triple (grid , cand )
270+
271+ assert move is not None
272+ assert move ["strategy" ] == "hidden_triple"
273+ assert move ["unit" ] == "col"
274+ assert move ["unit_index" ] == column
275+ assert move ["r" ] == 0 and move ["c" ] == column
276+ assert move ["remove" ] == extra
277+ assert cand [0 ][column ] == set (triple )
278+
279+
197280def test_x_wing_rows_then_cols () -> None :
198281 grid = _empty_grid ()
199282 cand = candidates (grid )
0 commit comments