def _removeMemo( how_anlz_list: List[HowToAnalyze], region: Region, squ_list: List[Square] ) -> None: """メモの除外 ヒント(値)によってメモを除外 Args: how_anlz_list (List[ChangeHistroy]): 解析方法 region (Region): 領域 squ_list (List[Square]): 枡リスト """ # 確定枡を抽出 not_none_squ_list: List[Square] = SudokuUtil.find_fixed_squ_from_region( squ_list) # 未確定枡を抽出 none_squ_list: List[Square] = SudokuUtil.find_unfixed_squ_from_region( squ_list) # メモからヒント(値)を除外 for none_squ in none_squ_list: for memo in none_squ.memo_val_list[:]: for not_none_squ in not_none_squ_list: if memo == not_none_squ.get_fixed_val(): none_squ.memo_val_list.remove(memo) # 解析方法生成 how_anlz: HowToAnalyze = HowToAnalyze( Method.ELIMIONATION) how_anlz.region = region how_anlz.remove_memo_list.append(memo) how_anlz.changed_squ = none_squ how_anlz.trigger_squ_list.append(not_none_squ) how_anlz.msg = MsgFactory.how_to_elimionation(how_anlz) how_anlz_list.append(how_anlz)
def _analyze_naked_pair( wk: AnalyzeWk, how_anlz_list: List[HowToAnalyze], region: Region, squ_list: List[Square] ) -> None: """ネイキッドペア解析 Args: wk (AnalyzeWk): ワーク how_anlz_list (List[HowToAnalyze]): 解析方法 region (Region): 領域 """ # 未確定枡を取得 unfixed_list: List[Square] = SudokuUtil.find_unfixed_squ_from_region( squ_list) # 対象領域の全ての枡が確定している if len(unfixed_list) == 0: return # ペア数(2~8)を大きくしながら解析 # ※制限時は2~3 find_pair_cnt: int = 8 if Method.NAKED_PAIR in wk.limit_method_list: find_pair_cnt = 3 for naked_num in range(2, find_pair_cnt + 1): # 未確定枡数-1よりネイキッド数の方が大きくなったら処理終了 # [補足] # 未確定数とネイキッド数が同じ場合、必ず全ての枡がペアになるため除外するメモがなくなる # ⇒-1して終了条件の比較を行っている if len(unfixed_list) - 1 <= naked_num: return # ペア可能リストを算出 can_pair_list = list() for unfixed_squ in unfixed_list: if len(unfixed_squ.memo_val_list) > naked_num: continue # naked_num=3の場合 # +[1]--------------------------------------+ # | 1:1 1:2 1:3 | # | m=[N,M,O](@) m=[N,P](*) ? | # | 2:1 2:2 2:3 | # | m=[M,O]($) m=[M,Q](*) ? | # | 3:1 3:2 3:3 | # | m=[N,M](#) m=[O,R](*) m=[N,M,O,R,Q,S] | # +[4]--------------------------------------+ # @枡、$枡、#枡、*枡3個を抽出 # 1:1 m=[N,M,O](@) # 1:2 m=[N,P](*) # 2:1 m=[M,O]($) # 2:2 m=[M,Q](*) # 3:1 m=[N,M](#) # 3:2 m=[O,R](*) can_pair_list.append(unfixed_squ) # ペア可能リストがペア数より小さい場合は対象外 # 次のペア数を調べる if len(can_pair_list) < naked_num: continue # ペアを見つける # 例に当てはめると # 1:1 m=[N,M,O](@) # 1:2 m=[N,P](*) # 2:1 m=[M,O]($) # 2:2 m=[M,Q](*) # 3:1 m=[N,M](#) # 3:2 m=[O,R](*) # から # 1:1 m=[N,M,O](@) # 2:1 m=[M,O]($) # 3:1 m=[N,M](#) # を見つける for pivot_squ in can_pair_list[:]: pivot_pair: Set[int] = set(pivot_squ.memo_val_list) for compare_squ in can_pair_list[:]: if pivot_squ == compare_squ: continue pivot_pair = pivot_pair.union(set(compare_squ.memo_val_list)) if len(pivot_pair) > naked_num: break if len(pivot_pair) > naked_num: can_pair_list.remove(pivot_squ) # ネイキッド数≒枡数は対象外 if len(can_pair_list) != naked_num: continue # ペア発見! pair_set: Set[int] = set() for squ in can_pair_list: pair_set = pair_set.union(squ.memo_val_list) pair_list: List[int] = list(pair_set) pair_list.sort() # 変更枡抽出 change_squ_list: List[Square] = list() for squ in unfixed_list: if squ in can_pair_list: continue for memo in squ.memo_val_list: if memo in pair_list: change_squ_list.append(squ) break # ペアは見つかったが、変更枡が存在しない if len(change_squ_list) == 0: continue for change_squ in change_squ_list: for loop_memo in pair_list: if loop_memo not in change_squ.memo_val_list: continue # メモを除外 change_squ.memo_val_list.remove(loop_memo) # 解析方法生成 how_anlz: HowToAnalyze = HowToAnalyze( Method.NAKED_PAIR) how_anlz.region = region how_anlz.changed_squ = change_squ how_anlz.remove_memo_list.append(loop_memo) how_anlz.trigger_squ_list.extend(can_pair_list) how_anlz.msg = MsgFactory.how_to_naked_pair( how_anlz, pair_list) how_anlz_list.append(how_anlz)