您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
根据游戏规则与回溯法自动求解0h n0盘面
// ==UserScript== // @name 0hn0求解器 // @namespace https://greasyfork.org/users/471937 // @version 0.1 // @description 根据游戏规则与回溯法自动求解0h n0盘面 // @author 油油 // @match 0hn0.com/ // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; var n var new_tile var init_tiles, counted_tiles var Game = window.Game const OFFSET = [[1, 0], [0, 1], [-1, 0], [0, -1]] // 监控盘面开局状态 var classObs = new MutationObserver(mus => { var updater = mus .map(mu => (mu.attributeName === "class" && mu.target)) .reduce((x, y) => (x || y)) if (!updater) return if (updater.classList.contains('hidden')) { show_panel(false) } else { show_panel(true) init() } }) classObs.observe(document.querySelector('#board'), { attributes: true }) // 添加工具栏 var toolbar = document.createElement('div') Object.assign(toolbar.style, { position: 'absolute', zIndex: 1000, }) document.body.appendChild(toolbar) add_tool('重置', () => { init_tiles.forEach(t => t.value = -1) counted_tiles.forEach(t => t.unmark()) }) add_tool('执行一层', game_action(brute_once)) add_tool('求解', game_action(brute_solve)) show_panel(false) function game_action(action) { return () => { action() Game.checkForLevelComplete() } } function add_tool(name, action) { var btn = document.createElement('button') btn.innerText = name btn.addEventListener('click', action) toolbar.appendChild(btn) } function show_panel(visible) { toolbar.style.display = visible ? 'flex' : 'none' } function init() { n = Game.grid.width init_tiles = Game.grid.emptyTiles counted_tiles = Game.grid.tiles.filter(x => x.value > 0) } function count_data(tile) { var raw = [] var line, flag_empty, cnt for (var dir = 0; dir < 4; dir++) { line = [] flag_empty = false cnt = 0 for (var step = 1; ; step++) { var new_tile = _step(tile, dir, step) if (!new_tile || new_tile.value == 0) { // wall switch_status() break } if (flag_empty == (new_tile.value == -1)) cnt++ else switch_status() } raw.push(line) } var res = { tile: tile, raw: raw, cap: raw.map(_sum), } res.curr = _sum(raw.map(x => x[0])) res.cap_sum = _sum(res.cap) return res function switch_status() { line.push(cnt) cnt = 1 flag_empty = !flag_empty } } function check_tile(tile) { var dir, data = count_data(tile) if (data.curr > tile.value) { // error tile.mark() return false } if (data.curr == tile.value) { if (data.curr == data.cap_sum) return false // finished // rule 1 for (dir = 0; dir < 4; dir++) { var new_tile = _step(tile, dir, data.raw[dir][0] + 1) if (new_tile) new_tile.value = 0 } return true } // rule 2 for (dir = 0; dir < 4; dir++) { var left = tile.value - (data.cap_sum - data.cap[dir]) if (left > 0) { var filled = false while (left > 0) { new_tile = _step(tile, dir, left) if (new_tile && new_tile.value == -1) { new_tile.value = -2 filled = true } left-- } if (filled) return true } } // rule 3 for (dir = 0; dir < 4; dir++) { var line = data.raw[dir] if (line.length < 3 || line[1] != 1) continue if (data.curr + line[2] >= tile.value) { new_tile = _step(tile, dir, line[0] + 1) new_tile.value = 0 return true } } } function brute_once() { var res = counted_tiles.map(check_tile) .reduce((x, y) => (x | y)) // rule 4 Game.grid.emptyTiles.forEach(tile => { var tmp = 0 for (var dir = 0; dir < 4; dir++) { new_tile = _step(tile, dir, 1) tmp += !(new_tile && new_tile.value) } if (tmp == 4) { tile.value = 0 res = true } }) return res } function brute_solve() { while (brute_once()); } function _step(tile, dir, step) { var new_x = tile.x + OFFSET[dir][0] * step, new_y = tile.y + OFFSET[dir][1] * step return Game.grid.tile(new_x, new_y) } function _sum(array) { var res = 0 for (var x of array) res += x return res } })();