连连看
close_llk(); // toast("开始运行"); // while (true) { // sleep(200); // let img = images.captureScreen(); // let color = images.pixel(img, 410, 615); // // let color = images.pixel(img, 390, 615); // if (colors.isSimilar(color, color_target, 5, "rgb+")) break; // } // // sleep(4000) // let img = images.captureScreen(); // let img = images.read("/sdcard/Samsung Flow/llk2.png"); // llk(); var w = floaty.rawWindow( <frame gravity="center" w="226" h="70" alpha="0.6"> <horizontal> <button id="b_run" w="113" h="70" text="准备中"></button> <button id="b_auto" w="113" h="70" text="准备中"></button> </horizontal> </frame > ); w.setPosition(330, 2590); auto.waitFor(); images.requestScreenCapture(); events.on("exit", function () { img.recycle(); icon_block.recycle(); for (let k = 1; k <= 28; ++k) { imgIcons[k].recycle(); imgIcons_ice[k].recycle(); } log("recycle imgs done!") }); let icon_block = images.read("/sdcard/Samsung Flow/icon_block.png"); let imgIcons = new Array(29); let imgIcons_ice = new Array(29); for (let k = 1; k <= 28; ++k) { imgIcons[k] = images.read("/sdcard/Samsung Flow/llk1/" + k + ".png"); imgIcons_ice[k] = images.read("/sdcard/Samsung Flow/llkice1/" + k + ".png"); } let color_target = colors.parseColor("#F6A85E"); let llk_running = false; let manual_run = false; let llk_auto_run = true; // llk_auto_run = false; let llk_no_dfs = true; w.b_run.click(() => { if (!llk_running) { manual_run = true; w.b_run.setText("队列中"); } }); w.b_auto.click(() => { if (llk_auto_run) { llk_auto_run = false; w.b_auto.setText("已关闭自动运行"); } else { llk_auto_run = true; w.b_auto.setText("已开启自动运行"); } }); w.b_run.setText("手动启动"); w.b_auto.setText("已开启自动运行"); log("init done!"); while (true) { if (llk_auto_run) { img = images.captureScreen(); let color = images.pixel(img, 410, 615); // let color = images.pixel(img, 390, 615); if (colors.isSimilar(color, color_target, 5, "rgb+")) { sleep(20); img = images.captureScreen(); llk_running = true; // llk_auto_run = false; manual_run = false; // w.b_auto.setText("已关闭自动运行"); w.b_run.setText("自动运行中"); llk(); llk_running = false; w.b_run.setText("手动启动"); // sleep(300); } } else if (manual_run) { llk_running = true; manual_run = false; w.b_run.setText("手动运行中"); img = images.captureScreen(); llk(); llk_running = false; w.b_run.setText("手动启动"); } sleep(100); } function llk() { const map = { r: 8, //地图行数 c: 7, //地图列数 start_x: 0, //方块起始点x坐标 start_y: 808 //方块起始点y坐标 } map.start_x = map.c == 8 ? 48 : 132; const arrLen = { r: (map.r + 2), c: (map.c + 2) };//数组大小 const _region = [map.start_x, map.start_y, map.c * 168, map.r * 168]; //找图区间 const _threshold = 0.85; //找图精确度 const log_icons = ["⬛", "⬜", "🟥", "🟪", "🟨", "🟧", "🟦", "🟩", "🟫", "⚪", "🔴", "🟣", "🟡", "🟠", "🔵", "🟢", "🟤", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘", "🌑", "❤", "🧡", "💛", "💚", "💙", "💜", "🤎", "⛔", "🧊"]; //打印图形用图标 const d = [[-1, 0], [1, 0], [0, -1], [0, 1]]; //遍历四个方向 const path = [{ y1: -1, x1: -1, y2: -1, x2: -1 }]; //存储路径搜索结果:表示 (y1, x1) 与 (y2, x2) 可消除 const mp_bw = initArr(arrLen.r, arrLen.c, 0); //地图预处理结果,取值0/1表示是否存在方块 const mp = initArr(arrLen.r, arrLen.c, 0); //地图最终处理结果,0为空,相同的数字代表是同一种方块 const v = new Array(); //二维数组,以方块类型编号为下标,存储该类型方块的坐标 for (let k = 1; k <= 28; ++k) v[k] = new Array(); getMap(); //获取地图,将会写入 mp_bw, mp, v 数组, 其中 mp 数组是为了可视化展示路径用 if (check_map_clean()) return; // logMap(mp_bw); logMap(mp); check_edge(); //检查是否存在某种类型的方块个数是奇数个(多为提取地图出错导致) // mp_bw[1][1] = mp_bw[2][2] = mp_bw[2][4] = mp_bw[4][2] = 0; // logMap(mp_bw); // log(check_connection({ y: 1, x: 5 }, { y: 6, x: 3 })); // log(check_connection(v[2][0], v[2][1])); // exit(); let flag_success = false; //标记搜索路径是否成功 let date1 = new Date().getTime(); if (llk_no_dfs) no_backtrace_search(); else dfs(); let date2 = new Date().getTime(); log("搜索路径用时:" + (date2 - date1) + "ms"); /* ⛔⛔⛔⛔ no_backtrace_search()无回溯暴力遍历所有点组合,只要遇到能连的点就连, ⛔🟩🟩⛔ 适用于地图只有部分解(只能消除一部分)的情况, ⛔ ⛔ 可能无法解决如左图的情况。 ⛔🟪🟩⛔ bfs()同样是遍历所有点的组合,但遇到无解情况会回溯,直到成功为止, ⛔🟩🟪⛔ 适用于当前地图有完全解(能清空)的情况,否则会返回空解集 ⛔⛔⛔⛔ 左图情况可以找到正确路径。 */ // log(path); // exit(); click_path(30); // draw_path(); return; function click_path(speed) { // return; if (llk_no_dfs) { for (let k = 1; k < path.length; ++k) { press(getX(path[k].x1) + 50, getY(path[k].y1) + 50, 1); sleep(speed); // sleep(270); press(getX(path[k].x2) + 50, getY(path[k].y2) + 50, 1); sleep(speed); // sleep(470); } } else { for (let k = path.length - 1; k >= 1; --k) { press(getX(path[k].x1) + 50, getY(path[k].y1) + 50, 1); sleep(speed); // sleep(270); press(getX(path[k].x2) + 50, getY(path[k].y2) + 50, 1); sleep(speed); // sleep(470); } } } function draw_path() { logMap(mp); sleep(10); // for (let k = 1; k < path.length; ++k) { for (let k = path.length - 1; k >= 1; --k) { let logStr = "\n"; for (let i = 0; i < arrLen.r; ++i) { for (let j = 0; j < arrLen.c - 1; ++j) { if ((i == path[k].y1 && j == path[k].x1) || (i == path[k].y2 && j == path[k].x2)) logStr += "💎";//log_icons_c[mp[i][j]]; else logStr += log_icons[mp[i][j]]; } if ((i == path[k].y1 && (arrLen.c - 1) == path[k].x1) || (i == path[k].y2 && (arrLen.c - 1) == path[k].x2)) logStr += "💎"//log_icons_c[mp[i][arrLen.c - 1]]; else logStr += log_icons[mp[i][arrLen.c - 1]]; if (i != arrLen.r - 1) logStr += "\n"; } log(logStr); mp[path[k].y1][path[k].x1] = mp[path[k].y2][path[k].x2] = 0; sleep(10); } } function no_backtrace_search() { while (true) { // log("--------"); let flag_no_op = 1; for (let i = 1; i <= 28; ++i) { // log("dfs 第 " + i + " 种方块", difItem); for (let j = 0; j < v[i].length; ++j) { for (let k = j + 1; k < v[i].length; ++k) { if (v[i][j].vis || v[i][k].vis || check_ice(v[i][j]) || check_ice(v[i][k])) continue; if (check_connection(v[i][j], v[i][k])) { flag_no_op = 0; // click_block(v[i][j].x, v[i][j].y, v[i][k].x, v[i][k].y, 30); // log(" succ (" + v[i][j].y + ", " + v[i][j].x + ") - (" + v[i][k].y + ", " + v[i][k].x + ")"); path.push({ y1: v[i][j].y, x1: v[i][j].x, y2: v[i][k].y, x2: v[i][k].x }); mp_bw[v[i][j].y][v[i][j].x] = mp_bw[v[i][k].y][v[i][k].x] = 0; v[i][j].vis = v[i][k].vis = 1; let tx, ty; for (let m = 0; m < 4; ++m) { tx = v[i][j].x + d[m][0]; ty = v[i][j].y + d[m][1]; if (mp_bw[ty][tx] == 33) mp_bw[ty][tx] = 1; tx = v[i][k].x + d[m][0]; ty = v[i][k].y + d[m][1]; if (mp_bw[ty][tx] == 33) mp_bw[ty][tx] = 1; } } else { // logMap(mp_bw); // log(" **** [" + i + "][" + j + "] - [" + i + "][" + k + "] - " + check_connection(v[i][j], v[i][k])); // log(" fail (" + v[i][j].y + ", " + v[i][j].x + ") - (" + v[i][k].y + ", " + v[i][k].x + ")"); } } } } // log("--------"); if (flag_no_op) return; } } function check_ice(u) { return mp_bw[u.y][u.x] == 33; } function dfs() { if (check_map_clean()) { // logMap(mp_bw); log("dfs successed!"); flag_success = true; return; } // log("dfs check fail"); // 最坏情况 O() for (let i = 1; i <= 28; ++i) { // log("dfs 第 " + i + " 种方块,共", v[i].length); for (let j = 0; j < v[i].length; ++j) { for (let k = j + 1; k < v[i].length; ++k) { if (v[i][j].vis || v[i][k].vis || check_ice(v[i][j]) || check_ice(v[i][k])) continue; if (check_connection(v[i][j], v[i][k])) { // log(" ***suc (" + v[i][j].y + ", " + v[i][j].x + ") - (" + v[i][k].y + ", " + v[i][k].x + ") ***"); mp_bw[v[i][j].y][v[i][j].x] = mp_bw[v[i][k].y][v[i][k].x] = 0; v[i][j].vis = v[i][k].vis = 1; let bt = new Array(); // backtrace数组记录解冻操作 let tx, ty; for (let m = 0; m < 4; ++m) { tx = v[i][j].x + d[m][0]; ty = v[i][j].y + d[m][1]; if (mp_bw[ty][tx] == 33) { mp_bw[ty][tx] = 1; bt.push({ y: ty, x: tx }); } tx = v[i][k].x + d[m][0]; ty = v[i][k].y + d[m][1]; if (mp_bw[ty][tx] == 33) { mp_bw[ty][tx] = 1; bt.push({ y: ty, x: tx }); } } dfs(); if (flag_success) { path.push({ y1: v[i][j].y, x1: v[i][j].x, y2: v[i][k].y, x2: v[i][k].x }); return; } // log(" **回溯 👆") mp_bw[v[i][j].y][v[i][j].x] = mp_bw[v[i][k].y][v[i][k].x] = 1; for (let m = 0; m < bt.length; ++m) mp_bw[bt[m].y][bt[m].x] = 33; } else { // logMap(mp_bw); // log(" **** [" + i + "][" + j + "] - [" + i + "][" + k + "] - " + check_connection(v[i][j], v[i][k])); // log(" fail (" + v[i][j].y + ", " + v[i][j].x + ") - (" + v[i][k].y + ", " + v[i][k].x + ")"); } } } } // flag_success = true; // throw new Error("No solution"); } function check_connection(a, b) { // if (a.vis || b.vis) return false; let t = { x: 0, y: 0, dir: -1, turn: -1 }; let x, y, dir, turn; const q = [{ x: a.x, y: a.y, dir: -1, turn: -1 }]; const vis = new Array(arrLen.r); for (let k = 0; k < arrLen.r; k++) { vis[k] = new Array(arrLen.c); for (let j = 0; j < arrLen.c; j++) { vis[k][j] = new Array(4); vis[k][j][0] = vis[k][j][1] = vis[k][j][2] = vis[k][j][3] = 0x3f3f3f3f; } } // const vis = initArr(arrLen.r, arrLen.c, { 0: 0x3f3f3f3f, 1: 0x3f3f3f3f, 2: 0x3f3f3f3f, 3: 0x3f3f3f3f }); vis[a.y][a.x] = 1; while (q.length) { t = q.shift(); // log("****: " + t.y, t.x, t.dir, t.turn); for (let i = 0; i < 4; ++i) { x = t.x + d[i][0]; y = t.y + d[i][1]; dir = i; turn = t.turn + (t.dir != i); if (turn <= 2 && x >= 0 && y >= 0 && x < arrLen.c && y < arrLen.r) { // log(" **: " + y, x, dir, turn, "mp:", mp_bw[y][x], "vis:", vis[y][x]); if (y == b.y && x == b.x) return true; if (mp_bw[y][x] == 0 && vis[y][x][dir] > turn) { // log("push (" + y + ", " + x + ") d:" + dir + " turn:" + turn); vis[y][x][dir] = turn; q.push({ x: x, y: y, dir: dir, turn: turn }); } } } } return false; } function check_map_clean() { for (let i = 1; i <= map.r; ++i) for (let j = 1; j <= map.c; ++j) if (mp_bw[i][j] == 1 || mp_bw[i][j] == 33) return false; return true; } function getMap() { let date1 = new Date().getTime(); // let colorCorner = colors.parseColor("#f7f7f5"); let colorCorner2 = colors.parseColor("#f7f7f7"); let colorIce = colors.parseColor("#e5fcff"); // log(colorCorner, colorCorner2); // var file_catalog = "/sdcard/Samsung Flow/llkice1/"; // var recv = files.listDir(file_catalog, function (name) { // return name.endsWith(".png") && files.isFile(files.join(file_catalog, name)); // }); // let cnt = recv.length; // log("cnt1: ", cnt); // log("mp_bw start"); for (let i = 1; i <= map.r; ++i) { for (let j = 1; j <= map.c; ++j) { let color = images.pixel(img, getX(j) + 10, getY(i) + 10); // log("(" + i + ", " + j + ") :" + colors.toString(color).replace("#ff", "#")); if (colors.isSimilar(color, colorCorner2, 10, "rgb+")) { mp_bw[i][j] = 1; } } } if (check_map_clean()) return; // log("mp_bw done"); // log("cnt1: **", cnt); //线程1:寻找冰块 + 识别冰块类型 let find_img_thread1 = threads.start(function () { // log("ice start"); for (let i = 1; i <= map.r; ++i) { for (let j = 1; j <= map.c; ++j) { let color = images.pixel(img, getX(j) + 10, getY(i) + 10); if (colors.isSimilar(color, colorIce, 10, "rgb+")) { mp_bw[i][j] = 33; // let flag = true; // let imgIcon = images.clip(img, getX(j) + 10, getY(i) + 10, 148, 148); for (let k = 1; k <= 28; ++k) { if (images.findImage(img, imgIcons_ice[k], { region: [getX(j) + 10, getY(i) + 10, 148, 148], threshold: 0.95, level: 1 })) { v[k].push({ y: i, x: j, vis: 0 }); mp[i][j] = k; break; } } // if (flag) // images.save(imgIcon, "/sdcard/Samsung Flow/llkice1/" + (++cnt) + ".png", "png", 100); // imgIcon.recycle(); } } } log("ice done"); logMap(mp_bw); }); // let file_catalog2 = "/sdcard/Samsung Flow/llk1/"; // let recv2 = files.listDir(file_catalog2, function (name) { // return name.endsWith(".png") && files.isFile(files.join(file_catalog2, name)); // }); // let cnt2 = recv2.length; // log("cnt2: ", cnt2); // let imgMap = images.clip(img, map.start_x, map.start_y, map.c * 168, map.r * 168); // let idx = 1; function check_block_type(start, end) { for (let k = start; k <= end; ++k) { let points = images.matchTemplate(img, imgIcons[k], { region: _region, threshold: _threshold, max: 6 }).points; points.forEach(point => { let ii, jj; for (ii = map.c; ii > 0; --ii) if (point.x >= getX(ii)) break; for (jj = map.r; jj > 0; --jj) if (point.y >= getY(jj)) break; // log("(" + (ii + 1) + ", " + (jj + 1) + ") :" + k); if (mp_bw[jj][ii] == 1) { mp[jj][ii] = k; v[k].push({ y: jj, x: ii, vis: 0 }); } }); } } //线程2,3:和主线程分摊全图找图任务 let find_img_thread2 = threads.start(function () { // log("thread 2 start"); check_block_type(10, 19) log("thread 2 done"); find_img_thread2.interrupt(); }); let find_img_thread3 = threads.start(function () { // log("thread 3 start"); check_block_type(20, 28) log("thread 3 done"); find_img_thread3.interrupt(); }); // log("thread main start"); check_block_type(1, 9); log("thread main done"); while (find_img_thread2 && find_img_thread2.isAlive()) { sleep(30); } while (find_img_thread3 && find_img_thread3.isAlive()) { sleep(30); } log("**** all done!") //********* 旧版方法:遇到未识别的方块剪切处理后进行全图识别,难以并行处理 ********* // for (let i = 1; i <= map.r; ++i) { // for (let j = 1; j <= map.c; ++j) { // if (mp_bw[i][j] == 1 && 0 == mp[i][j]) { // // log("(" + (i + 1) + ", " + (j + 1) + ") :", 310 + 168 * j, 1154 + 168 * i, 148, 148); // let imgIcon = images.clip(img, getX(j) + 10, getY(i) + 10, 148, 148); // // images.save(imgIcon, "/sdcard/Samsung Flow/llk1/" + idx + ".png", "png", 100); // let points = images.matchTemplate(img, imgIcon, { // region: _region, // threshold: _threshold, // max: 6 // }).points; // // let flag = true; // // for (let k = 1; k <= cnt2; ++k) { // // imga = images.read("/sdcard/Samsung Flow/llk1/" + k + ".png"); // // if (images.findImage(imga, imgIcon)) { flag = false; break; } // // imga.recycle(); // // } // // if (flag) // // log("save ", cnt2); // // if (flag) // // images.save(imgIcon, "/sdcard/Samsung Flow/llk1/" + (++cnt2) + ".png", "png", 100); // imgIcon.recycle(); // // log(points); // v[idx] = new Array(); // points.forEach(point => { // let ii, jj; // for (ii = map.c; ii > 0; --ii) if (point.x >= getX(ii)) break; // for (jj = map.r; jj > 0; --jj) if (point.y >= getY(jj)) break; // // log("(" + (ii + 1) + ", " + (jj + 1) + ") :" + idx); // mp[jj][ii] = idx; // v[idx].push({ y: jj, x: ii, vis: 0 }); // }); // ++idx; // } // } // } // difItem = idx; difItem = 28; // imgMap.recycle(); // log("cnt2: **", cnt2); let points = images.matchTemplate(img, icon_block, { region: [map.start_x, map.start_y, map.c * 168, map.r * 168], threshold: 0.8 }).points; points.forEach(point => { let ii, jj; for (ii = map.c; ii > 0; --ii) if (point.x >= getX(ii)) break; for (jj = map.r; jj > 0; --jj) if (point.y >= getY(jj)) break; mp_bw[jj][ii] = mp[jj][ii] = 32; }); while (find_img_thread1 && find_img_thread1.isAlive()) { sleep(30); } let date2 = new Date().getTime(); log("地图处理用时:" + (date2 - date1) + "ms"); } function check_edge() { return; for (let i = 1; i <= 28; ++i) { log(v[i]); // if (v[i].length % 2) // throw new Error("number of points is odd at " + log_icons[i] + "(color " + i + " )"); } } function logMap(arr) { let logStr = "\n"; for (let i = 0; i < arrLen.r; ++i) { for (let j = 0; j < arrLen.c - 1; ++j) { // log(String(mp_bw[i][j])); logStr += log_icons[arr[i][j]]; } logStr += log_icons[arr[i][arrLen.c - 1]]; if (i != arrLen.r - 1) logStr += "\n"; } log(logStr); } function initArr(r, c, init) { let tArr = new Array(r); for (let k = 0; k < r; k++) { tArr[k] = new Array(c); for (let j = 0; j < c; j++) { tArr[k][j] = init; } } return tArr; } function getX(c) { return map.start_x + 168 * (c - 1); } function getY(r) { return map.start_y + 168 * (r - 1); } } function llk_old() { const mapSize = { r: 8, c: 8 }; //地图边长 // const mapSize = { r: 7, c: 5 }; //地图边长 // const mapStart = { x: 132, y: 808 }; //地图开始坐标 const mapStart = { x: mapSize.c == 8 ? 48 : 132, y: 808 }; //地图开始坐标 const arrLen = { r: (mapSize.r + 2), c: (mapSize.c + 2) };//数组大小 const _region = [mapStart.x, mapStart.y, mapSize.c * 168, mapSize.r * 168]; let difItem; // 方块种类数 const _threshold = 0.85; //找图精确度 const log_icons = ["⬛", "⬜", "🟥", "🟪", "🟨", "🟧", "🟦", "🟩", "🟫", "⚪", "🔴", "🟣", "🟡", "🟠", "🔵", "🟢", "🟤", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘", "🌑", "⛔", "🧊"]; //打印图形用图标 const log_icons_c = ["⚫", "⚪", "🔴", "🟣", "🟡", "🟠", "🔵", "🟢", "🟤", "⬜", "🟥", "🟪", "🟨", "🟧", "🟦", "🟩", "🟫", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘", "🌑", "⛔", "🧊"]; //打印图形用图标 let flag_success = false; //标记搜索路径是否成功 let icon_block = images.read("/sdcard/Samsung Flow/icon_block.png"); const mp_bw = initArr(arrLen.r, arrLen.c, 0); //地图预处理结果,取值0/1表示是否存在方块 const mp = initArr(arrLen.r, arrLen.c, 0); //地图最终处理结果,0为空,相同的数字代表是同一种方块 const v = new Array(); //二维数组,以方块类型编号为下标,存储该类型方块的坐标 const path = [{ y1: -1, x1: -1, y2: -1, x2: -1 }]; //存储运算结果:表示 (y1, x1) 与 (y2, x2) 可消除 getMap(); //获取地图,将会写入 mp_bw, mp, v 数组 if (check_map_clean()) return; // logMap(mp_bw); logMap(mp); // check_edge(); //检查是否存在某种类型的方块个数是奇数个(多为提取地图出错导致) // mp_bw[1][1] = mp_bw[2][2] = mp_bw[2][4] = mp_bw[4][2] = 0; // logMap(mp_bw); // log(judge_connection({ y: 1, x: 5 }, { y: 6, x: 3 })); // log(judge_connection(v[2][0], v[2][1])); // exit(); let date1 = new Date().getTime(); if (llk_no_dfs) no_backtrace_search(); else dfs(); let date2 = new Date().getTime(); toastLog("搜索路径用时:" + (date2 - date1) + "ms"); // log(path); // exit(); for (let k = 1; k < path.length; ++k) click_block(path[k].x1, path[k].y1, path[k].x2, path[k].y2, 30); // draw_path(); icon_block.recycle(); return; function click_block(x1, y1, x2, y2, speed) { // for (let k = 1; k < path.length; ++k) { // for (let k = path.length - 1; k >= 1; --k) { press(getX(x1) + 50, getY(y1) + 50, 1); sleep(speed); // sleep(270); press(getX(x2) + 50, getY(y2) + 50, 1); sleep(speed); // sleep(470); // } } function draw_path() { logMap(mp); sleep(10); for (let k = 1; k < path.length; ++k) { // for (let k = path.length - 1; k >= 1; --k) { let logStr = "\n"; for (let i = 0; i < arrLen.r; ++i) { for (let j = 0; j < arrLen.c - 1; ++j) { if ((i == path[k].y1 && j == path[k].x1) || (i == path[k].y2 && j == path[k].x2)) logStr += "💎";//log_icons_c[mp[i][j]]; else logStr += log_icons[mp[i][j]]; } if ((i == path[k].y1 && (arrLen.c - 1) == path[k].x1) || (i == path[k].y2 && (arrLen.c - 1) == path[k].x2)) logStr += "💎"//log_icons_c[mp[i][arrLen.c - 1]]; else logStr += log_icons[mp[i][arrLen.c - 1]]; if (i != arrLen.r - 1) logStr += "\n"; } log(logStr); mp[path[k].y1][path[k].x1] = mp[path[k].y2][path[k].x2] = 0; sleep(10); } } function no_backtrace_search() { while (true) { let flag_no_op = 1; for (let i = 1; i < difItem; ++i) { // log("dfs 第 " + i + " 种方块", difItem); for (let j = 0; j < v[i].length; ++j) { for (let k = j + 1; k < v[i].length; ++k) { if (v[i][j].vis || v[i][k].vis) continue; if (judge_connection(v[i][j], v[i][k])) { flag_no_op = 0; // click_block(v[i][j].x, v[i][j].y, v[i][k].x, v[i][k].y, 30); // log(" succ (" + v[i][j].y + ", " + v[i][j].x + ") - (" + v[i][k].y + ", " + v[i][k].x + ")"); path.push({ y1: v[i][j].y, x1: v[i][j].x, y2: v[i][k].y, x2: v[i][k].x }); mp_bw[v[i][j].y][v[i][j].x] = mp_bw[v[i][k].y][v[i][k].x] = 0; v[i][j].vis = v[i][k].vis = 1; } else { // logMap(mp_bw); // log(" **** [" + i + "][" + j + "] - [" + i + "][" + k + "] - " + judge_connection(v[i][j], v[i][k])); // log(" fail (" + v[i][j].y + ", " + v[i][j].x + ") - (" + v[i][k].y + ", " + v[i][k].x + ")"); } } } } if (flag_no_op) return; } } function dfs() { if (check_map_clean()) { // logMap(mp_bw); log("dfs successed!"); flag_success = true; return; } // log("dfs check fail"); for (let i = 1; i < difItem; ++i) { // log("dfs 第 " + i + " 种方块", difItem); for (let j = 0; j < v[i].length; ++j) { for (let k = j + 1; k < v[i].length; ++k) { if (v[i][j].vis || v[i][k].vis) continue; if (judge_connection(v[i][j], v[i][k])) { log(" succ (" + v[i][j].y + ", " + v[i][j].x + ") - (" + v[i][k].y + ", " + v[i][k].x + ")"); mp_bw[v[i][j].y][v[i][j].x] = mp_bw[v[i][k].y][v[i][k].x] = 0; v[i][j].vis = v[i][k].vis = 1; // return; dfs(); if (flag_success) { path.push({ y1: v[i][j].y, x1: v[i][j].x, y2: v[i][k].y, x2: v[i][k].x }); return; } log(" **回溯 👆") mp_bw[v[i][j].y][v[i][j].x] = mp_bw[v[i][k].y][v[i][k].x] = 1; } else { // logMap(mp_bw); // log(" **** [" + i + "][" + j + "] - [" + i + "][" + k + "] - " + judge_connection(v[i][j], v[i][k])); log(" fail (" + v[i][j].y + ", " + v[i][j].x + ") - (" + v[i][k].y + ", " + v[i][k].x + ")"); } } } } // throw new Error("No solution"); } function judge_connection(a, b) { // if (a.vis || b.vis) return false; let t = { x: 0, y: 0, dir: -1, turn: -1 }; let x, y, dir, turn; const q = [{ x: a.x, y: a.y, dir: -1, turn: -1 }]; const vis = new Array(arrLen.r); for (let k = 0; k < arrLen.r; k++) { vis[k] = new Array(arrLen.c); for (let j = 0; j < arrLen.c; j++) { vis[k][j] = new Array(4); vis[k][j][0] = vis[k][j][1] = vis[k][j][2] = vis[k][j][3] = 0x3f3f3f3f; } } // const vis = initArr(arrLen.r, arrLen.c, { 0: 0x3f3f3f3f, 1: 0x3f3f3f3f, 2: 0x3f3f3f3f, 3: 0x3f3f3f3f }); const d = [[-1, 0], [1, 0], [0, -1], [0, 1]]; vis[a.y][a.x] = 1; while (q.length) { t = q.shift(); // log("****: " + t.y, t.x, t.dir, t.turn); for (let i = 0; i < 4; ++i) { x = t.x + d[i][0]; y = t.y + d[i][1]; dir = i; turn = t.turn + (t.dir != i); if (turn <= 2 && x >= 0 && y >= 0 && x < arrLen.c && y < arrLen.r) { // log(" **: " + y, x, dir, turn, "mp:", mp_bw[y][x], "vis:", vis[y][x]); if (y == b.y && x == b.x) return true; if (mp_bw[y][x] == 0 && vis[y][x][dir] > turn) { // log("push (" + y + ", " + x + ") d:" + dir + " turn:" + turn); vis[y][x][dir] = turn; q.push({ x: x, y: y, dir: dir, turn: turn }); } } } } return false; } function check_map_clean() { for (let i = 1; i <= mapSize.r; ++i) for (let j = 1; j <= mapSize.c; ++j) if (mp_bw[i][j] == 1) return false; return true; } function getMap() { let date1 = new Date().getTime(); // let colorCorner = colors.parseColor("#f7f7f5"); let colorCorner2 = colors.parseColor("#f7f7f7"); let colorIce = colors.parseColor("#e5fcff"); // log(colorCorner, colorCorner2); for (let i = 1; i <= mapSize.r; ++i) { for (let j = 1; j <= mapSize.c; ++j) { let color = images.pixel(img, getX(j) + 10, getY(i) + 10); // log("(" + i + ", " + j + ") :" + colors.toString(color).replace("#ff", "#")); if (colors.isSimilar(color, colorCorner2, 10, "rgb+")) { mp_bw[i][j] = 1; } else if (colors.isSimilar(color, colorIce, 10, "rgb+")) { mp_bw[i][j] = mp[i][j] = 26; } } } // let imgMap = images.clip(img, mapStart.x, mapStart.y, mapSize.c * 168, mapSize.r * 168); let idx = 1; for (let i = 1; i <= mapSize.r; ++i) { for (let j = 1; j <= mapSize.c; ++j) { if (mp_bw[i][j] == 1 && 0 == mp[i][j]) { // log("(" + (i + 1) + ", " + (j + 1) + ") :", 310 + 168 * j, 1154 + 168 * i, 148, 148); let imgIcon = images.clip(img, getX(j) + 10, getY(i) + 10, 148, 148); // images.save(imgIcon, "/sdcard/Samsung Flow/llk2.png", "png", 100); let points = images.matchTemplate(img, imgIcon, { region: _region, threshold: _threshold, max: 6 }).points; imgIcon.recycle(); // log(points); v[idx] = new Array(); points.forEach(point => { let ii, jj; for (ii = mapSize.c; ii > 0; --ii) if (point.x >= getX(ii)) break; for (jj = mapSize.r; jj > 0; --jj) if (point.y >= getY(jj)) break; // log("(" + (ii + 1) + ", " + (jj + 1) + ") :" + idx); mp[jj][ii] = idx; v[idx].push({ y: jj, x: ii, vis: 0 }); }); ++idx; } } } difItem = idx; // imgMap.recycle(); let points = images.matchTemplate(img, icon_block, { region: [mapStart.x, mapStart.y, mapSize.c * 168, mapSize.r * 168], threshold: 0.8 }).points; points.forEach(point => { let ii, jj; for (ii = mapSize.c; ii > 0; --ii) if (point.x >= getX(ii)) break; for (jj = mapSize.r; jj > 0; --jj) if (point.y >= getY(jj)) break; mp_bw[jj][ii] = mp[jj][ii] = 25; }); let date2 = new Date().getTime(); log("地图处理用时:" + (date2 - date1) + "ms"); } function check_edge() { return; for (let i = 1; i < difItem; ++i) { // log(v[i]); if (v[i].length % 2) throw new Error("number of points is odd at " + log_icons[i] + "(color " + i + " )"); } } function logMap(arr) { // 🟥🟧🟨🟩🟦🟪🟫⬛⬜ 🔴🟠🟡🟢🔵🟣🟤⚫⚪ let logStr = "\n"; for (let i = 0; i < arrLen.r; ++i) { for (let j = 0; j < arrLen.c - 1; ++j) { // log(String(mp_bw[i][j])); logStr += log_icons[arr[i][j]]; } logStr += log_icons[arr[i][arrLen.c - 1]]; if (i != arrLen.r - 1) logStr += "\n"; } log(logStr); } function initArr(r, c, init) { let tArr = new Array(r); for (let k = 0; k < r; k++) { tArr[k] = new Array(c); for (let j = 0; j < c; j++) { tArr[k][j] = init; } } return tArr; } function getX(c) { return mapStart.x + 168 * (c - 1); } function getY(r) { return mapStart.y + 168 * (r - 1); } } function close_llk() { var ThisEngine = engines.myEngine(); var RunningNow = engines.all(); if (RunningNow.length > 1) { for (var i = 0; i < RunningNow.length; i++) { if (RunningNow[i].toString() != ThisEngine.toString() && RunningNow[i].toString().indexOf("连连看") != -1) { log("停止脚本", RunningNow[i].toString()); RunningNow[i].forceStop(); } } } // toast("已关闭所有脚本"); }
东北日出西边雨 道是无情却有情