def _find_share_squ(wk: AnalyzeWk, squ1: Square, squ2: Square) -> List[Square]: """2個の枡の共通枡を検索 Args: wk (AnalyzeWk): 解析WK squ1 (Square): 枡1 squ2 (Square): 枡2 Returns: List[Square]: 共通枡 """ share_list: List[Square] = list() region_area_level: Region = _which_region_area_level(squ1, squ2) # エリアレベルで枡1、枡2が同一行、同一列に存在する場合 if region_area_level == Region.ROW or\ region_area_level == Region.CLM: region_pos_squ1: int region_pos_squ2: int if region_area_level == Region.ROW: region_pos_squ1 = squ1.row region_pos_squ2 = squ2.row else: region_pos_squ1 = squ1.clm region_pos_squ2 = squ2.clm # 枡1と枡2が同一行(列) if region_pos_squ1 == region_pos_squ2: # +[1]-------------------+[2]-------------------+[3]-------------------+ # | 1:1(1) 1:2(*) 1:3(*) | 1:4(2) 1:5(*) 1:6(*) | 1:7(*) 1:8(*) 1:9(*) | # *枡が共通枡になる region_squ_list: List[Square] if region_area_level == Region.ROW: region_squ_list = wk.row_dict[region_pos_squ1] else: region_squ_list = wk.clm_dict[region_pos_squ1] for region_squ in region_squ_list: if region_squ == squ1 or region_squ == squ2: continue share_list.append(region_squ) # 枡1と枡2が別行(列) else: # +[1]-------------------+[2]-------------------+[3]-------------------+ # | 1:1(1) 1:2 1:3 | 1:4 1:5 1:6 | 1:7(*) 1:8(*) 1:9(*) | # | 2:1 2:2 2:3 | 2:4 2:5 2:6 | 2:7 2:8 2:9 | # | 3:1(*) 3:2(*) 3:3(*) | 3:4 3:5 3:6 | 3:7(2) 3:8 3:9 | # *枡が共通枡になる # 枡1と同一行(列)にある枡を取得 # +[1]-------------------+[2]-------------------+[3]-------------------+ # | 1:1(1) 1:2 1:3 | 1:4 1:5 1:6 | 1:7(*) 1:8(*) 1:9(*) | # ^^^^^^ ^^^^^^ ^^^^^^ region_squ_list1: List[Square] if region_area_level == Region.ROW: region_squ_list1 = wk.row_dict[squ1.row] else: region_squ_list1 = wk.clm_dict[squ1.clm] for region_squ in region_squ_list1: # 枡2と同一エリアにある枡を対象に if region_squ == squ1 or\ region_squ.area_id != squ2.area_id: continue share_list.append(region_squ) # 枡2と同一行(列)にある枡を取得 # | 3:1(*) 3:2(*) 3:3(*) | 3:4 3:5 3:6 | 3:7(2) 3:8 3:9 | # ^^^^^^ ^^^^^^ ^^^^^^ region_squ_list2: List[Square] if region_area_level == Region.ROW: region_squ_list2 = wk.row_dict[squ2.row] else: region_squ_list2 = wk.clm_dict[squ2.clm] for region_squ in region_squ_list2: # 枡1と同一エリアにある枡を対象に if region_squ == squ2 or\ region_squ.area_id != squ1.area_id: continue share_list.append(region_squ) # エリアレベルで枡1、枡2が同一行、同一列に存在しない場合 else: # 交差枡を算出する share_list = SudokuUtil.find_cross_squ(wk, squ1, squ2) return share_list
def analyze(wk: AnalyzeWk, how_anlz_list: List[HowToAnalyze]) -> bool: """シンプルチェーン 1つの数字に注目して 枡 =強= 枡 =弱= 枡 =強= 枡 =弱= 枡 =強= 枡 のように強リンクではじまって弱リンク、強リンク...の組み合わせが続き、 強リンクで終わるパターンで最初と最後の交差枡にはその数字は入らないという解法 ※弱リンクの部分は強リンクになっても可 ※強リンク、弱リンクの解説はLinkType.pyのdocstringを参照 例> +[1]-------------------------+[2]-------------------------+[3]-------------------------+ | 1:1 1:2 1:3 | 1:4 1:5 1:6 | 1:7 1:8 1:9 | | ? ? ? | ? ? ? | ? ? hint=N | | 2:1 2:2 2:3 | 2:4 2:5 2:6 | 2:7 2:8 2:9 | | ? ? ? | ? ? hint=N | ? ? ? | | 3:1 3:2 3:3 | 3:4 3:5 3:6 | 3:7 3:8 3:9 | | hint=N ? ? | ? ? ? | ? ? ? | +[4]-------------------------+[5]-------------------------+[6]-------------------------+ | 4:1 4:2 4:3 | 4:4 4:5(#) 4:6 | 4:7 4:8 4:9 | | ? ? m=[N,?] | ? m=[N,?] ? | ? ? ? | | 5:1 5:2 5:3 | 5:4 5:5 5:6 | 5:7 5:8 5:9 | | ? ? ? | ? ? ? | hint=N ? ? | | 6:1 6:2(*) 6:3 | 6:4(@) 6:5 6:6 | 6:7 6:8 6:9 | | ? m=[N,?] m=[N,?] | m=[N,?] ? ? | ? ? ? | +[7]-------------------------+[8]-------------------------+[9]-------------------------+ | 7:1 7:2 7:3 | 7:4 7:5 7:6 | 7:7 7:8 7:9 | | ? m=[N,?] m=[N,?] | ? ? ? | ? ? ? | | 8:1 8:2 8:3 | 8:4 8:5 8:6 | 8:7 8:8 8:9 | | ? ? ? | m=[N,?] m=[N,?] ? | ? hint=N ? | | 9:1 9:2(+) 9:3 | 9:4 9:5(!) 9:6 | 9:7 9:8 9:9 | | ? m=[N,?] ? | ? m=[N,?] ? | ? ? ? | +----------------------------+----------------------------+----------------------------+ ※8:8がNで確定している、上記のような状態の枠は本処理には来ないが、、、説明用に目をつぶる 数字Nで以下のチェーンが形成されている @枡 =強= #枡 =弱= !枡 =強= +枡 チェーンの最初の@枡と最後の+枡の交差枡(*枡)からNを除外することが出来る。 検証> 上記例に当てはめて交差枡*がNで確定すると仮定 ・@枡からNが除外される @枡 =強= #枡 =弱= !枡 =強= +枡 ^^^ ・#枡がNで確定する @枡 =強= #枡 =弱= !枡 =強= +枡 ^^^ ・!枡からNが除外される @枡 =強= #枡 =弱= !枡 =強= +枡 ^^^ ・+枡がNで確定する @枡 =強= #枡 =弱= !枡 =強= +枡 ^^^ +[1]-------------------------+[2]-------------------------+[3]-------------------------+ | 1:1 1:2 1:3 | 1:4 1:5 1:6 | 1:7 1:8 1:9 | | ? ? ? | ? ? ? | ? ? hint=N | | 2:1 2:2 2:3 | 2:4 2:5 2:6 | 2:7 2:8 2:9 | | ? ? ? | ? ? hint=N | ? ? ? | | 3:1 3:2 3:3 | 3:4 3:5 3:6 | 3:7 3:8 3:9 | | hint=N ? ? | ? ? ? | ? ? ? | +[4]-------------------------+[5]-------------------------+[6]-------------------------+ | 4:1 4:2 4:3 | 4:4 4:5(#) 4:6 | 4:7 4:8 4:9 | | ? ? m=[?] | ? v=N ? | ? ? ? | | 5:1 5:2 5:3 | 5:4 5:5 5:6 | 5:7 5:8 5:9 | | ? ? ? | ? ? ? | hint=N ? ? | | 6:1 6:2(*) 6:3 | 6:4(@) 6:5 6:6 | 6:7 6:8 6:9 | | ? v=N m=[?] | m=[?] ? ? | ? ? ? | +[7]-------------------------+[8]-------------------------+[9]-------------------------+ | 7:1 7:2 7:3 | 7:4 7:5 7:6 | 7:7 7:8 7:9 | | ? m=[?] m=[N,?] | ? ? ? | ? ? ? | | 8:1 8:2 8:3 | 8:4 8:5 8:6 | 8:7 8:8 8:9 | | ? ? ? | m=[N,?] m=[?] ? | ? hint=N ? | | 9:1 9:2(+) 9:3 | 9:4 9:5(!) 9:6 | 9:7 9:8 9:9 | | ? v=N ? | ? m=[?] ? | ? ? ? | +----------------------------+----------------------------+----------------------------+ 2列目でNが2つ出てくるため矛盾が生じる。 Args: wk (AnalyzeWk): ワーク how_anlz_list (List[HowToAnalyze]): 解析方法 Returns: bool: エラーの場合にFalse """ for loop_memo in range(1, 10): # チェーンを作成 all_chain_list: List[List[Chain]] =\ _create_simple_chain(wk, loop_memo) for chain_list in all_chain_list: first_squ = chain_list[0].squ last_squ = chain_list[len(chain_list) - 1].squ # 交差枡取得 cross_squ_list: List[Square] = SudokuUtil.find_cross_squ( wk, first_squ, last_squ) # 交差枡が変更対象かどうか判定 change_squ_list: List[Square] = list() for cross_squ in cross_squ_list: # 未確定かつメモが存在する枡が対象となる if cross_squ.get_fixed_val() is None and\ loop_memo in cross_squ.memo_val_list: change_squ_list.append(cross_squ) # 対象なし # ⇒次のチェーンをチェック if len(change_squ_list) == 0: continue # 対象あり chain_squ_list: List[Square] = list() for chain in chain_list: chain_squ_list.append(chain.squ) for change_squ in change_squ_list: # メモを除外 change_squ.memo_val_list.remove(loop_memo) # 解析方法生成 how_anlz: HowToAnalyze = HowToAnalyze(Method.SIMPLE_CHAIN) how_anlz.changed_squ = change_squ how_anlz.remove_memo_list.append(loop_memo) how_anlz.trigger_squ_list.extend(chain_squ_list) how_anlz.chain_squ_list.extend(chain_squ_list) how_anlz.msg = MsgFactory.how_to_simple_chain(how_anlz) how_anlz_list.append(how_anlz) return True return True