<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      數織(Nonogram)解謎思路與解謎邏輯2

      如果游戲棋盤特別大,那么以生成所有結果再進行篩選的方式也會變得龐大無比導致頁面卡死,所以必須有一種輕量的邏輯來對數據進行處理

      源碼

      type RuleList = number[]
      type IndexList = number[]
      type CellItem = { value: -1 | 0 | 1 }
      type CellMap = Record<string, CellItem>
      // type BarLimit = { rule: RuleList, cellKeyList: string[], indexList: IndexList }
      type BarItem = { rule: RuleList, rule_re: RuleList, cellKeyList: string[], frontLimitIndexList: IndexList, backLimitIndexList: IndexList }
      type BarMap = Record<string, BarItem>;
      const inputRowRestrict = `3 8 4 2 3 1,1 3 3 3 3 3 4 1 1,1 3 1 4 1 5 1,2 6 1 5 2 5 2,1 6 6 1 1,4 1 1 1 4 3,2 3 2 1 4 2 1 1 4,4 10 1 6 7,3 3 1 9 5 5,3 4 4 1 1 4 3,1 1 3 3 5 6 1 1 1 1 1,10 2 10 2 5 1,12 3 10 3 7,1 7 1 7 2 4 4,1 1 1 1 4 7 4 1 5,1 3 1 1 2 7,9 4 4,1 2 3 8 4 2,5 3 7 1 3 4 1,5 1 6 1 5 1 1,4 1 1 4 2 3 3 3,4 1 1 6 1 2 3 3,4 1 1 1 4 3 1 1 4,5 4 7 3 1 1 2 1,5 4 7 3 2 1 4,5 4 7 2 1 11 2 1 1,7 4 6 1 6 2 6,6 5 8 9 3,5 2 2 1 3 1 4 2 4,6 2 8 1 2 2 3,2 3 1 1 2 4 4 3 3 3,2 1 2 6 4 6 3 2,3 1 7 3 6 1 2,2 5 3 5 2 1 5 2,8 3 5 3 3 2 2,3 5 1 4 3 6 3 1 2,3 3 21 3 3 2,1 1 1 9 1 5 3 2 1,1 2 10 8 3 3,2 1 3 7 1 6 2 2,2 1 4 2 2 7 1 1 2,3 1 1 13 2 1 5 5,12 3 1 1 1 3 8,1 1 1 4 6 6 1 2 5 4 3,3 5 2 1 3 3 3 4 10,14 7 4 1 10,9 5 5 3 8,2 10 4 3 5 4,1 3 3 1 3 3 2 5,4 1 1 1 5 5 1 5`;
      const inputColRestrict = `4 3 3 11 3 1 1 5 6,1 7 10 3 1 1 3 4,4 2 12 2 1 4,1 3 15 1 2,1 3 3 8 3 3 4,5 6 1 5 5 4,11 1 1 4 7,13 2 5 8,2 3 3 2 4 4 9,5 1 4 3 7 1 4 4 1 3,5 3 2 2 5 3 1 5 3 1,3 2 1 6 1 5 4,2 2 3 10,2 1 2 9,4 3 1 3 2 5 2,2 7 9 1 7,2 6 3 6 7 3,1 3 1 12 8 3,1 1 1 6 9 9 1,2 2 3 14 16 1,5 1 3 21 9,5 4 6 3 2 3 3 2,3 5 6 7 3 1,3 5 2 5 3 1 1,6 4 3 4 6 1,2 4 4 2 2 1 6,5 5 3 8,1 1 5 3 3 2 5,3 5 1 3 1 1 1 7,2 8 1 2 3 3 1 3,2 4 3 3 7 2,5 1 3 5,10 2 2 1 5 3,4 4 2 4 1 3 6 3,1 3 1 10 7 5,1 1 9 1 4 3 1,1 4 3 1 5 2,2 3 4 5 2,2 1 1 1 3 8 1 3,1 3 1 1 1 5 1 1,3 3 3 5,3 1 4 1 5 3 7,4 5 1 7 5 2 8,4 2 4 1 3 5 4 6,3 1 6 1 1 3 2 4 8,2 2 3 3 1 3 2 6,1 1 4 7 3 1 1 1 11,26 3 8,1 5 2 3 11 1 4 2,5 5 1 6 14 1 2 2`;
      /** 開始破解 */
      const start = (rowRuleStr: string, colRuleStr: string) => {
          let { cellMap, barMap } = createMap(rowRuleStr, colRuleStr)
          let archiveList: { barMap: BarMap, cellMap: CellMap }[] = []
          let time = 0
          let isDone = false
          do {
              let { isChange, isError } = crackBarMap(barMap, cellMap)
              if (isError) {
                  // 出現錯誤證明決策失誤,取出最后一條存檔
                  let lastArchive = archiveList.pop()
                  if (!lastArchive) {
                      throw new Error("無法破解");
                  }
                  Object.values(lastArchive.cellMap).some(v => {
                      if (!v.value) {
                          v.value = -1
                          return true
                      }
                      return false
                  })
                  barMap = lastArchive.barMap
                  cellMap = lastArchive.cellMap
              } else if (!isChange) {
                  archiveList.push({
                      barMap: JSON.parse(JSON.stringify(barMap)),
                      cellMap: JSON.parse(JSON.stringify(cellMap)),
                  })
                  isDone = Object.values(cellMap).every(v => {
                      if (!v.value) {
                          v.value = 1
                          return false
                      }
                      return true
                  })
              }
              time++
          } while (time < 99 && !isDone);
          console.log('time', time)
          // 開始解謎,解謎過程就是不斷對barMap進行處理
          Object.keys(barMap).forEach(v => {
              if (v.includes('r-')) {
                  let item = barMap[v]
                  console.log(item.cellKeyList.map(v2 => cellMap[v2].value === -1 ? ' ' : '1'), item.rule)
              }
          });
      }
      /** 創建數據集合 */
      const createMap = (rowRuleStr: string, colRuleStr: string) => {
          let rowRuleArr = getRule(rowRuleStr)
          let colRuleArr = getRule(colRuleStr)
          /** 單元格集合 */
          let cellMap: CellMap = {}
          /** 條(行/列)集合 */
          let barMap: BarMap = {}
          // 填充集合數據
          rowRuleArr.forEach((rowRule, rowIndex) => {
              barMap[`r-${rowIndex}`] = createBarItem(rowRule)
              colRuleArr.forEach((colRule, colIndex) => {
                  if (!barMap[`c-${colIndex}`]) {
                      barMap[`c-${colIndex}`] = createBarItem(colRule)
                  }
                  cellMap[`${rowIndex}-${colIndex}`] = { value: 0 } // -1不填,0待填,1填入
                  barMap[`r-${rowIndex}`].cellKeyList.push(`${rowIndex}-${colIndex}`)
                  barMap[`c-${colIndex}`].cellKeyList.push(`${rowIndex}-${colIndex}`)
              })
          })
          return { cellMap, barMap }
      }
      /** 獲取規則 */
      const getRule = (ruleStr: string) => ruleStr.replace(',', ',').split(',').map(v => v.split(' ').map(v2 => Number(v2)).filter(v2 => v2)).filter(v => v)
      /** 創建條數據 */
      const createBarItem = (rule: RuleList) => ({ rule, rule_re: [...rule].reverse(), cellKeyList: [], frontLimitIndexList: createLimitIndexList(rule), backLimitIndexList: createLimitIndexList([...rule].reverse()) })
      /** 創建極限坐標 */
      const createLimitIndexList = (rule: RuleList): number[] => rule.reduce<[number[], number]>(([arr, index], v) => [arr.concat(index), index + v + 1], [[], 0])[0];
      /** 破解條集合 */
      const crackBarMap = (barMap: BarMap, cellMap: CellMap) => {
          let isChange = false
          let isError = false
          Object.values(barMap).forEach(v => {
              let cellValueList = v.cellKeyList.map(v => cellMap[v].value)
              let cellValueList_re = [...cellValueList].reverse()
              let [frontLimitIndexList, frontLimitValueList] = handleLimitIndexList(v.frontLimitIndexList, v.rule, v.rule_re, cellValueList, cellValueList_re)
              let [backLimitIndexList, backLimitValueList] = handleLimitIndexList(v.backLimitIndexList, v.rule_re, v.rule, cellValueList_re, cellValueList)
              v.frontLimitIndexList = frontLimitIndexList
              v.backLimitIndexList = backLimitIndexList
              backLimitValueList.reverse()
              let absValue = (v.rule.length + 1) * 2
              cellValueList.forEach((v2, i2) => {
                  // 先檢查生成的值是否符合規則
                  if (v2 * frontLimitValueList[i2] < 0 || v2 * backLimitValueList[i2] < 0) {
                      isError = true
                      return
                  }
                  // 檢查是否匹配到了可確定項
                  if (Math.abs(frontLimitValueList[i2] + backLimitValueList[i2]) !== absValue) return
                  // 對未填充的單元格進行填充
                  if (!v2) {
                      cellMap[v.cellKeyList[i2]].value = (frontLimitValueList[i2]) > 0 ? 1 : -1
                      isChange = true
                  }
              })
          })
          return { isChange, isError }
      }
      /** 處理極限坐標 */
      const handleLimitIndexList = (indexList: IndexList, rule: RuleList, rule_re: RuleList, cellValueList: CellItem['value'][], cellValueList_re: CellItem['value'][]) => {
          // let cellValueList = limit.cellKeyList.map(v => cellMap[v].value)
          let indexArr = [...indexList]
          let indexIsChange: Boolean
          // 需要將極限坐標調整至符合單元格填充狀態
          do {
              indexIsChange = false
              // 第一遍,從前往后掃描,將不可填入的部分位置讓開
              cellValueList.forEach((v, i) => {
                  if (v !== -1) return
                  indexArr.forEach((v2, i2) => {
                      // 滿足條件證明v2與不可填入格沖突了,需要將v2放在不可填入格之后
                      if (v2 <= i && v2 + rule[i2] > i) {
                          indexArr[i2] = i + 1
                          indexIsChange = true
                      }
                      /** 第一個不執行下方檢查邏輯 */
                      if (!i2) return
                      /** 校正index使其符合rule */
                      if (indexArr[i2] < indexArr[i2 - 1] + rule[i2 - 1] + 1) {
                          indexArr[i2] = indexArr[i2 - 1] + rule[i2 - 1] + 1
                          indexIsChange = true
                      }
                  })
              })
              // 反轉坐標列表
              indexArr.reverse()
              let diff = cellValueList.length - 1
              // 第二遍,從后往前掃描,將填入的部分對齊
              cellValueList_re.forEach((v, i) => {
                  let originalIndex = diff - i
                  if (v !== 1) return
                  indexArr.some((v2, i2) => {
                      // 填入部分在標記范圍內不用處理
                      if (v2 <= originalIndex && v2 + rule_re[i2] > originalIndex) return true
                      // 坐標初始值小于填入部分,則需要將該坐標的標記范圍末端與填入部分對齊
                      if (v2 < originalIndex) {
                          indexArr[i2] = originalIndex + 1 - rule_re[i2]
                          indexIsChange = true
                          return true
                      }
                  })
              })
              // 反轉坐標列表
              indexArr.reverse()
              /** 校正index使其符合rule */
              indexArr.forEach((v2, i2) => {
                  /** 第一個不執行下方檢查邏輯 */
                  if (!i2) return
                  /** 校正index使其符合rule */
                  if (indexArr[i2] < indexArr[i2 - 1] + rule[i2 - 1] + 1) {
                      indexArr[i2] = indexArr[i2 - 1] + rule[i2 - 1] + 1
                      indexIsChange = true
                  }
              })
          } while (indexIsChange);
          let valueList: number[] = []
          let listValue = -1
          let listIndex = 0
          cellValueList.forEach((v, i) => {
              if (i === indexArr[listIndex]) {
                  listValue = listValue * -1 + 1
              }
              valueList.push(listValue)
              if (i === indexArr[listIndex] + rule[listIndex] - 1) {
                  listValue = listValue * -1 - 1
                  listIndex++
              }
          })
          return [indexArr, valueList]
      }
      start(inputRowRestrict, inputColRestrict)
      

      同樣是輸入規則字符串,不過這次沒有做可視化頁面,如果需要的話可以轉成js后運行,會輸出結果示意圖

      設計思路

      本次設計采用前后極限對齊取值的方式進行破解
      例如10格長度,規則是2 4

      初始一看有三個格子顏色一致,但是只以顏色判斷是不行的,需要對其進行編號

      這里的數字填充規則是不填部分用負數表示,填充部分用正數表示(需要注意-1有可能不存在,有些編碼從2開始)
      但是由于前后極限數字填充方向不一致,并不是數字相同的代表對齊,而是有一個特殊的校驗規則,同一位置的數字之和的絕對值等于規則個數加1再乘2,所以對于本條規則絕對值應該等于6,那么第7位就可確定填充

      那么問題就落在了怎么確定前后極限位置上

      避讓

      首先要對不填的位置進行避讓,深藍色表示連續填充的起始位置,此位置作為重要判斷依據

      從左往右依次判斷,到第2位發現已確認不填,那么就要看極限位置是否需要調整,需要調整就要將起始位置放到已確認不填之后,變為

      這時候就發現,極限位置重疊了,也就是說需要對極限位置進行梳理

      梳理完成后繼續判斷,第6位發現已確認不填,同樣調整位置后再進行梳理

      對齊

      避讓只處理已確認不填的位置,現在需要處理已確認填充的位置
      對齊操作要從右往左判斷,發現第5位為已確認填充且當前極限位置中沒有填充,那么需要將在它前面的、最近的、最后一位填充位置與其對齊

      對齊操作不會使極限位置重疊,因此不需要進行梳理
      但是,對齊操作導致的位置變動可能會使避讓處理失效(同理避讓處理也會讓對齊操作失效,不過對齊操作緊跟避讓操作立馬就修復了),所以要重復避讓-對齊-避讓-對齊操作直至極限位置不再發生變動
      處理操作的核心是極限位置盡可能不向右移動,但每次處理都在向右移動,相應的,后極限位置也在向左移動直至兩者保持一致,此時代表本條規則被破解了
      當所有規則都被破解,那么整個數織也就被破解了
      當然,其中還有決策機制,與前作中機制一致這里就不多做解釋了
      如果有時間我會盡可能將上邊羅里吧嗦的邏輯解釋轉變為頁面動畫,方便更加直觀的觀看整個結題過程

      posted @ 2025-06-26 10:37  杜柯楓  閱讀(35)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日日碰狠狠添天天爽超碰97| 在线观看美女网站大全免费| 亚洲男人AV天堂午夜在| 日韩精品区一区二区三vr| 国产色无码专区在线观看| 成人亚洲国产精品一区不卡| 国产成人精品午夜福利在线观看| 韩国主播av福利一区二区| 粉嫩国产一区二区三区在线| 中文字幕有码无码AV| 啪啪av一区二区三区| 国产精品自在线拍国产手青青机版| 精品自拍自产一区二区三区| 国产激情艳情在线看视频| 精品国产亚洲午夜精品av| 成人麻豆日韩在无码视频| 午夜天堂一区人妻| 溧水县| 亚洲精品综合久中文字幕| 国产二区三区不卡免费| 国产精品无码制服丝袜| 国产精品中文字幕第一区| 午夜国产精品福利一二| 日本高清视频网站www| 一二三三免费观看视频| 亚洲av中文久久精品国内| 2022亚洲男人天堂| 野外做受三级视频| 午夜福利日本一区二区无码| 少妇高潮喷潮久久久影院| 日韩中文字幕高清有码| 自拍偷拍一区二区三区四| 宅男噜噜噜66在线观看| 顺昌县| 污污网站18禁在线永久免费观看| 久久人妻公开中文字幕| 日韩国产中文字幕精品| 欧美嫩交一区二区三区| 无码日韩做暖暖大全免费不卡| 伊人色综合久久天天| 国产亚洲999精品AA片在线爽|