├── html ├── favicon.ico ├── sheep_map │ ├── images │ │ ├── 0.png │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ ├── 9.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 14.png │ │ ├── 15.png │ │ ├── 16.png │ │ ├── pre.png │ │ ├── mask │ │ │ ├── 0.png │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ ├── 8.png │ │ │ ├── 9.png │ │ │ ├── 10.png │ │ │ ├── 11.png │ │ │ ├── 12.png │ │ │ ├── 13.png │ │ │ ├── 14.png │ │ │ ├── 15.png │ │ │ └── 16.png │ │ ├── next.png │ │ └── side.png │ ├── main.css │ ├── index.php │ ├── map_data.php │ ├── index.html │ └── map_data.js └── index.php ├── requirements.txt ├── mitmweb_ylgy.sh ├── item ├── __pycache__ │ ├── Card.cpython-39.pyc │ ├── CardPosition.cpython-39.pyc │ └── ResidualPool.cpython-39.pyc ├── ResidualPool.py ├── Card.py └── CardPosition.py ├── 关卡地图数据库文件 ├── 20221022-2204-20221024-1755.db └── 20221025-0417-20221026-1451.db ├── hepler ├── __pycache__ │ └── FileHelper.cpython-39.pyc └── FileHelper.py ├── .gitignore ├── shuffle.js ├── readme.md ├── autoSolve.py ├── sheep_manual.py ├── business └── SheepSolver.py └── sheep.py /html/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/favicon.ico -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | func_timeout==4.3.5 2 | mitmproxy==8.1.0 3 | PyExecJS==1.5.1 4 | requests==2.26.0 5 | -------------------------------------------------------------------------------- /html/sheep_map/images/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/0.png -------------------------------------------------------------------------------- /html/sheep_map/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/1.png -------------------------------------------------------------------------------- /html/sheep_map/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/2.png -------------------------------------------------------------------------------- /html/sheep_map/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/3.png -------------------------------------------------------------------------------- /html/sheep_map/images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/4.png -------------------------------------------------------------------------------- /html/sheep_map/images/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/5.png -------------------------------------------------------------------------------- /html/sheep_map/images/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/6.png -------------------------------------------------------------------------------- /html/sheep_map/images/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/7.png -------------------------------------------------------------------------------- /html/sheep_map/images/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/8.png -------------------------------------------------------------------------------- /html/sheep_map/images/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/9.png -------------------------------------------------------------------------------- /html/sheep_map/images/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/10.png -------------------------------------------------------------------------------- /html/sheep_map/images/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/11.png -------------------------------------------------------------------------------- /html/sheep_map/images/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/12.png -------------------------------------------------------------------------------- /html/sheep_map/images/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/13.png -------------------------------------------------------------------------------- /html/sheep_map/images/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/14.png -------------------------------------------------------------------------------- /html/sheep_map/images/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/15.png -------------------------------------------------------------------------------- /html/sheep_map/images/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/16.png -------------------------------------------------------------------------------- /html/sheep_map/images/pre.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/pre.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/0.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/1.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/2.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/3.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/4.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/5.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/6.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/7.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/8.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/9.png -------------------------------------------------------------------------------- /html/sheep_map/images/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/next.png -------------------------------------------------------------------------------- /html/sheep_map/images/side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/side.png -------------------------------------------------------------------------------- /mitmweb_ylgy.sh: -------------------------------------------------------------------------------- 1 | /usr/bin/mitmweb -p 9998 -s sheep.py --web-port 9999 --web-iface 0.0.0.0 --set block_global=false 2 | -------------------------------------------------------------------------------- /html/sheep_map/images/mask/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/10.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/11.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/12.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/13.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/14.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/15.png -------------------------------------------------------------------------------- /html/sheep_map/images/mask/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/html/sheep_map/images/mask/16.png -------------------------------------------------------------------------------- /item/__pycache__/Card.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/item/__pycache__/Card.cpython-39.pyc -------------------------------------------------------------------------------- /关卡地图数据库文件/20221022-2204-20221024-1755.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/关卡地图数据库文件/20221022-2204-20221024-1755.db -------------------------------------------------------------------------------- /关卡地图数据库文件/20221025-0417-20221026-1451.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/关卡地图数据库文件/20221025-0417-20221026-1451.db -------------------------------------------------------------------------------- /hepler/__pycache__/FileHelper.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/hepler/__pycache__/FileHelper.cpython-39.pyc -------------------------------------------------------------------------------- /item/__pycache__/CardPosition.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/item/__pycache__/CardPosition.cpython-39.pyc -------------------------------------------------------------------------------- /item/__pycache__/ResidualPool.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longhuan1999/sheep/HEAD/item/__pycache__/ResidualPool.cpython-39.pyc -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .idea/ 3 | node_modules/ 4 | *.json 5 | !config.json 6 | test.py 7 | __pycache__/ 8 | business/__pycache__/ 9 | html/sheep_map/test.html 10 | html/test.html 11 | html/sheep_maps.db 12 | html/*.py 13 | -------------------------------------------------------------------------------- /hepler/FileHelper.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os.path 3 | 4 | 5 | class FileHelper(object): 6 | def read_json_data(self, file_path): 7 | file_content = self.read_file_content(file_path) or "null" 8 | return json.loads(file_content) 9 | 10 | @staticmethod 11 | def read_file_content(file_path): 12 | try: 13 | if os.path.exists(file_path): 14 | reader = open(file_path, "r") 15 | content = reader.read() 16 | reader.close() 17 | return content 18 | else: 19 | return None 20 | except Exception as e: 21 | return None 22 | -------------------------------------------------------------------------------- /item/ResidualPool.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | class ResidualPool(object): 5 | def __init__(self): 6 | # 当前操作池有多少张卡牌 7 | self._pool_count = 0 8 | # 当前操作池可容纳的最大牌数 9 | self._pool_limit = 7 10 | # 当前操作池帕牌类别及数量 11 | self._pool_card = {} 12 | 13 | def is_pool_full(self): 14 | return len(self._pool_card.keys()) >= 6 or self._pool_count >= self._pool_limit 15 | 16 | def show_pool_state(self): 17 | return "count: {}, detail: {}".format(self._pool_count, json.dumps(self._pool_card)) 18 | 19 | def pick_card(self, card_detail): 20 | self._pool_count += 1 21 | card_type = card_detail.get_type() 22 | if card_type in self._pool_card: 23 | self._pool_card[card_type] += 1 24 | else: 25 | self._pool_card[card_type] = 1 26 | self._make_card_disappear(card_type) 27 | 28 | def recover_card(self, card_detail): 29 | card_type = card_detail.get_type() 30 | if card_type in self._pool_card: 31 | if self._pool_card[card_type] == 1: 32 | self._pool_card.pop(card_type) 33 | else: 34 | self._pool_card[card_type] -= 1 35 | self._pool_count -= 1 36 | else: 37 | self._pool_card[card_type] = 2 38 | self._pool_count += 2 39 | 40 | def _make_card_disappear(self, card_type): 41 | if self._pool_card[card_type] == 3: 42 | self._pool_count -= 3 43 | self._pool_card.pop(card_type) 44 | -------------------------------------------------------------------------------- /html/sheep_map/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background-color: #000; 4 | color: #fff; 5 | font-family: Monospace; 6 | font-size: 13px; 7 | line-height: 24px; 8 | overscroll-behavior: none; 9 | } 10 | 11 | a { 12 | color: #ff0; 13 | text-decoration: none; 14 | } 15 | 16 | a:hover { 17 | text-decoration: underline; 18 | } 19 | 20 | button { 21 | cursor: pointer; 22 | text-transform: uppercase; 23 | } 24 | 25 | #info { 26 | position: absolute; 27 | top: 0px; 28 | width: 100%; 29 | padding: 10px; 30 | box-sizing: border-box; 31 | text-align: center; 32 | -moz-user-select: none; 33 | -webkit-user-select: none; 34 | -ms-user-select: none; 35 | user-select: none; 36 | pointer-events: none; 37 | z-index: 1; /* TODO Solve this in HTML */ 38 | } 39 | 40 | a, button, input, select { 41 | pointer-events: auto; 42 | } 43 | 44 | .lil-gui { 45 | z-index: 2 !important; /* TODO Solve this in HTML */ 46 | } 47 | 48 | @media all and ( max-width: 640px ) { 49 | .lil-gui.root { 50 | right: auto; 51 | top: auto; 52 | max-height: 50%; 53 | max-width: 80%; 54 | bottom: 0; 55 | left: 0; 56 | } 57 | } 58 | 59 | #overlay { 60 | position: absolute; 61 | font-size: 16px; 62 | z-index: 2; 63 | top: 0; 64 | left: 0; 65 | width: 100%; 66 | height: 100%; 67 | display: flex; 68 | align-items: center; 69 | justify-content: center; 70 | flex-direction: column; 71 | background: rgba(0,0,0,0.7); 72 | } 73 | 74 | #overlay button { 75 | background: transparent; 76 | border: 0; 77 | border: 1px solid rgb(255, 255, 255); 78 | border-radius: 4px; 79 | color: #ffffff; 80 | padding: 12px 18px; 81 | text-transform: uppercase; 82 | cursor: pointer; 83 | } 84 | 85 | #notSupported { 86 | width: 50%; 87 | margin: auto; 88 | background-color: #f00; 89 | margin-top: 20px; 90 | padding: 10px; 91 | } 92 | -------------------------------------------------------------------------------- /item/Card.py: -------------------------------------------------------------------------------- 1 | class Card(object): 2 | def __init__(self, origin_data): 3 | self._origin_data = origin_data 4 | self._parent_note = set() 5 | self._children_node = set() 6 | 7 | def get_type(self): 8 | return self._origin_data["type"] 9 | 10 | def clac_area(self): 11 | width = self._origin_data["max_x"] - self._origin_data["min_x"] 12 | height = self._origin_data["max_y"] - self._origin_data["min_y"] 13 | return width * height 14 | 15 | def get_position(self): 16 | return [self._origin_data["min_x"], self._origin_data["min_y"], 17 | self._origin_data["max_x"], self._origin_data["max_y"]] 18 | 19 | def clac_iou(self, card): 20 | current_position = self.get_position() 21 | other_position = card.get_position() 22 | min_x = max(current_position[0], other_position[0]) 23 | min_y = max(current_position[1], other_position[1]) 24 | max_x = min(current_position[2], other_position[2]) 25 | max_y = min(current_position[3], other_position[3]) 26 | overlap_area = max(0, max_x - min_x) * max(0, max_y - min_y) 27 | current_area = self.clac_area() 28 | other_area = card.clac_area() 29 | return overlap_area / (current_area + other_area - overlap_area) 30 | 31 | def has_parent(self): 32 | return len(self._parent_note) > 0 33 | 34 | def get_children_set(self): 35 | return self._children_node 36 | 37 | def add_parent(self, card_index): 38 | self._parent_note.add(card_index) 39 | 40 | def recover_parent(self, card_index): 41 | self._parent_note.remove(card_index) 42 | 43 | def add_children(self, card_index): 44 | self._children_node.add(card_index) 45 | 46 | def recover_children(self, card_index): 47 | self._children_node.remove(card_index) 48 | -------------------------------------------------------------------------------- /shuffle.js: -------------------------------------------------------------------------------- 1 | 2 | // 生成随机数的类 3 | var XorShift = function() { 4 | function t() {} 5 | return Object.defineProperty(t, "instance", { 6 | get: function() { 7 | return this._instance || (this._instance = new t()), this._instance; 8 | }, 9 | enumerable: !1, 10 | configurable: !0 11 | }), t.prototype.setSeed = function(t) { 12 | if (!Array.isArray(t) || 4 !== t.length) throw new TypeError("seed must be an array with 4 numbers"); 13 | this._state0U = 0 | t[0], this._state0L = 0 | t[1], this._state1U = 0 | t[2], this._state1L = 0 | t[3]; 14 | }, t.prototype.randomint = function() { 15 | var t = this._state0U, e = this._state0L, o = this._state1U, n = this._state1L, i = (n >>> 0) + (e >>> 0), a = o + t + (i / 2 >>> 31) >>> 0, r = i >>> 0; 16 | this._state0U = o, this._state0L = n; 17 | var c = 0, s = 0; 18 | return c = (t ^= c = t << 23 | (-512 & e) >>> 9) ^ o, s = (e ^= s = e << 23) ^ n, 19 | c ^= t >>> 18, s ^= e >>> 18 | (262143 & t) << 14, c ^= o >>> 5, s ^= n >>> 5 | (31 & o) << 27, 20 | this._state1U = c, this._state1L = s, [ a, r ]; 21 | }, t.prototype.random = function() { 22 | var t = this.randomint(); 23 | return 2.3283064365386963e-10 * t[0] + 2.220446049250313e-16 * (t[1] >>> 12); 24 | }, t._instance = null, t; 25 | }(); 26 | 27 | // 打乱数组的方法 28 | function shuffle(array, seed=null) { 29 | var xorshift = XorShift.instance; 30 | if (seed != null) { 31 | // 设置随机种子 32 | xorshift.setSeed(seed); 33 | // 先获取一次随机值 34 | xorshift.random(); 35 | } 36 | // 数组下标从后往前遍历 37 | for (var i = array.length - 1; i >= 0; i--) { 38 | // 获取0到1之间的随机值 39 | var random = xorshift.random(); 40 | // 计算出随机的下标 41 | var j = Math.floor(random * (i + 1)); 42 | // 交换两个下标 43 | var temp = array[j]; 44 | array[j] = array[i]; 45 | array[i] = temp; 46 | } 47 | // 将数组反序排列 48 | array.reverse(); 49 | return array; 50 | } 51 | -------------------------------------------------------------------------------- /item/CardPosition.py: -------------------------------------------------------------------------------- 1 | class CardPosition(object): 2 | def __init__(self): 3 | # 以序号注册所有卡牌数据 4 | self._origin_data = {} 5 | # 以序号注册可操作卡牌数据 6 | self._head_data = {} 7 | # 当前登记的序号 8 | self._card_count = 0 9 | 10 | def append_level_card(self, card_list): 11 | start_index = len(self._origin_data) + 1 12 | self._append_origin_data(card_list) 13 | end_index = len(self._origin_data) + 1 14 | new_card_data = {key: self._origin_data[key] for key in range(start_index, end_index)} 15 | self._handle_overlap_data(new_card_data) 16 | 17 | def generate_head_data(self): 18 | for key_old, card_old in self._origin_data.items(): 19 | if not card_old.has_parent(): 20 | self._head_data[key_old] = card_old 21 | 22 | def get_head_description(self): 23 | return "-".join([str(item) for item in sorted(self._head_data.keys())]) 24 | 25 | def get_card_detail(self, card_index): 26 | return self._origin_data[card_index] 27 | 28 | def pick_card(self, card_index): 29 | self._head_data.pop(card_index) 30 | children_set = self._origin_data[card_index].get_children_set() 31 | for children_key in children_set: 32 | children_item = self._origin_data[children_key] 33 | children_item.recover_parent(card_index) 34 | if not children_item.has_parent(): 35 | self._head_data[children_key] = children_item 36 | 37 | def recover_card(self, card_index): 38 | card_detail = self._origin_data[card_index] 39 | self._head_data[card_index] = card_detail 40 | children_set = card_detail.get_children_set() 41 | for children_key in children_set: 42 | children_item = self._origin_data[children_key] 43 | children_item.add_parent(card_index) 44 | if children_key in self._head_data: 45 | self._head_data.pop(children_key) 46 | 47 | def get_head_key_list(self): 48 | return list(self._head_data.keys()) 49 | 50 | def is_head_data_empty(self): 51 | return len(self._head_data.keys()) == 0 52 | 53 | def _append_origin_data(self, card_list): 54 | for card_item in card_list: 55 | self._card_count += 1 56 | self._origin_data[self._card_count] = card_item 57 | 58 | def _handle_overlap_data(self, card_dict): 59 | old_card_dict = {key: self._origin_data[key] for key in self._origin_data.keys() if key not in card_dict} 60 | for key_new, card_new in card_dict.items(): 61 | for key_old, card_old in old_card_dict.items(): 62 | if card_new.clac_iou(card_old) > 0: 63 | card_new.add_children(key_old) 64 | card_old.add_parent(key_new) -------------------------------------------------------------------------------- /html/sheep_map/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 羊了个羊3D地图 5 | 6 | 7 | 8 | 40 | 41 | 49 | 50 | 51 | 52 |
53 | 【撤销移除】 54 | 55 | 56 |
57 | 58 | 59 | 60 | 0){//判断是否有Get参数 62 | if(isset($_GET["id"])){//判断所需要的参数是否存在,isset用来检测变量是否设置,返回true or false 63 | $id = $_GET["id"];//存在 64 | echo "\n"; 65 | } else { 66 | echo "\n"; 67 | } 68 | } else { 69 | echo "\n"; 70 | } 71 | ?> 72 | 73 | -------------------------------------------------------------------------------- /html/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 羊了个羊3D地图 5 | 6 | 7 | 8 | open('sheep_maps.db'); 33 | } 34 | } 35 | $db = new MyDB(); 36 | if(!$db){ 37 | echo "\n\t"; 38 | //echo $db->lastErrorMsg(); 39 | } else { 40 | echo "\n\t"; 41 | //echo "成功创建或打开数据文件\n"; 42 | } 43 | 44 | $sql1 =<<exec($sql1); 54 | if(!$ret1){ 55 | echo "\n\t"; 56 | //echo $db->lastErrorMsg(); 57 | } else { 58 | echo "\n\t"; 59 | //echo "成功创建或检查数据表\n"; 60 | } 61 | 62 | $req_json_str = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents("php://input"); 63 | //echo gettype($req_json_str); 64 | if(strpos($req_json_str, "levelData") !== false && strpos($req_json_str, "layers") !== false){ 65 | $ret4 = $db->query("SELECT ID FROM MAPS WHERE MAP_INFO = '$req_json_str'"); 66 | while($row = $ret4->fetchArray()){ 67 | $ID = $row["ID"]; 68 | } 69 | if($ID == null){ 70 | $sql2 = "INSERT INTO MAPS (MAP_INFO,IP,DATA_TIME) VALUES ('$req_json_str','$ip','$data_time')"; 71 | $ret2 = $db->exec($sql2); 72 | $ret3 = $db->query("SELECT MAX(ID) from MAPS"); 73 | if(!$ret2){ 74 | echo "\n\t"; 75 | //echo $db->lastErrorMsg(); 76 | } else { 77 | echo "\n\t"; 78 | //echo "成功插入数据\n"; 79 | while($row = $ret3->fetchArray() ){ 80 | $ID = $row["MAX(ID)"]; 81 | } 82 | } 83 | } 84 | } 85 | if($ID == null){ 86 | echo "访问示例3D地图\n\t"; 87 | echo "\n"; 88 | } else { 89 | echo "访问当前关卡3D地图\n\t"; 90 | echo "\n"; 91 | } 92 | $db->close(); 93 | ?> 94 | 95 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | > 关卡数据中的解答步骤字段名 "oprations" 已纠正为 "operations",请使用最新项目!
2 | [https://ylgy.endless084.top](https://ylgy.endless084.top) 做了兼容,提交的关卡数据中的解答步骤字段名还是 "oprations" 也能查看3D地图解答,但会有弹窗提示。 3 | 4 | > **求解算法来自 [NB-Dragon/SheepSolver](https://github.com/NB-Dragon/SheepSolver) ,5分钟内求解成功率暂时不高
5 | 经过一些调整和测试,四种模式同时尝试(已添加到抓包脚本中)有一定概率在短时间内得到解,甚至是多解,建议超过60~90秒就放弃重试!** 6 | ![image](https://user-images.githubusercontent.com/43313501/195137874-747484b7-4f49-48f0-b95f-65bfb387d560.png) 7 | 8 | 9 | ### 一、运行环境 10 | 11 | #### 1、Python3 12 | 13 | 推荐使用`Anaconda`进行安装,官网:[https://www.anaconda.com](https://www.anaconda.com/) 。 14 | 15 | #### 2、Node.js 16 | 17 | 用来防止`pyExecJs`库报错,也可以用来安装网页服务器,官网:[https://nodejs.org/zh-cn/download](https://nodejs.org/zh-cn/download) 。 18 | 19 | #### 3、Git 20 | 21 | Windows系统需要手动安装`git`,官网:[https://gitforwindows.org](https://gitforwindows.org) 。 22 | 23 | #### 4、Web服务器(任选一种) 24 | 25 | (一)使用`nginx`或`apache`等 Web服务搭配`php`环境以及`sqlite`数据库,具体可以百度 26 | 27 | 搭建好 Web服务环境后需要将`autoSolve.py`中`post_map_data`函数中的服务器地址换成你自己的。 28 | 29 | > **也可以不换直接用我写好的的也行:[https://ylgy.endless084.top](https://ylgy.endless084.top)** 30 | 31 | 本人因为想将3d地图放在 vps 上,所以使用的是 nginx 虚拟主机(域名)搭配 php 环境,mitmproxy 抓包放在了本地电脑上。 32 | 33 | (二)使用`Node.js` 34 | 35 | 安装网页服务器: 36 | ``` 37 | npm install -g live-server 38 | ``` 39 | 40 | 启动网页服务器,在本项目目录下分别执行以下命令启动网页服务器: 41 | ``` 42 | cd html/sheep_map 43 | # Windows: cd html\sheep_map 44 | live-server 45 | ``` 46 | 47 | 执行后会浏览器会自动打开3d地图网页。算出解后刷新网页,就可以看到最新的游戏3d地图了。 48 | 49 | --- 50 | 51 | ### 二、克隆本项目 52 | 53 | 使用以下命令将本项目克隆到本地,并进入项目目录: 54 | ``` 55 | git clone https://github.com/longhuan1999/sheep.git 56 | cd sheep 57 | ``` 58 | 59 | > MacOS系统使用终端执行,Windows系统使用Powershell。 60 | 61 | --- 62 | 63 | ### 三、mitmproxy的配置 64 | 65 | [mitmproxy](https://github.com/mitmproxy/mitmproxy)是一个开源的抓包工具,可以加载自己写的Python代码进行数据处理。 66 | 67 | 目测不支持国外vps抓包,游戏会检测ip的地理位置。 68 | 69 | #### 1、安装 70 | 71 | 安装Python3后,执行以下命令安装mitmproxy、pyExecJs和requests: 72 | ``` 73 | pip install mitmproxy pyExecJs requests 74 | ``` 75 | 76 | #### 2、启动 77 | 78 | 新开一个终端,切换到本项目目录,执行以下命令启动抓包工具并加载`sheep.py`插件: 79 | ``` 80 | mitmweb -p 6666 -s sheep.py 81 | # 默认代理端口是8080,默认web端口是8081,如果出现端口占用情况,参考以下参数 82 | # -p [代理端口] 83 | # --web-port [web端口] 84 | # --web-iface 或 --web-host [web主机名] 85 | # 示例: 86 | mitmweb -p 9998 -s sheep.py --web-port 9999 --web-iface 0.0.0.0 87 | mitmweb -p 9998 -s sheep.py --web-port 9999 --web-host 0.0.0.0 88 | ``` 89 | 90 | 执行后浏览器会弹出一个抓包的网页界面。 91 | 92 | 接下来使用手机连接电脑的ip以及使用指定端口端口作为代理,就可以抓包了。 93 | 94 | >设置代理可以参考视频教程 [【4分钟教会你Charles抓包设置抓取电脑HTTPS以及IOS手机抓包-哔哩哔哩】](https://b23.tv/S0d8iYa) 两分钟的地方。 95 | 96 | #### 3、安装证书 97 | 98 | 使用手机浏览器访问 [http://mitm.it](http://mitm.it) 安装`mitmproxy`的证书。 99 | 100 | 苹果手机需要在 设置 - 通用 - 关于本机 - 证书信任设置 里信任证书。 101 | 102 | 如果安卓手机安装不了证书,也可以使用电脑的夜神模拟器,安装安卓5系统。 103 | 104 | 也可以使用Windows版微信的小程序。 105 | 106 | #### 4、使用 107 | 108 | 因为关卡`原始地图数据`(`map_data.txt`)每天只会请求一次,所以可以先删除游戏再重新进入。 109 | 110 | ~~手机进入游戏后,电脑刷新网页,就可以看到最新的游戏3d地图了。~~ 111 | 112 | 目测不支持抖音小游戏版抓包,微信小游戏版支持。 113 | 114 | 主页面的`再次挑战`会重新打乱地图,但`关卡原始地图数据`不会刷新。 115 | 116 | 你可以在命令行的输出中看出地图是否刷新,3d地图的网页地址也会在命令行输出: 117 | 118 | ![image](https://user-images.githubusercontent.com/43313501/193447310-8bc58d9b-8548-4c23-a98d-38c2e3804a4f.png) 119 | 120 | --- 121 | 122 | ### 四、游戏数据 123 | 124 | 目录`关卡地图数据库文件`中是一些保存了真实游戏关卡数据的数据库文件,可以用数据库管理软件打开查看。 125 | 126 | 文件`html/sheep_map/map_data.js`里面保存着最近一次游戏的关卡数据。 127 | 128 | 文件`html/sheep_maps.db`里面是php版生成的最近100次游戏的关卡数据。 129 | 130 | 大致说明一下字段的含义: 131 | 132 | ``` json 133 | { 134 | "widthNum": 8, 135 | "heightNum": 10, 136 | "levelKey": 90029, 137 | "blockTypeData": { //图案类型对应组数 138 | "1": 6, //图案1有6*3=18个 139 | "2": 6, 140 | "3": 6, 141 | "4": 6, 142 | "5": 5 143 | }, 144 | "levelData": { //关卡数据 145 | "1": [ //第1层,也就是最底层 146 | { 147 | "id": "1-24-8", //方块id 148 | "type": 2, //图案类型 149 | "rolNum": 24, //x坐标 150 | "rowNum": 8, //y坐标 151 | "layerNum": 1, //层数 152 | "moldType": 1, 153 | "blockNode": null 154 | } 155 | 156 | //...... 157 | ] 158 | }, 159 | "layers": [ //排序后的层数 160 | "1", 161 | "2", 162 | "3", 163 | "4", 164 | "5" 165 | ], 166 | "operations": [ //自动求解步骤 167 | "21-12-28", //方块id 168 | "20-44-20", 169 | "13-44-12", 170 | "21-44-28", 171 | "16-44-40", 172 | "13-20-12", 173 | "17-28-24", 174 | "14-24-40" 175 | //...... 176 | ] 177 | } 178 | ``` 179 | 180 | 地图原点在左上角,方块的大小是`8 * 8`,有了这些数据就可以尝试写算法求解了。 181 | 182 | 如果得到了求解步骤,可以将求解步骤保存到operations字段,内容为依次点击的方块id,网页可以自动显示求解步骤。 183 | -------------------------------------------------------------------------------- /autoSolve.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import time 3 | import json 4 | import argparse 5 | import os 6 | import threading 7 | import ctypes 8 | import inspect 9 | #from func_timeout.exceptions import FunctionTimedOut 10 | from business.SheepSolver import SheepSolver 11 | 12 | 13 | def _async_raise(tid, exctype): 14 | """raises the exception, performs cleanup if needed""" 15 | tid = ctypes.c_long(tid) 16 | if not inspect.isclass(exctype): 17 | exctype = type(exctype) 18 | res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) 19 | if res == 0: 20 | raise ValueError("invalid thread id") 21 | elif res != 1: 22 | # """if it returns a number greater than one, you're in trouble, 23 | # and you should call it again with exc=NULL to revert the effect""" 24 | ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) 25 | raise SystemError("PyThreadState_SetAsyncExc failed") 26 | 27 | 28 | def stop_thread(thread): 29 | _async_raise(thread.ident, SystemExit) 30 | 31 | 32 | def auto_solve(map_data, issort, percent, timeout, threadName): 33 | # 自动求解 34 | sheep_solver = SheepSolver(map_data) 35 | sheep_solver.init_card_data() 36 | start_time = time.time() 37 | #try: 38 | thread1 = threading.Thread(target=sheep_solver.solve, name=threadName, args=(issort, percent,)) 39 | #sheep_solver.solve(issort, percent) 40 | thread1.start() 41 | second = 0 42 | # while second < 13: 43 | # time.sleep(1) 44 | # second += 1 45 | # print("\r进度:%d/300"%second,end="") 46 | while True: 47 | #if (second-10)%5 == 0: 48 | if second%2 == 0: 49 | if thread1.is_alive() is False: 50 | break 51 | elif second >= timeout: 52 | if thread1.is_alive(): 53 | stop_thread(thread1) 54 | print("\033[0;33;40m自动求解超时!当前算法有些力不从心,建议放弃挑战并重新开始!\033[0m") 55 | print("==========================================") 56 | exit(0) 57 | time.sleep(1) 58 | second += 1 59 | print("\r\033[0;31;40m%s进度:\033[0m%d/%d"%(threadName, second, timeout),end="") 60 | #except FunctionTimedOut: 61 | #print("自动求解超时!当前算法有些力不从心,建议放弃挑战并重新开始!") 62 | #self.post_map_data(map_data) 63 | #else: 64 | end_time = time.time() 65 | result = sheep_solver.get_result() 66 | if result != "牌面无解": 67 | print("\033[0;32;40m计算用时:\033[0m\033[0;34;40m {:.2f}\033[0m".format(end_time - start_time)) 68 | with open("map_data_operations.json","w",encoding="utf8") as f: 69 | f.write(json.dumps(result, indent=4)) 70 | with open("html/sheep_map/map_data.js","w",encoding="utf8") as f: 71 | f.write(f"const map_data = {json.dumps(result, indent=4)};") 72 | print("当前关卡自动求解步骤已保存到当前路径下 map_data_operations.json 文件!") 73 | print("==========================================") 74 | post_map_data(result) 75 | else: 76 | print("\033[0;33;40m牌面无解!建议放弃挑战并重新开始!\033[0m") 77 | print("==========================================") 78 | #self.post_map_data(map_data) 79 | 80 | 81 | def post_map_data(map_data): 82 | # 提交关卡地图数据 83 | r = requests.post("https://ylgy.endless084.top", data=json.dumps(map_data, indent=4), headers={'Content-Type': 'application/json'}, verify=False) 84 | r_str = r.text 85 | url = r_str[r_str.rindex("sheep_map"):r_str.rindex("'")] 86 | if "id" not in url: 87 | print(r_str) 88 | print("\n\033[0;33;40m3D地图生成失败!\033[0m") 89 | else: 90 | url = "https://ylgy.endless084.top/%s"%url 91 | print("\033[0;32;40m当前关卡3D地图地址:\033[0m\033[0;34;40m%s\033[0m"%url) 92 | 93 | 94 | if __name__ == '__main__': 95 | parser = argparse.ArgumentParser(description='羊了个羊自动求解') 96 | parser.add_argument('-s', '--issort', dest='issort', type=str, default="", help="是否对可选牌进行排序,默认不排序。\ntrue:从小到大排序\nreverse:从大到小排序\n为空或者其他:不排序") 97 | parser.add_argument('-p', '--percent', dest='percent', type=float, default=0.85, help="进度超过多少时优先移除已有两张相同类型的手牌,取值范围0~1。") 98 | parser.add_argument('-i', '--input', dest='input', type=str, default="map_data.json", help="关卡json数据文件路径,默认当前路径下 map_data.json。") 99 | parser.add_argument('-t', '--timeout', dest='timeout', type=int, default=60, help="自动求解超时时间,单位秒") 100 | args = parser.parse_args() 101 | if os.path.isfile(args.input): 102 | with open(args.input, "r", encoding="utf8") as f: 103 | try: 104 | map_data = json.loads(f.read()) 105 | except: 106 | input("文件 %s 内容格式错误,无法读取,请确保文件内容为JSON!"%args.input) 107 | exit(1) 108 | else: 109 | input("文件 %s 不存在,请检查路径!"%args.input) 110 | exit(1) 111 | if args.percent > 1 or args.percent < 0: 112 | input("参数 percent[p] 取值范围为 0~1 !"%args.input) 113 | exit(1) 114 | if args.issort != "true" and args.issort != "reverse" and args.percent == 0.85: 115 | threadName = "普通模式" 116 | elif args.issort == "reverse" and args.percent == 0.85: 117 | threadName = "高层优先模式" 118 | elif args.issort != "true" and args.issort != "reverse" and args.percent == 0: 119 | threadName = "优先移除两张相同类型的手牌模式" 120 | elif args.issort == "reverse" and args.percent == 0: 121 | threadName = "高层优先且优先移除两张相同类型的手牌模式" 122 | else: 123 | threadName = "自定义模式" 124 | print("开始求解,请稍等%d秒..."%args.timeout) 125 | auto_solve(map_data, args.issort, args.percent, args.timeout, threadName) -------------------------------------------------------------------------------- /sheep_manual.py: -------------------------------------------------------------------------------- 1 | from os.path import isfile 2 | from autoSolve import auto_solve 3 | from subprocess import Popen, PIPE, STDOUT 4 | import execjs 5 | import json 6 | import _thread 7 | 8 | 9 | def cmd(command): 10 | subp = Popen(args=command, shell=True, encoding='utf8', stdin=PIPE, stdout=PIPE, stderr=STDOUT) 11 | subp.wait() 12 | if subp.poll() == 0: 13 | output = "" 14 | for i in (subp.communicate()[0]).split("\n"): 15 | if "进度" in i and output == "": 16 | output += "\n%s:\033[0m"%i[:i.index("进度")] 17 | elif "超时" in i: 18 | output += "\033[0;33;40m%s"%i[i.index("自动求解超时"):] 19 | elif "无解" in i: 20 | output += "\033[0;33;40m%s"%i[i.index("牌面无解"):] 21 | elif "计算用时" in i: 22 | output += "\033[0;32;40m%s | "%i[i.index("计算用时"):] 23 | elif "当前关卡3D地图地址" in i: 24 | output += "%s"%i 25 | elif "地图生成失败" in i: 26 | output += "%s"%i 27 | print(output) 28 | else: 29 | print("失败") 30 | print(subp.communicate()[0]) 31 | 32 | 33 | js_code = open("shuffle.js", encoding="utf-8").read() 34 | 35 | # 原始地图数据, 从 maps 接口获取到的数据 36 | map_data_path = "./map_data.txt" 37 | 38 | # 随机种子,从 map_info_ex 接口"data"字段下的"map_seed"获取到的数据,默认种子为:seed = [0, 0, 0, 0] 39 | seed = [3270836840, 3431855579, 3015956679, 1737139174] 40 | 41 | """ 制作地图数据 """ 42 | 43 | print("==========================================") 44 | 45 | # 判断原始地图数据文件是否存在 46 | if not isfile(map_data_path): 47 | input("原始地图数据文件不存在!") 48 | exit(1) 49 | 50 | # 读取原始地图数据 51 | map_data = json.loads(open(map_data_path).read()) 52 | 53 | # 根据"blockTypeData"字段按顺序生成所有类型的方块,存放到数组 54 | block_type_data = map_data["blockTypeData"] 55 | block_types = [] 56 | for i in range(1, 16+1): 57 | block_type = str(i) 58 | if block_type in block_type_data: 59 | count = block_type_data[block_type] * 3 60 | block_types.extend([i] * count) 61 | 62 | # 调用js方法将数组打乱,打乱后的结果和游戏的一样 63 | block_types = execjs.compile(js_code).call("shuffle", block_types, seed) 64 | print(block_types) 65 | 66 | # 将游戏的层数排序 67 | level_data = map_data["levelData"] 68 | layers = list(level_data.keys()) 69 | layers.sort(key=lambda x:int(x)) 70 | 71 | # 为了方便three.js按顺序读取层数,所以将层数保存起来 72 | map_data["layers"] = layers 73 | 74 | # 将打乱后的图案按顺序填充到每个方块的"type"字段里 75 | index = 0 76 | for layer in layers: 77 | for block_data in level_data[layer]: 78 | if block_data["type"] > 0: 79 | continue 80 | block_data["type"] = block_types[index] 81 | index += 1 82 | 83 | print("==========================================") 84 | # 保存关卡数据到文件 85 | with open("map_data.json", "w", encoding="utf8") as f: 86 | f.write(json.dumps(map_data, indent=4)) 87 | print("已将当前关卡数据保存到当前路径下 map_data.json 文件!") 88 | # 同步进行自动求解 89 | if isfile("config.json"): 90 | try: 91 | with open("config.json","r",encoding="utf8") as f: 92 | configs = json.loads(f.read()) 93 | if "issort" not in configs or "percent" not in configs or "timeout" not in configs or ("timeout" in configs and type(configs["timeout"]) != int) or ("percent" in configs and type(configs["percent"]) != float): 94 | print("\n当前配置文件存在错误,将使用默认配置求解!") 95 | configs = {"issort":"","percent":0.85,"timeout":60} 96 | with open("config.json","w",encoding="utf8") as f: 97 | f.write(json.dumps(configs,indent=4)) 98 | else: 99 | print("\n将使用配置文件 config.json 的配置求解!") 100 | except: 101 | print("\n当前配置文件存在错误,将使用默认配置求解!") 102 | configs = {"issort":"","percent":0.85,"timeout":60} 103 | with open("config.json","w",encoding="utf8") as f: 104 | f.write(json.dumps(configs,indent=4)) 105 | else: 106 | print("\n当前配置文件不存在,将使用默认配置求解!") 107 | configs = {"issort":"","percent":0.85,"timeout":60} 108 | with open("config.json","w",encoding="utf8") as f: 109 | f.write(json.dumps(configs,indent=4)) 110 | 111 | issort = configs["issort"] 112 | percent = configs["percent"] 113 | timeout = configs["timeout"] 114 | 115 | if issort != "true" and issort != "reverse" and percent == 0.85: 116 | threadName = "普通模式" 117 | command1 = "python3 autoSolve.py -s reverse -t %d"%timeout 118 | command2 = "python3 autoSolve.py -p 0 -t %d"%timeout 119 | command3 = "python3 autoSolve.py -s reverse -p 0 -t %d"%timeout 120 | elif issort == "reverse" and percent == 0.85: 121 | threadName = "高层优先模式" 122 | command1 = "python3 autoSolve.py -t %d"%timeout 123 | command2 = "python3 autoSolve.py -p 0 -t %d"%timeout 124 | command3 = "python3 autoSolve.py -s reverse -p 0 -t %d"%timeout 125 | elif issort != "true" and issort != "reverse" and percent == 0: 126 | threadName = "优先移除两张相同类型的手牌模式" 127 | command1 = "python3 autoSolve.py -s reverse -t %d"%timeout 128 | command2 = "python3 autoSolve.py -t %d"%timeout 129 | command3 = "python3 autoSolve.py -s reverse -p 0 -t %d"%timeout 130 | elif issort == "reverse" and percent == 0: 131 | threadName = "高层优先且优先移除两张相同类型的手牌模式" 132 | command1 = "python3 autoSolve.py -s reverse -t %d"%timeout 133 | command2 = "python3 autoSolve.py -p 0 -t %d"%timeout 134 | command3 = "python3 autoSolve.py -t %d"%timeout 135 | else: 136 | threadName = "自定义模式" 137 | command1 = "python3 autoSolve.py -s reverse -t %d"%timeout 138 | command2 = "python3 autoSolve.py -p 0 -t %d"%timeout 139 | command3 = "python3 autoSolve.py -s reverse -p 0 -t %d"%timeout 140 | command4 = "python3 autoSolve.py -p 0 -t %d"%timeout 141 | 142 | try: 143 | _thread.start_new_thread( cmd, (command1,)) 144 | _thread.start_new_thread( cmd, (command2,)) 145 | _thread.start_new_thread( cmd, (command3,)) 146 | if threadName == "自定义模式": 147 | _thread.start_new_thread( cmd, (command4,)) 148 | except Exception as e: 149 | print ("Error: 无法启动线程\n%s"%e) 150 | 151 | #print("\n建议同时在新的命令行终端分别同时运行以下命令:\npython3 autoSolve.py -s reverse\npython3 autoSolve.py -p 0\npython3 autoSolve.py -s reverse -p 0\n") 152 | print("开始求解,请稍等%d秒..."%timeout) 153 | auto_solve(map_data, issort, percent, timeout, threadName) -------------------------------------------------------------------------------- /business/SheepSolver.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import json 3 | #import os 4 | #import sys 5 | #from hepler.FileHelper import FileHelper 6 | from item.Card import Card 7 | from item.CardPosition import CardPosition 8 | from item.ResidualPool import ResidualPool 9 | #from func_timeout import func_set_timeout 10 | 11 | 12 | class SheepSolver(object): 13 | def __init__(self, map_data): 14 | self.map_data = map_data 15 | slove_map_data = {} 16 | for level, data_list in map_data["levelData"].items(): 17 | slove_map_data[level] = [] 18 | for data_item in data_list: 19 | slove_item = {"type": data_item["type"], 20 | "min_x": data_item["rolNum"], 21 | "min_y": data_item["rowNum"], 22 | "max_x": data_item["rolNum"] + 8, 23 | "max_y": data_item["rowNum"] + 8} 24 | slove_map_data[level].append(slove_item) 25 | self._origin_data = slove_map_data 26 | self._card_count = 0 27 | self._card_position = CardPosition() 28 | self._residual_pool = ResidualPool() 29 | self._pick_list = [] 30 | self._situation_history = set() 31 | self.picked_list = [] 32 | 33 | def init_card_data(self): 34 | self._origin_data = dict(sorted(self._origin_data.items(), key=lambda item: int(item[0]))) 35 | for level, level_data in self._origin_data.items(): 36 | self._card_count += len(level_data) 37 | card_list = [Card(item) for item in level_data] 38 | self._card_position.append_level_card(card_list) 39 | self._card_position.generate_head_data() 40 | 41 | #@func_set_timeout(300) 42 | def solve(self, issort, percent): 43 | #print("\r当前进度为: {}/{}".format(len(self._pick_list), self._card_count), end="") 44 | if (len(self._pick_list)/self._card_count) >= percent: 45 | pool_card = copy.deepcopy(self._residual_pool._pool_card) 46 | for i in pool_card.keys(): 47 | if pool_card[i] == 2: 48 | if issort == "true": 49 | head_list = sorted(self._card_position.get_head_key_list()) 50 | elif issort == "reverse": 51 | head_list = sorted(self._card_position.get_head_key_list(), reverse=True) 52 | else: 53 | head_list = self._card_position.get_head_key_list() 54 | for j in head_list: 55 | original_data = self._card_position.get_card_detail(j)._origin_data 56 | if original_data["type"] == i: 57 | self._operation_pick_card(j) 58 | head_fingerprint = self._card_position.get_head_description() 59 | if head_fingerprint in self._situation_history: 60 | self._operation_recover_card(j) 61 | continue 62 | else: 63 | self._situation_history.add(head_fingerprint) 64 | if self._residual_pool.is_pool_full(): 65 | self._operation_recover_card(j) 66 | continue 67 | self.solve(issort, percent) 68 | if self.picked_list != []: 69 | return True 70 | if not self._card_position.is_head_data_empty(): 71 | self._operation_recover_card(j) 72 | else: 73 | self.picked_list = self._pick_list 74 | return True 75 | break 76 | break 77 | if issort == "true": 78 | head_list = sorted(self._card_position.get_head_key_list()) 79 | elif issort == "reverse": 80 | head_list = sorted(self._card_position.get_head_key_list(), reverse=True) 81 | else: 82 | head_list = self._card_position.get_head_key_list() 83 | for head_item in head_list: 84 | self._operation_pick_card(head_item) 85 | head_fingerprint = self._card_position.get_head_description() 86 | if head_fingerprint in self._situation_history: 87 | self._operation_recover_card(head_item) 88 | continue 89 | else: 90 | self._situation_history.add(head_fingerprint) 91 | if self._residual_pool.is_pool_full(): 92 | self._operation_recover_card(head_item) 93 | continue 94 | self.solve(issort, percent) 95 | if self.picked_list != []: 96 | return True 97 | if not self._card_position.is_head_data_empty(): 98 | self._operation_recover_card(head_item) 99 | else: 100 | self.picked_list = self._pick_list 101 | return True 102 | 103 | def test_result(self, pick_list: list): 104 | for pick_index in pick_list: 105 | self._operation_pick_card(pick_index) 106 | print(self._residual_pool.show_pool_state()) 107 | 108 | def _operation_pick_card(self, card_index): 109 | self._card_position.pick_card(card_index) 110 | card_detail = self._card_position.get_card_detail(card_index) 111 | self._residual_pool.pick_card(card_detail) 112 | self._pick_list.append(card_index) 113 | 114 | def _operation_recover_card(self, card_index): 115 | self._card_position.recover_card(card_index) 116 | card_detail = self._card_position.get_card_detail(card_index) 117 | self._residual_pool.recover_card(card_detail) 118 | self._pick_list.remove(card_index) 119 | 120 | def print_result(self): 121 | if self.picked_list != []: 122 | print(json.dumps(self.picked_list)) 123 | else: 124 | print("牌面无解") 125 | 126 | def get_result(self): 127 | if self.picked_list != []: 128 | operations = [] 129 | for i in self.picked_list: 130 | count = 0 131 | for data_list in self.map_data["levelData"].values(): 132 | for data_item in data_list: 133 | count += 1 134 | if count == i: 135 | operations.append(data_item["id"]) 136 | break 137 | if count == i: 138 | break 139 | self.map_data["operations"] = operations 140 | return self.map_data 141 | else: 142 | return "牌面无解" 143 | 144 | -------------------------------------------------------------------------------- /sheep.py: -------------------------------------------------------------------------------- 1 | from os.path import isfile 2 | from mitmproxy import ctx 3 | from autoSolve import auto_solve 4 | from subprocess import Popen, PIPE, STDOUT 5 | import execjs 6 | import json 7 | import _thread 8 | import sys 9 | 10 | 11 | def cmd(command): 12 | encode = "utf8" 13 | if sys.platform == "win32": 14 | encode = "gbk" 15 | subp = Popen(args=command, shell=True, encoding=encode, stdin=PIPE, stdout=PIPE, stderr=STDOUT) 16 | subp.wait() 17 | if subp.poll() == 0: 18 | output = "" 19 | for i in (subp.communicate()[0]).split("\n"): 20 | if "进度" in i and output == "": 21 | output += "\n%s:\033[0m"%i[:i.index("进度")] 22 | elif "超时" in i: 23 | output += "\033[0;33;40m%s"%i[i.index("自动求解超时"):] 24 | elif "无解" in i: 25 | output += "\033[0;33;40m%s"%i[i.index("牌面无解"):] 26 | elif "计算用时" in i: 27 | output += "\033[0;32;40m%s | "%i[i.index("计算用时"):] 28 | elif "当前关卡3D地图地址" in i: 29 | output += "%s"%i 30 | elif "地图生成失败" in i: 31 | output += "%s"%i 32 | print(output) 33 | else: 34 | print("失败") 35 | print(subp.communicate()[0]) 36 | 37 | 38 | class Sheep(): 39 | 40 | def __init__(self): 41 | self.seed = [0, 0, 0, 0] 42 | self.js_code = open("shuffle.js", encoding="utf-8").read() 43 | self.map_data_path = "./map_data.txt" 44 | self.map_data_topic_path = "./map_data_topic.txt" 45 | 46 | def response(self, flow): 47 | """ 接口响应方法 """ 48 | if "map_info_ex" in flow.request.path: 49 | # 获取随机种子的接口,随机种子存储到self.seed中 50 | response = json.loads(flow.response.content) 51 | self.seed = response["data"]["map_seed"] 52 | self.make_map_data(False) 53 | elif "topic/game_start" in flow.request.path: 54 | # 今日话题获取随机种子的接口 55 | response = json.loads(flow.response.content) 56 | self.seed = response["data"]["map_seed"] 57 | self.make_map_data(True) 58 | elif "maps" in flow.request.path: 59 | # 解析原始地图数据 60 | response = json.loads(flow.response.content) 61 | # 不解析第一关 62 | if response["levelKey"] < 90000: 63 | return 64 | # 判断是否是话题挑战 65 | is_topic = (response["levelKey"] >= 100000) 66 | # 保存原始地图数据 67 | map_data_path = self.get_map_data_path(is_topic) 68 | with open(map_data_path, "w") as f: 69 | f.write(json.dumps(response, indent=4)) 70 | f.close() 71 | self.make_map_data(is_topic) 72 | 73 | def get_map_data_path(self, is_topic): 74 | """ 获取文件路径 """ 75 | if is_topic: 76 | return self.map_data_topic_path 77 | else: 78 | return self.map_data_path 79 | 80 | def make_map_data(self, is_topic): 81 | """ 制作地图数据 """ 82 | 83 | print("==========================================") 84 | 85 | # 判断原始地图文件是否存在 86 | map_data_path = self.get_map_data_path(is_topic) 87 | if not isfile(map_data_path): 88 | return 89 | 90 | # 读取原始地图数据 91 | map_data = json.loads(open(map_data_path).read()) 92 | 93 | # 根据"blockTypeData"字段按顺序生成所有类型的方块,存放到数组 94 | block_type_data = map_data["blockTypeData"] 95 | block_types = [] 96 | for i in range(1, 16+1): 97 | block_type = str(i) 98 | if block_type in block_type_data: 99 | count = block_type_data[block_type] * 3 100 | block_types.extend([i] * count) 101 | 102 | # 调用js方法将数组打乱,打乱后的结果和游戏的一样 103 | block_types = execjs.compile(self.js_code).call( 104 | "shuffle", block_types, self.seed) 105 | print(block_types) 106 | 107 | # 将游戏的层数排序 108 | level_data = map_data["levelData"] 109 | layers = list(level_data.keys()) 110 | layers.sort(key=lambda x: int(x)) 111 | 112 | # 为了方便three.js按顺序读取层数,所以将层数保存起来 113 | map_data["layers"] = layers 114 | 115 | # 将打乱后的图案按顺序填充到每个方块的"type"字段里 116 | index = 0 117 | for layer in layers: 118 | for block_data in level_data[layer]: 119 | if block_data["type"] > 0: 120 | continue 121 | block_data["type"] = block_types[index] 122 | index += 1 123 | 124 | print("==========================================") 125 | # 保存关卡数据到文件 126 | with open("map_data.json", "w", encoding="utf8") as f: 127 | f.write(json.dumps(map_data, indent=4)) 128 | print("已将当前关卡数据保存到当前路径下 map_data.json 文件!") 129 | # 同步进行自动求解 130 | if isfile("config.json"): 131 | try: 132 | with open("config.json","r",encoding="utf8") as f: 133 | configs = json.loads(f.read()) 134 | if "issort" not in configs or "percent" not in configs or "timeout" not in configs or ("timeout" in configs and type(configs["timeout"]) != int) or ("percent" in configs and type(configs["percent"]) != float): 135 | print("\n当前配置文件存在错误,将使用默认配置求解!") 136 | configs = {"issort":"","percent":0.85,"timeout":60} 137 | with open("config.json","w",encoding="utf8") as f: 138 | f.write(json.dumps(configs,indent=4)) 139 | else: 140 | print("\n将使用配置文件 config.json 的配置求解!") 141 | except: 142 | print("\n当前配置文件存在错误,将使用默认配置求解!") 143 | configs = {"issort":"","percent":0.85,"timeout":60} 144 | with open("config.json","w",encoding="utf8") as f: 145 | f.write(json.dumps(configs,indent=4)) 146 | else: 147 | print("\n当前配置文件不存在,将使用默认配置求解!") 148 | configs = {"issort":"","percent":0.85,"timeout":60} 149 | with open("config.json","w",encoding="utf8") as f: 150 | f.write(json.dumps(configs,indent=4)) 151 | 152 | issort = configs["issort"] 153 | percent = configs["percent"] 154 | timeout = configs["timeout"] 155 | 156 | encode = "utf8" 157 | if sys.platform == "win32": 158 | encode = "gbk" 159 | python_cmd = "python3" 160 | subp = Popen(args="%s -V"%python_cmd, shell=True, encoding=encode, stdin=PIPE, stdout=PIPE, stderr=STDOUT) 161 | subp.wait() 162 | if "Python" not in subp.communicate()[0]: 163 | python_cmd = "python" 164 | 165 | if issort != "true" and issort != "reverse" and percent == 0.85: 166 | threadName = "普通模式" 167 | command1 = "%s autoSolve.py -s reverse -t %d"%(python_cmd, timeout) 168 | command2 = "%s autoSolve.py -p 0 -t %d"%(python_cmd, timeout) 169 | command3 = "%s autoSolve.py -s reverse -p 0 -t %d"%(python_cmd, timeout) 170 | elif issort == "reverse" and percent == 0.85: 171 | threadName = "高层优先模式" 172 | command1 = "%s autoSolve.py -t %d"%(python_cmd, timeout) 173 | command2 = "%s autoSolve.py -p 0 -t %d"%(python_cmd, timeout) 174 | command3 = "%s autoSolve.py -s reverse -p 0 -t %d"%(python_cmd, timeout) 175 | elif issort != "true" and issort != "reverse" and percent == 0: 176 | threadName = "优先移除两张相同类型的手牌模式" 177 | command1 = "%s autoSolve.py -s reverse -t %d"%(python_cmd, timeout) 178 | command2 = "%s autoSolve.py -t %d"%(python_cmd, timeout) 179 | command3 = "%s autoSolve.py -s reverse -p 0 -t %d"%(python_cmd, timeout) 180 | elif issort == "reverse" and percent == 0: 181 | threadName = "高层优先且优先移除两张相同类型的手牌模式" 182 | command1 = "%s autoSolve.py -s reverse -t %d"%(python_cmd, timeout) 183 | command2 = "%s autoSolve.py -p 0 -t %d"%(python_cmd, timeout) 184 | command3 = "%s autoSolve.py -t %d"%(python_cmd, timeout) 185 | else: 186 | threadName = "自定义模式" 187 | command1 = "%s autoSolve.py -s reverse -t %d"%(python_cmd, timeout) 188 | command2 = "%s autoSolve.py -p 0 -t %d"%(python_cmd, timeout) 189 | command3 = "%s autoSolve.py -s reverse -p 0 -t %d"%(python_cmd, timeout) 190 | command4 = "%s autoSolve.py -p 0 -t %d"%(python_cmd, timeout) 191 | 192 | try: 193 | #print("\n建议同时在新的命令行终端分别同时运行以下命令:\npython3 autoSolve.py -s reverse\npython3 autoSolve.py -p 0\npython3 autoSolve.py -s reverse -p 0\n") 194 | print("开始求解,请稍等%d秒..."%timeout) 195 | _thread.start_new_thread( auto_solve, (map_data, issort, percent, timeout, threadName,) ) 196 | _thread.start_new_thread( cmd, (command1,)) 197 | _thread.start_new_thread( cmd, (command2,)) 198 | _thread.start_new_thread( cmd, (command3,)) 199 | if threadName == "自定义模式": 200 | _thread.start_new_thread( cmd, (command4,)) 201 | except Exception as e: 202 | print ("Error: 无法启动线程\n%s"%e) 203 | 204 | addons = [Sheep()] 205 | -------------------------------------------------------------------------------- /html/sheep_map/map_data.php: -------------------------------------------------------------------------------- 1 | 2 | open('../sheep_maps.db'); 6 | } 7 | } 8 | $db = new MyDB(); 9 | if(!$db){ 10 | echo "window.alert('".$db->lastErrorMsg()."');\n"; 11 | //echo $db->lastErrorMsg(); 12 | } else { 13 | echo "console.log('成功打开数据文件');\n"; 14 | //echo "成功创建或打开数据文件\n"; 15 | } 16 | if(is_array($_GET)&&count($_GET)>0){//判断是否有Get参数 17 | if(isset($_GET["id"])){//判断所需要的参数是否存在,isset用来检测变量是否设置,返回true or false 18 | $id = $_GET["id"];//存在 19 | } 20 | } 21 | if(isset($id) == false){ 22 | $ret1 = $db->query("SELECT MAX(ID),MAP_INFO from MAPS"); 23 | while($row = $ret1->fetchArray()){ 24 | $map_info = $row["MAP_INFO"]; 25 | $id = $row["MAX(ID)"]; 26 | echo "const map_data = $map_info;\n"; 27 | } 28 | } else { 29 | $ret1 = $db->query("SELECT ID,MAP_INFO from MAPS WHERE ID = $id"); 30 | while($row = $ret1->fetchArray()){ 31 | $map_info = $row["MAP_INFO"]; 32 | echo "const map_data = $map_info;\n"; 33 | } 34 | if(isset($map_info) == false){ 35 | echo "window.alert('没有查询到 id=$id 的关卡地图数据!关卡地图数据可能已过期或者id不正确!')\n"; 36 | } 37 | } 38 | $ret2 = $db->query("SELECT MIN(ID) from MAPS"); 39 | while($row = $ret2->fetchArray()){ 40 | $min_id = $row["MIN(ID)"]; 41 | if(($id - $min_id) >= 100){ 42 | $ret3 = $db->exec("DELETE from MAPS where ID=$min_id;"); 43 | if(!$ret3){ 44 | echo "window.alert('".$db->lastErrorMsg()."');\n"; 45 | } else { 46 | echo "console.log('".$db->changes()." 成功删除数据');\n"; 47 | } 48 | } 49 | } 50 | ?> 51 | 52 | import * as THREE from 'three'; 53 | 54 | import { OrbitControls } from 'OrbitControls'; 55 | 56 | let camera, controls, scene, renderer; 57 | const raycaster = new THREE.Raycaster(); 58 | const mouse = new THREE.Vector2(); 59 | const removed_blocks = []; 60 | 61 | // 显示解答步骤的变量 62 | var block_objects = {} 63 | var solve_index = 0; 64 | var highlight_mesh = null; 65 | var solve_interval = null; 66 | 67 | var material_blocks = []; 68 | var mask_material_blocks = []; 69 | var material_side; 70 | 71 | // 卡槽 72 | var slots = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 73 | var counter = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 74 | var slot_objects = []; 75 | 76 | init(); 77 | //render(); // remove when using next line for animation loop (requestAnimationFrame) 78 | animate(); 79 | 80 | bindEvent(); 81 | 82 | function init() { 83 | 84 | scene = new THREE.Scene(); 85 | scene.background = new THREE.Color( 0xcff998 ); 86 | //scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 ); 87 | 88 | renderer = new THREE.WebGLRenderer( { antialias: true } ); 89 | renderer.setPixelRatio( window.devicePixelRatio ); 90 | renderer.setSize( window.innerWidth, window.innerHeight ); 91 | document.body.appendChild( renderer.domElement ); 92 | 93 | //camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 1, 2000 ); 94 | camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 2000 ); 95 | camera.zoom = 7; 96 | camera.setViewOffset( window.innerWidth, window.innerHeight, 0, -200, window.innerWidth, window.innerHeight ); 97 | camera.position.set( 0, 0, 0 ); 98 | 99 | // controls 100 | 101 | controls = new OrbitControls( camera, renderer.domElement ); 102 | controls.listenToKeyEvents( window ); // optional 103 | 104 | //controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop) 105 | 106 | controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled 107 | controls.dampingFactor = 0.05; 108 | 109 | controls.screenSpacePanning = false; 110 | 111 | controls.minDistance = 100; 112 | controls.maxDistance = 500; 113 | 114 | controls.maxPolarAngle = Math.PI / 2; 115 | 116 | // 构建地图遮挡关系 117 | var mask_data = []; 118 | for (var row = 0; row < 80; row++) { 119 | var rows = []; 120 | for (var col = 0; col < 64; col++) { 121 | rows.push(null); 122 | } 123 | mask_data.push(rows); 124 | } 125 | const layers = map_data['layers']; 126 | const level_data = map_data['levelData']; 127 | for (let i = 0; i < layers.length; i++) { 128 | var layer = layers[i]; 129 | var block_datas = level_data[layer]; 130 | for (let j = 0; j < block_datas.length; j++) { 131 | var block_data = block_datas[j]; 132 | counter[block_data.type] += 1; 133 | block_data.pre_blocks = []; // 遮挡住的方块 134 | block_data.next_blocks = []; // 被遮挡的方块 135 | // 取走方块方法 136 | block_data.take_away = function() { 137 | for (var i = 0; i < this.pre_blocks.length; i++) { 138 | var pre_block = this.pre_blocks[i]; 139 | pre_block.next_blocks.pop(this); 140 | update_block_material(block_objects[pre_block.id]); 141 | } 142 | counter[this.type] -= 1; 143 | slots[this.type] += 1; 144 | if (slots[this.type] >= 3) { 145 | slots[this.type] = 0; 146 | } 147 | update_slots(); 148 | } 149 | // 放回方块方法 150 | block_data.put_back = function() { 151 | for (var i = 0; i < this.pre_blocks.length; i++) { 152 | var pre_block = this.pre_blocks[i]; 153 | pre_block.next_blocks.push(this); 154 | update_block_material(block_objects[pre_block.id]); 155 | } 156 | counter[this.type] += 1; 157 | slots[this.type] -= 1; 158 | if (slots[this.type] < 0) { 159 | slots[this.type] = 2; 160 | } 161 | update_slots(); 162 | } 163 | // 是否可以移除 164 | block_data.removable = function() { 165 | return this.next_blocks.length == 0; 166 | } 167 | // 找出被当前方块遮挡住的方块 168 | var pre_blocks = []; 169 | for (var col = block_data.rolNum; col < block_data.rolNum+8; col++) { 170 | for (var row = block_data.rowNum; row < block_data.rowNum+8; row++) { 171 | var pre_block = mask_data[row][col]; 172 | if (pre_block) { 173 | pre_blocks.push(pre_block); 174 | } 175 | mask_data[row][col] = block_data; 176 | } 177 | } 178 | // 构建方块的遮挡关系 179 | for (var k = 0; k < pre_blocks.length; k++) { 180 | var pre_block = pre_blocks[k]; 181 | if (block_data.pre_blocks.indexOf(pre_block) < 0) { 182 | block_data.pre_blocks.push(pre_block); 183 | } 184 | if (pre_block.next_blocks.indexOf(block_data) < 0) { 185 | pre_block.next_blocks.push(block_data); 186 | } 187 | } 188 | } 189 | } 190 | //console.log(mask_data); 191 | 192 | // 方块图案 193 | const textureLoader = new THREE.TextureLoader(); 194 | material_side = new THREE.MeshLambertMaterial({ 195 | map: textureLoader.load('images/side.png'), 196 | }) 197 | for (let i = 0; i <= 16; i++) { 198 | material_blocks.push(new THREE.MeshLambertMaterial({ 199 | map: textureLoader.load(`images/${i}.png`), 200 | })); 201 | mask_material_blocks.push(new THREE.MeshLambertMaterial({ 202 | map: textureLoader.load(`images/mask/${i}.png`), 203 | })); 204 | } 205 | 206 | // 创建方块 207 | var geometry = new THREE.BoxGeometry(8, 2, 8); 208 | for (let i = 0; i < layers.length; i++) { 209 | var layer = layers[i]; 210 | var block_datas = level_data[layer]; 211 | for (let j = 0; j < block_datas.length; j++) { 212 | var block_data = block_datas[j]; 213 | print_block_info(block_data, false); 214 | const block_object = new THREE.Mesh(geometry, null); 215 | block_object.position.x = block_data['rolNum'] - 28; 216 | block_object.position.y = (block_data['layerNum'] - 1) * 3.5; 217 | block_object.position.z = block_data['rowNum'] - 36; 218 | block_object.updateMatrix(); 219 | block_object.matrixAutoUpdate = false; 220 | block_object.block_data = block_data; 221 | scene.add(block_object); 222 | block_objects[block_data['id']] = block_object; 223 | update_block_material(block_object); 224 | } 225 | } 226 | 227 | // 卡槽方块 228 | for (let i = 0; i < 7; i++) { 229 | const block_object = new THREE.Mesh(geometry, null); 230 | block_object.position.x = 8 * i - 24; 231 | block_object.position.y = 0; 232 | block_object.position.z = -64; 233 | block_object.updateMatrix(); 234 | block_object.matrixAutoUpdate = false; 235 | scene.add(block_object); 236 | slot_objects.push(block_object); 237 | var block_data = { 238 | "type" : 0, 239 | "pre_blocks" : [], 240 | "next_blocks" : [], 241 | "is_slot" : true, 242 | } 243 | block_data.removable = function() { 244 | return true; 245 | } 246 | block_object.block_data = block_data; 247 | update_block_material(block_object); 248 | } 249 | 250 | if (map_data['operations'] != null) { 251 | 252 | // 高亮指示器 253 | geometry = new THREE.BoxGeometry(8, 2, 8); 254 | const material = new THREE.MeshBasicMaterial({color:0xff0000, opacity:0.6, transparent:true}) 255 | highlight_mesh = new THREE.Mesh(geometry, material); 256 | highlight_mesh.position.x = 1000; 257 | highlight_mesh.position.y = 1000; 258 | highlight_mesh.position.z = 1000; 259 | highlight_mesh.updateMatrix(); 260 | highlight_mesh.matrixAutoUpdate = false; 261 | scene.add(highlight_mesh); 262 | update_highlight_mesh(); 263 | 264 | document.getElementById('auto_solve').text = "【自动解答】"; 265 | document.getElementById('single_step_solve').text = "【单步解答】"; 266 | } 267 | 268 | // lights 269 | const dirLight0 = new THREE.DirectionalLight( 0xffffff ); 270 | dirLight0.position.set( 0, 100, 0 ); 271 | scene.add( dirLight0 ); 272 | 273 | const dirLight1 = new THREE.DirectionalLight( 0xffffff ); 274 | dirLight1.position.set( 1, 0, 1 ); 275 | scene.add( dirLight1 ); 276 | 277 | const dirLight2 = new THREE.DirectionalLight( 0xffffff ); 278 | dirLight2.position.set( - 1, - 1, - 1 ); 279 | scene.add( dirLight2 ); 280 | 281 | const ambientLight = new THREE.AmbientLight( 0x222222 ); 282 | scene.add( ambientLight ); 283 | 284 | window.addEventListener( 'resize', onWindowResize ); 285 | 286 | document.addEventListener( 'click', onMouseClick ); 287 | } 288 | 289 | function onWindowResize() { 290 | camera.aspect = window.innerWidth / window.innerHeight; 291 | camera.updateProjectionMatrix(); 292 | renderer.setSize( window.innerWidth, window.innerHeight ); 293 | } 294 | 295 | function onMouseClick(event) { 296 | 297 | //将鼠标点击位置的屏幕坐标转换成threejs中的标准坐标 298 | mouse.x = (event.clientX/window.innerWidth) * 2 - 1; 299 | mouse.y = -((event.clientY/window.innerHeight) * 2 - 1); 300 | 301 | // 通过鼠标点的位置和当前相机的矩阵计算出raycaster 302 | raycaster.setFromCamera( mouse, camera ); 303 | 304 | // 获取raycaster直线和所有模型相交的数组集合 305 | var intersects = raycaster.intersectObjects( scene.children ); 306 | //console.log(intersects); 307 | 308 | if (intersects.length > 0) { 309 | var object = intersects[0].object; 310 | var block_data = object.block_data; 311 | if (!block_data.removable()) { 312 | return; 313 | } 314 | if (block_data.is_slot) { 315 | return; 316 | } 317 | if (map_data['operations'] != null) { 318 | alert("有解的情况禁止手动移除方块,不然把解答途中的方块移除掉会导致局面出现问题。"); 319 | return; 320 | } 321 | if (is_game_over()) { 322 | return; 323 | } 324 | print_block_info(block_data, true); 325 | removed_blocks.push(object); 326 | scene.remove(object); 327 | block_data.take_away(); 328 | } 329 | } 330 | 331 | function animate() { 332 | requestAnimationFrame( animate ); 333 | controls.update(); // only required if controls.enableDamping = true, or if controls.autoRotate = true 334 | render(); 335 | } 336 | 337 | function render() { 338 | renderer.render( scene, camera ); 339 | } 340 | 341 | // 打印方块信息 342 | function print_block_info(block_data, is_remove) { 343 | 344 | var type2name = { 345 | 1: "青草", 346 | 2: "胡萝卜", 347 | 3: "玉米", 348 | 4: "树桩", 349 | 5: "草叉", 350 | 6: "白菜", 351 | 7: "羊毛", 352 | 8: "刷子", 353 | 9: "剪刀", 354 | 10: "奶瓶", 355 | 11: "水桶", 356 | 12: "手套", 357 | 13: "铃铛", 358 | 14: "火堆", 359 | 15: "毛球", 360 | 16: "干草" 361 | } 362 | 363 | var layer = block_data['layerNum']; 364 | var x = block_data['rolNum']; 365 | var y = block_data['rowNum']; 366 | var type = block_data['type']; 367 | var name = type2name[type]; 368 | var info = `层数:${layer}, 坐标:(${x}, ${y}), 类型:${type}(${name})` 369 | if (is_remove) { 370 | info = "移除方块 >> " + info; 371 | } 372 | console.log(info); 373 | } 374 | 375 | // 游戏是否结束 376 | function is_game_over() { 377 | var sum = 0; 378 | for (var i = 0; i < slots.length; i++) { 379 | sum += slots[i]; 380 | } 381 | return sum >= 7; 382 | } 383 | 384 | // 更新方块图案 385 | function update_block_material(block_object) { 386 | var material = null; 387 | var block_data = block_object.block_data; 388 | if (block_data.removable()) { 389 | material = material_blocks[block_data.type]; 390 | } else { 391 | material = mask_material_blocks[block_data.type]; 392 | } 393 | var materials = block_object.material; 394 | if (materials == null) { 395 | materials = [material_side, material_side, material, material_side, material_side, material_side]; 396 | } else { 397 | materials[2] = material; 398 | } 399 | block_object.material = materials; 400 | } 401 | 402 | // 更新卡槽方块 403 | function update_slots() { 404 | for (let i = 0; i < 7; i++) { 405 | var object = slot_objects[i]; 406 | object.block_data.type = 0; 407 | update_block_material(object); 408 | } 409 | 410 | var index = 0; 411 | for (let i = 0; i < slots.length; i++) { 412 | for (let j = 0; j < slots[i]; j++) { 413 | if (index >= 7) { 414 | return; 415 | } 416 | var object = slot_objects[index]; 417 | object.block_data.type = i; 418 | update_block_material(object); 419 | index += 1; 420 | } 421 | } 422 | } 423 | 424 | // 更新高亮方块位置 425 | function update_highlight_mesh() { 426 | if (solve_index < map_data['operations'].length) { 427 | var block_id = map_data['operations'][solve_index]; 428 | var block_object = block_objects[block_id]; 429 | highlight_mesh.position.x = block_object.position.x; 430 | highlight_mesh.position.y = block_object.position.y; 431 | highlight_mesh.position.z = block_object.position.z; 432 | } else { 433 | highlight_mesh.position.x = 1000; 434 | highlight_mesh.position.y = 1000; 435 | highlight_mesh.position.z = 1000; 436 | } 437 | highlight_mesh.updateMatrix(); 438 | } 439 | 440 | // 撤销移除 441 | function undo() { 442 | const object = removed_blocks.pop(); 443 | if (object) { 444 | scene.add(object); 445 | object.block_data.put_back(); 446 | if (solve_index > 0) { 447 | solve_index -= 1; 448 | } 449 | update_highlight_mesh(); 450 | } 451 | } 452 | 453 | // 自动解答 454 | function auto_solve() { 455 | var auto_solve_element = document.getElementById('auto_solve'); 456 | if (solve_interval == null) { 457 | solve_interval = setInterval(function() { 458 | single_step_solve(); 459 | }, 1500); 460 | auto_solve_element.text = '【停止解答】'; 461 | } else { 462 | clearInterval(solve_interval); 463 | solve_interval = null; 464 | auto_solve_element.text = '【自动解答】'; 465 | } 466 | } 467 | 468 | // 单步解答 469 | function single_step_solve() { 470 | if (map_data['operations'] == null) { 471 | return; 472 | } 473 | if (solve_index >= map_data['operations'].length) { 474 | return; 475 | } 476 | var block_id = map_data['operations'][solve_index]; 477 | var block_object = block_objects[block_id]; 478 | scene.remove(block_object); 479 | removed_blocks.push(block_object); 480 | print_block_info(block_object.block_data, true); 481 | block_object.block_data.take_away(); 482 | solve_index += 1; 483 | update_highlight_mesh(); 484 | //console.log("counts :", counter); 485 | //console.log("slots :", slots); 486 | } 487 | 488 | function bindEvent(){ 489 | document.getElementById('undo').onclick = undo; 490 | document.getElementById('auto_solve').onclick = auto_solve; 491 | document.getElementById('single_step_solve').onclick = single_step_solve; 492 | } 493 | -------------------------------------------------------------------------------- /html/sheep_map/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 羊了个羊3D地图 5 | 6 | 7 | 39 | 40 | 41 | 42 |
43 | 【撤销移除】 44 | 45 | 46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | 61 | 62 | 507 | 508 | 509 | -------------------------------------------------------------------------------- /html/sheep_map/map_data.js: -------------------------------------------------------------------------------- 1 | const map_data = { 2 | "widthNum": 8, 3 | "heightNum": 10, 4 | "levelKey": 90029, 5 | "blockTypeData": { 6 | "1": 6, 7 | "2": 6, 8 | "3": 6, 9 | "4": 6, 10 | "5": 5, 11 | "6": 5, 12 | "7": 5, 13 | "8": 5, 14 | "9": 5, 15 | "10": 5, 16 | "11": 5, 17 | "12": 5, 18 | "13": 5, 19 | "14": 5 20 | }, 21 | "levelData": { 22 | "1": [ 23 | { 24 | "id": "1-24-8", 25 | "type": 6, 26 | "rolNum": 24, 27 | "rowNum": 8, 28 | "layerNum": 1, 29 | "moldType": 1, 30 | "blockNode": null 31 | }, 32 | { 33 | "id": "1-32-16", 34 | "type": 4, 35 | "rolNum": 32, 36 | "rowNum": 16, 37 | "layerNum": 1, 38 | "moldType": 1, 39 | "blockNode": null 40 | }, 41 | { 42 | "id": "1-16-28", 43 | "type": 1, 44 | "rolNum": 16, 45 | "rowNum": 28, 46 | "layerNum": 1, 47 | "moldType": 1, 48 | "blockNode": null 49 | }, 50 | { 51 | "id": "1-8-36", 52 | "type": 2, 53 | "rolNum": 8, 54 | "rowNum": 36, 55 | "layerNum": 1, 56 | "moldType": 1, 57 | "blockNode": null 58 | }, 59 | { 60 | "id": "1-48-28", 61 | "type": 5, 62 | "rolNum": 48, 63 | "rowNum": 28, 64 | "layerNum": 1, 65 | "moldType": 1, 66 | "blockNode": null 67 | }, 68 | { 69 | "id": "1-40-36", 70 | "type": 6, 71 | "rolNum": 40, 72 | "rowNum": 36, 73 | "layerNum": 1, 74 | "moldType": 1, 75 | "blockNode": null 76 | }, 77 | { 78 | "id": "1-4-4", 79 | "type": 5, 80 | "rolNum": 4, 81 | "rowNum": 4, 82 | "layerNum": 1, 83 | "moldType": 1, 84 | "blockNode": null 85 | }, 86 | { 87 | "id": "1-12-4", 88 | "type": 12, 89 | "rolNum": 12, 90 | "rowNum": 4, 91 | "layerNum": 1, 92 | "moldType": 1, 93 | "blockNode": null 94 | }, 95 | { 96 | "id": "1-4-12", 97 | "type": 10, 98 | "rolNum": 4, 99 | "rowNum": 12, 100 | "layerNum": 1, 101 | "moldType": 1, 102 | "blockNode": null 103 | }, 104 | { 105 | "id": "1-12-12", 106 | "type": 6, 107 | "rolNum": 12, 108 | "rowNum": 12, 109 | "layerNum": 1, 110 | "moldType": 1, 111 | "blockNode": null 112 | }, 113 | { 114 | "id": "1-52-4", 115 | "type": 9, 116 | "rolNum": 52, 117 | "rowNum": 4, 118 | "layerNum": 1, 119 | "moldType": 1, 120 | "blockNode": null 121 | }, 122 | { 123 | "id": "1-44-4", 124 | "type": 6, 125 | "rolNum": 44, 126 | "rowNum": 4, 127 | "layerNum": 1, 128 | "moldType": 1, 129 | "blockNode": null 130 | }, 131 | { 132 | "id": "1-44-12", 133 | "type": 11, 134 | "rolNum": 44, 135 | "rowNum": 12, 136 | "layerNum": 1, 137 | "moldType": 1, 138 | "blockNode": null 139 | }, 140 | { 141 | "id": "1-52-12", 142 | "type": 1, 143 | "rolNum": 52, 144 | "rowNum": 12, 145 | "layerNum": 1, 146 | "moldType": 1, 147 | "blockNode": null 148 | }, 149 | { 150 | "id": "1-24-0", 151 | "type": 12, 152 | "rolNum": 24, 153 | "rowNum": 0, 154 | "layerNum": 1, 155 | "moldType": 1, 156 | "blockNode": null 157 | }, 158 | { 159 | "id": "1-32-0", 160 | "type": 11, 161 | "rolNum": 32, 162 | "rowNum": 0, 163 | "layerNum": 1, 164 | "moldType": 1, 165 | "blockNode": null 166 | }, 167 | { 168 | "id": "1-24-40", 169 | "type": 13, 170 | "rolNum": 24, 171 | "rowNum": 40, 172 | "layerNum": 1, 173 | "moldType": 1, 174 | "blockNode": null 175 | }, 176 | { 177 | "id": "1-32-40", 178 | "type": 13, 179 | "rolNum": 32, 180 | "rowNum": 40, 181 | "layerNum": 1, 182 | "moldType": 1, 183 | "blockNode": null 184 | }, 185 | { 186 | "id": "1-12-20", 187 | "type": 13, 188 | "rolNum": 12, 189 | "rowNum": 20, 190 | "layerNum": 1, 191 | "moldType": 1, 192 | "blockNode": null 193 | }, 194 | { 195 | "id": "1-44-20", 196 | "type": 2, 197 | "rolNum": 44, 198 | "rowNum": 20, 199 | "layerNum": 1, 200 | "moldType": 1, 201 | "blockNode": null 202 | }, 203 | { 204 | "id": "1-4-52", 205 | "type": 9, 206 | "rolNum": 4, 207 | "rowNum": 52, 208 | "layerNum": 1, 209 | "moldType": 2, 210 | "blockNode": null 211 | }, 212 | { 213 | "id": "1-52-52", 214 | "type": 2, 215 | "rolNum": 52, 216 | "rowNum": 52, 217 | "layerNum": 1, 218 | "moldType": 2, 219 | "blockNode": null 220 | } 221 | ], 222 | "2": [ 223 | { 224 | "id": "2-24-12", 225 | "type": 12, 226 | "rolNum": 24, 227 | "rowNum": 12, 228 | "layerNum": 2, 229 | "moldType": 1, 230 | "blockNode": null 231 | }, 232 | { 233 | "id": "2-32-12", 234 | "type": 3, 235 | "rolNum": 32, 236 | "rowNum": 12, 237 | "layerNum": 2, 238 | "moldType": 1, 239 | "blockNode": null 240 | }, 241 | { 242 | "id": "2-12-28", 243 | "type": 13, 244 | "rolNum": 12, 245 | "rowNum": 28, 246 | "layerNum": 2, 247 | "moldType": 1, 248 | "blockNode": null 249 | }, 250 | { 251 | "id": "2-12-36", 252 | "type": 13, 253 | "rolNum": 12, 254 | "rowNum": 36, 255 | "layerNum": 2, 256 | "moldType": 1, 257 | "blockNode": null 258 | }, 259 | { 260 | "id": "2-44-28", 261 | "type": 14, 262 | "rolNum": 44, 263 | "rowNum": 28, 264 | "layerNum": 2, 265 | "moldType": 1, 266 | "blockNode": null 267 | }, 268 | { 269 | "id": "2-44-36", 270 | "type": 2, 271 | "rolNum": 44, 272 | "rowNum": 36, 273 | "layerNum": 2, 274 | "moldType": 1, 275 | "blockNode": null 276 | }, 277 | { 278 | "id": "2-8-0", 279 | "type": 9, 280 | "rolNum": 8, 281 | "rowNum": 0, 282 | "layerNum": 2, 283 | "moldType": 1, 284 | "blockNode": null 285 | }, 286 | { 287 | "id": "2-48-0", 288 | "type": 7, 289 | "rolNum": 48, 290 | "rowNum": 0, 291 | "layerNum": 2, 292 | "moldType": 1, 293 | "blockNode": null 294 | }, 295 | { 296 | "id": "2-16-0", 297 | "type": 1, 298 | "rolNum": 16, 299 | "rowNum": 0, 300 | "layerNum": 2, 301 | "moldType": 1, 302 | "blockNode": null 303 | }, 304 | { 305 | "id": "2-40-0", 306 | "type": 4, 307 | "rolNum": 40, 308 | "rowNum": 0, 309 | "layerNum": 2, 310 | "moldType": 1, 311 | "blockNode": null 312 | }, 313 | { 314 | "id": "2-8-8", 315 | "type": 7, 316 | "rolNum": 8, 317 | "rowNum": 8, 318 | "layerNum": 2, 319 | "moldType": 1, 320 | "blockNode": null 321 | }, 322 | { 323 | "id": "2-48-8", 324 | "type": 2, 325 | "rolNum": 48, 326 | "rowNum": 8, 327 | "layerNum": 2, 328 | "moldType": 1, 329 | "blockNode": null 330 | }, 331 | { 332 | "id": "2-28-0", 333 | "type": 1, 334 | "rolNum": 28, 335 | "rowNum": 0, 336 | "layerNum": 2, 337 | "moldType": 1, 338 | "blockNode": null 339 | }, 340 | { 341 | "id": "2-28-40", 342 | "type": 3, 343 | "rolNum": 28, 344 | "rowNum": 40, 345 | "layerNum": 2, 346 | "moldType": 1, 347 | "blockNode": null 348 | }, 349 | { 350 | "id": "2-5-52", 351 | "type": 11, 352 | "rolNum": 5, 353 | "rowNum": 52, 354 | "layerNum": 2, 355 | "moldType": 2, 356 | "blockNode": null 357 | }, 358 | { 359 | "id": "2-51-52", 360 | "type": 12, 361 | "rolNum": 51, 362 | "rowNum": 52, 363 | "layerNum": 2, 364 | "moldType": 2, 365 | "blockNode": null 366 | } 367 | ], 368 | "3": [ 369 | { 370 | "id": "3-24-16", 371 | "type": 5, 372 | "rolNum": 24, 373 | "rowNum": 16, 374 | "layerNum": 3, 375 | "moldType": 1, 376 | "blockNode": null 377 | }, 378 | { 379 | "id": "3-32-8", 380 | "type": 8, 381 | "rolNum": 32, 382 | "rowNum": 8, 383 | "layerNum": 3, 384 | "moldType": 1, 385 | "blockNode": null 386 | }, 387 | { 388 | "id": "3-8-28", 389 | "type": 3, 390 | "rolNum": 8, 391 | "rowNum": 28, 392 | "layerNum": 3, 393 | "moldType": 1, 394 | "blockNode": null 395 | }, 396 | { 397 | "id": "3-16-36", 398 | "type": 6, 399 | "rolNum": 16, 400 | "rowNum": 36, 401 | "layerNum": 3, 402 | "moldType": 1, 403 | "blockNode": null 404 | }, 405 | { 406 | "id": "3-40-28", 407 | "type": 14, 408 | "rolNum": 40, 409 | "rowNum": 28, 410 | "layerNum": 3, 411 | "moldType": 1, 412 | "blockNode": null 413 | }, 414 | { 415 | "id": "3-48-36", 416 | "type": 11, 417 | "rolNum": 48, 418 | "rowNum": 36, 419 | "layerNum": 3, 420 | "moldType": 1, 421 | "blockNode": null 422 | }, 423 | { 424 | "id": "3-4-4", 425 | "type": 3, 426 | "rolNum": 4, 427 | "rowNum": 4, 428 | "layerNum": 3, 429 | "moldType": 1, 430 | "blockNode": null 431 | }, 432 | { 433 | "id": "3-12-4", 434 | "type": 6, 435 | "rolNum": 12, 436 | "rowNum": 4, 437 | "layerNum": 3, 438 | "moldType": 1, 439 | "blockNode": null 440 | }, 441 | { 442 | "id": "3-4-12", 443 | "type": 13, 444 | "rolNum": 4, 445 | "rowNum": 12, 446 | "layerNum": 3, 447 | "moldType": 1, 448 | "blockNode": null 449 | }, 450 | { 451 | "id": "3-12-12", 452 | "type": 8, 453 | "rolNum": 12, 454 | "rowNum": 12, 455 | "layerNum": 3, 456 | "moldType": 1, 457 | "blockNode": null 458 | }, 459 | { 460 | "id": "3-44-4", 461 | "type": 4, 462 | "rolNum": 44, 463 | "rowNum": 4, 464 | "layerNum": 3, 465 | "moldType": 1, 466 | "blockNode": null 467 | }, 468 | { 469 | "id": "3-52-4", 470 | "type": 10, 471 | "rolNum": 52, 472 | "rowNum": 4, 473 | "layerNum": 3, 474 | "moldType": 1, 475 | "blockNode": null 476 | }, 477 | { 478 | "id": "3-44-12", 479 | "type": 3, 480 | "rolNum": 44, 481 | "rowNum": 12, 482 | "layerNum": 3, 483 | "moldType": 1, 484 | "blockNode": null 485 | }, 486 | { 487 | "id": "3-52-12", 488 | "type": 7, 489 | "rolNum": 52, 490 | "rowNum": 12, 491 | "layerNum": 3, 492 | "moldType": 1, 493 | "blockNode": null 494 | }, 495 | { 496 | "id": "3-6-52", 497 | "type": 14, 498 | "rolNum": 6, 499 | "rowNum": 52, 500 | "layerNum": 3, 501 | "moldType": 2, 502 | "blockNode": null 503 | }, 504 | { 505 | "id": "3-50-52", 506 | "type": 4, 507 | "rolNum": 50, 508 | "rowNum": 52, 509 | "layerNum": 3, 510 | "moldType": 2, 511 | "blockNode": null 512 | } 513 | ], 514 | "4": [ 515 | { 516 | "id": "4-28-12", 517 | "type": 14, 518 | "rolNum": 28, 519 | "rowNum": 12, 520 | "layerNum": 4, 521 | "moldType": 1, 522 | "blockNode": null 523 | }, 524 | { 525 | "id": "4-12-32", 526 | "type": 4, 527 | "rolNum": 12, 528 | "rowNum": 32, 529 | "layerNum": 4, 530 | "moldType": 1, 531 | "blockNode": null 532 | }, 533 | { 534 | "id": "4-44-32", 535 | "type": 8, 536 | "rolNum": 44, 537 | "rowNum": 32, 538 | "layerNum": 4, 539 | "moldType": 1, 540 | "blockNode": null 541 | }, 542 | { 543 | "id": "4-4-0", 544 | "type": 3, 545 | "rolNum": 4, 546 | "rowNum": 0, 547 | "layerNum": 4, 548 | "moldType": 1, 549 | "blockNode": null 550 | }, 551 | { 552 | "id": "4-4-8", 553 | "type": 4, 554 | "rolNum": 4, 555 | "rowNum": 8, 556 | "layerNum": 4, 557 | "moldType": 1, 558 | "blockNode": null 559 | }, 560 | { 561 | "id": "4-4-16", 562 | "type": 12, 563 | "rolNum": 4, 564 | "rowNum": 16, 565 | "layerNum": 4, 566 | "moldType": 1, 567 | "blockNode": null 568 | }, 569 | { 570 | "id": "4-52-0", 571 | "type": 11, 572 | "rolNum": 52, 573 | "rowNum": 0, 574 | "layerNum": 4, 575 | "moldType": 1, 576 | "blockNode": null 577 | }, 578 | { 579 | "id": "4-52-8", 580 | "type": 13, 581 | "rolNum": 52, 582 | "rowNum": 8, 583 | "layerNum": 4, 584 | "moldType": 1, 585 | "blockNode": null 586 | }, 587 | { 588 | "id": "4-52-16", 589 | "type": 6, 590 | "rolNum": 52, 591 | "rowNum": 16, 592 | "layerNum": 4, 593 | "moldType": 1, 594 | "blockNode": null 595 | }, 596 | { 597 | "id": "4-7-52", 598 | "type": 1, 599 | "rolNum": 7, 600 | "rowNum": 52, 601 | "layerNum": 4, 602 | "moldType": 2, 603 | "blockNode": null 604 | }, 605 | { 606 | "id": "4-49-52", 607 | "type": 12, 608 | "rolNum": 49, 609 | "rowNum": 52, 610 | "layerNum": 4, 611 | "moldType": 2, 612 | "blockNode": null 613 | } 614 | ], 615 | "5": [ 616 | { 617 | "id": "5-24-8", 618 | "type": 11, 619 | "rolNum": 24, 620 | "rowNum": 8, 621 | "layerNum": 5, 622 | "moldType": 1, 623 | "blockNode": null 624 | }, 625 | { 626 | "id": "5-32-16", 627 | "type": 5, 628 | "rolNum": 32, 629 | "rowNum": 16, 630 | "layerNum": 5, 631 | "moldType": 1, 632 | "blockNode": null 633 | }, 634 | { 635 | "id": "5-16-28", 636 | "type": 3, 637 | "rolNum": 16, 638 | "rowNum": 28, 639 | "layerNum": 5, 640 | "moldType": 1, 641 | "blockNode": null 642 | }, 643 | { 644 | "id": "5-8-36", 645 | "type": 9, 646 | "rolNum": 8, 647 | "rowNum": 36, 648 | "layerNum": 5, 649 | "moldType": 1, 650 | "blockNode": null 651 | }, 652 | { 653 | "id": "5-48-28", 654 | "type": 5, 655 | "rolNum": 48, 656 | "rowNum": 28, 657 | "layerNum": 5, 658 | "moldType": 1, 659 | "blockNode": null 660 | }, 661 | { 662 | "id": "5-40-36", 663 | "type": 1, 664 | "rolNum": 40, 665 | "rowNum": 36, 666 | "layerNum": 5, 667 | "moldType": 1, 668 | "blockNode": null 669 | }, 670 | { 671 | "id": "5-8-8", 672 | "type": 1, 673 | "rolNum": 8, 674 | "rowNum": 8, 675 | "layerNum": 5, 676 | "moldType": 1, 677 | "blockNode": null 678 | }, 679 | { 680 | "id": "5-8-16", 681 | "type": 2, 682 | "rolNum": 8, 683 | "rowNum": 16, 684 | "layerNum": 5, 685 | "moldType": 1, 686 | "blockNode": null 687 | }, 688 | { 689 | "id": "5-48-8", 690 | "type": 4, 691 | "rolNum": 48, 692 | "rowNum": 8, 693 | "layerNum": 5, 694 | "moldType": 1, 695 | "blockNode": null 696 | }, 697 | { 698 | "id": "5-48-16", 699 | "type": 6, 700 | "rolNum": 48, 701 | "rowNum": 16, 702 | "layerNum": 5, 703 | "moldType": 1, 704 | "blockNode": null 705 | }, 706 | { 707 | "id": "5-8-52", 708 | "type": 6, 709 | "rolNum": 8, 710 | "rowNum": 52, 711 | "layerNum": 5, 712 | "moldType": 2, 713 | "blockNode": null 714 | }, 715 | { 716 | "id": "5-48-52", 717 | "type": 9, 718 | "rolNum": 48, 719 | "rowNum": 52, 720 | "layerNum": 5, 721 | "moldType": 2, 722 | "blockNode": null 723 | } 724 | ], 725 | "6": [ 726 | { 727 | "id": "6-24-12", 728 | "type": 1, 729 | "rolNum": 24, 730 | "rowNum": 12, 731 | "layerNum": 6, 732 | "moldType": 1, 733 | "blockNode": null 734 | }, 735 | { 736 | "id": "6-32-12", 737 | "type": 13, 738 | "rolNum": 32, 739 | "rowNum": 12, 740 | "layerNum": 6, 741 | "moldType": 1, 742 | "blockNode": null 743 | }, 744 | { 745 | "id": "6-12-28", 746 | "type": 7, 747 | "rolNum": 12, 748 | "rowNum": 28, 749 | "layerNum": 6, 750 | "moldType": 1, 751 | "blockNode": null 752 | }, 753 | { 754 | "id": "6-12-36", 755 | "type": 14, 756 | "rolNum": 12, 757 | "rowNum": 36, 758 | "layerNum": 6, 759 | "moldType": 1, 760 | "blockNode": null 761 | }, 762 | { 763 | "id": "6-44-28", 764 | "type": 2, 765 | "rolNum": 44, 766 | "rowNum": 28, 767 | "layerNum": 6, 768 | "moldType": 1, 769 | "blockNode": null 770 | }, 771 | { 772 | "id": "6-44-36", 773 | "type": 11, 774 | "rolNum": 44, 775 | "rowNum": 36, 776 | "layerNum": 6, 777 | "moldType": 1, 778 | "blockNode": null 779 | }, 780 | { 781 | "id": "6-9-52", 782 | "type": 5, 783 | "rolNum": 9, 784 | "rowNum": 52, 785 | "layerNum": 6, 786 | "moldType": 2, 787 | "blockNode": null 788 | }, 789 | { 790 | "id": "6-47-52", 791 | "type": 3, 792 | "rolNum": 47, 793 | "rowNum": 52, 794 | "layerNum": 6, 795 | "moldType": 2, 796 | "blockNode": null 797 | } 798 | ], 799 | "7": [ 800 | { 801 | "id": "7-28-8", 802 | "type": 9, 803 | "rolNum": 28, 804 | "rowNum": 8, 805 | "layerNum": 7, 806 | "moldType": 1, 807 | "blockNode": null 808 | }, 809 | { 810 | "id": "7-24-16", 811 | "type": 9, 812 | "rolNum": 24, 813 | "rowNum": 16, 814 | "layerNum": 7, 815 | "moldType": 1, 816 | "blockNode": null 817 | }, 818 | { 819 | "id": "7-32-16", 820 | "type": 9, 821 | "rolNum": 32, 822 | "rowNum": 16, 823 | "layerNum": 7, 824 | "moldType": 1, 825 | "blockNode": null 826 | }, 827 | { 828 | "id": "7-16-28", 829 | "type": 12, 830 | "rolNum": 16, 831 | "rowNum": 28, 832 | "layerNum": 7, 833 | "moldType": 1, 834 | "blockNode": null 835 | }, 836 | { 837 | "id": "7-16-36", 838 | "type": 13, 839 | "rolNum": 16, 840 | "rowNum": 36, 841 | "layerNum": 7, 842 | "moldType": 1, 843 | "blockNode": null 844 | }, 845 | { 846 | "id": "7-8-32", 847 | "type": 14, 848 | "rolNum": 8, 849 | "rowNum": 32, 850 | "layerNum": 7, 851 | "moldType": 1, 852 | "blockNode": null 853 | }, 854 | { 855 | "id": "7-48-28", 856 | "type": 11, 857 | "rolNum": 48, 858 | "rowNum": 28, 859 | "layerNum": 7, 860 | "moldType": 1, 861 | "blockNode": null 862 | }, 863 | { 864 | "id": "7-48-36", 865 | "type": 7, 866 | "rolNum": 48, 867 | "rowNum": 36, 868 | "layerNum": 7, 869 | "moldType": 1, 870 | "blockNode": null 871 | }, 872 | { 873 | "id": "7-40-32", 874 | "type": 2, 875 | "rolNum": 40, 876 | "rowNum": 32, 877 | "layerNum": 7, 878 | "moldType": 1, 879 | "blockNode": null 880 | }, 881 | { 882 | "id": "7-10-52", 883 | "type": 13, 884 | "rolNum": 10, 885 | "rowNum": 52, 886 | "layerNum": 7, 887 | "moldType": 2, 888 | "blockNode": null 889 | }, 890 | { 891 | "id": "7-46-52", 892 | "type": 9, 893 | "rolNum": 46, 894 | "rowNum": 52, 895 | "layerNum": 7, 896 | "moldType": 2, 897 | "blockNode": null 898 | } 899 | ], 900 | "8": [ 901 | { 902 | "id": "8-24-8", 903 | "type": 8, 904 | "rolNum": 24, 905 | "rowNum": 8, 906 | "layerNum": 8, 907 | "moldType": 1, 908 | "blockNode": null 909 | }, 910 | { 911 | "id": "8-32-8", 912 | "type": 10, 913 | "rolNum": 32, 914 | "rowNum": 8, 915 | "layerNum": 8, 916 | "moldType": 1, 917 | "blockNode": null 918 | }, 919 | { 920 | "id": "8-28-16", 921 | "type": 7, 922 | "rolNum": 28, 923 | "rowNum": 16, 924 | "layerNum": 8, 925 | "moldType": 1, 926 | "blockNode": null 927 | }, 928 | { 929 | "id": "8-8-28", 930 | "type": 6, 931 | "rolNum": 8, 932 | "rowNum": 28, 933 | "layerNum": 8, 934 | "moldType": 1, 935 | "blockNode": null 936 | }, 937 | { 938 | "id": "8-8-36", 939 | "type": 13, 940 | "rolNum": 8, 941 | "rowNum": 36, 942 | "layerNum": 8, 943 | "moldType": 1, 944 | "blockNode": null 945 | }, 946 | { 947 | "id": "8-16-32", 948 | "type": 5, 949 | "rolNum": 16, 950 | "rowNum": 32, 951 | "layerNum": 8, 952 | "moldType": 1, 953 | "blockNode": null 954 | }, 955 | { 956 | "id": "8-40-28", 957 | "type": 3, 958 | "rolNum": 40, 959 | "rowNum": 28, 960 | "layerNum": 8, 961 | "moldType": 1, 962 | "blockNode": null 963 | }, 964 | { 965 | "id": "8-40-36", 966 | "type": 10, 967 | "rolNum": 40, 968 | "rowNum": 36, 969 | "layerNum": 8, 970 | "moldType": 1, 971 | "blockNode": null 972 | }, 973 | { 974 | "id": "8-48-32", 975 | "type": 3, 976 | "rolNum": 48, 977 | "rowNum": 32, 978 | "layerNum": 8, 979 | "moldType": 1, 980 | "blockNode": null 981 | }, 982 | { 983 | "id": "8-11-52", 984 | "type": 10, 985 | "rolNum": 11, 986 | "rowNum": 52, 987 | "layerNum": 8, 988 | "moldType": 2, 989 | "blockNode": null 990 | }, 991 | { 992 | "id": "8-45-52", 993 | "type": 11, 994 | "rolNum": 45, 995 | "rowNum": 52, 996 | "layerNum": 8, 997 | "moldType": 2, 998 | "blockNode": null 999 | } 1000 | ], 1001 | "9": [ 1002 | { 1003 | "id": "9-24-16", 1004 | "type": 12, 1005 | "rolNum": 24, 1006 | "rowNum": 16, 1007 | "layerNum": 9, 1008 | "moldType": 1, 1009 | "blockNode": null 1010 | }, 1011 | { 1012 | "id": "9-32-16", 1013 | "type": 11, 1014 | "rolNum": 32, 1015 | "rowNum": 16, 1016 | "layerNum": 9, 1017 | "moldType": 1, 1018 | "blockNode": null 1019 | }, 1020 | { 1021 | "id": "9-28-8", 1022 | "type": 11, 1023 | "rolNum": 28, 1024 | "rowNum": 8, 1025 | "layerNum": 9, 1026 | "moldType": 1, 1027 | "blockNode": null 1028 | }, 1029 | { 1030 | "id": "9-12-28", 1031 | "type": 14, 1032 | "rolNum": 12, 1033 | "rowNum": 28, 1034 | "layerNum": 9, 1035 | "moldType": 1, 1036 | "blockNode": null 1037 | }, 1038 | { 1039 | "id": "9-12-36", 1040 | "type": 12, 1041 | "rolNum": 12, 1042 | "rowNum": 36, 1043 | "layerNum": 9, 1044 | "moldType": 1, 1045 | "blockNode": null 1046 | }, 1047 | { 1048 | "id": "9-44-28", 1049 | "type": 7, 1050 | "rolNum": 44, 1051 | "rowNum": 28, 1052 | "layerNum": 9, 1053 | "moldType": 1, 1054 | "blockNode": null 1055 | }, 1056 | { 1057 | "id": "9-44-36", 1058 | "type": 11, 1059 | "rolNum": 44, 1060 | "rowNum": 36, 1061 | "layerNum": 9, 1062 | "moldType": 1, 1063 | "blockNode": null 1064 | }, 1065 | { 1066 | "id": "9-20-4", 1067 | "type": 10, 1068 | "rolNum": 20, 1069 | "rowNum": 4, 1070 | "layerNum": 9, 1071 | "moldType": 1, 1072 | "blockNode": null 1073 | }, 1074 | { 1075 | "id": "9-36-4", 1076 | "type": 8, 1077 | "rolNum": 36, 1078 | "rowNum": 4, 1079 | "layerNum": 9, 1080 | "moldType": 1, 1081 | "blockNode": null 1082 | }, 1083 | { 1084 | "id": "9-12-52", 1085 | "type": 2, 1086 | "rolNum": 12, 1087 | "rowNum": 52, 1088 | "layerNum": 9, 1089 | "moldType": 2, 1090 | "blockNode": null 1091 | }, 1092 | { 1093 | "id": "9-44-52", 1094 | "type": 13, 1095 | "rolNum": 44, 1096 | "rowNum": 52, 1097 | "layerNum": 9, 1098 | "moldType": 2, 1099 | "blockNode": null 1100 | } 1101 | ], 1102 | "10": [ 1103 | { 1104 | "id": "10-24-12", 1105 | "type": 1, 1106 | "rolNum": 24, 1107 | "rowNum": 12, 1108 | "layerNum": 10, 1109 | "moldType": 1, 1110 | "blockNode": null 1111 | }, 1112 | { 1113 | "id": "10-32-12", 1114 | "type": 6, 1115 | "rolNum": 32, 1116 | "rowNum": 12, 1117 | "layerNum": 10, 1118 | "moldType": 1, 1119 | "blockNode": null 1120 | }, 1121 | { 1122 | "id": "10-8-32", 1123 | "type": 12, 1124 | "rolNum": 8, 1125 | "rowNum": 32, 1126 | "layerNum": 10, 1127 | "moldType": 1, 1128 | "blockNode": null 1129 | }, 1130 | { 1131 | "id": "10-16-32", 1132 | "type": 12, 1133 | "rolNum": 16, 1134 | "rowNum": 32, 1135 | "layerNum": 10, 1136 | "moldType": 1, 1137 | "blockNode": null 1138 | }, 1139 | { 1140 | "id": "10-40-32", 1141 | "type": 1, 1142 | "rolNum": 40, 1143 | "rowNum": 32, 1144 | "layerNum": 10, 1145 | "moldType": 1, 1146 | "blockNode": null 1147 | }, 1148 | { 1149 | "id": "10-48-32", 1150 | "type": 11, 1151 | "rolNum": 48, 1152 | "rowNum": 32, 1153 | "layerNum": 10, 1154 | "moldType": 1, 1155 | "blockNode": null 1156 | }, 1157 | { 1158 | "id": "10-8-40", 1159 | "type": 12, 1160 | "rolNum": 8, 1161 | "rowNum": 40, 1162 | "layerNum": 10, 1163 | "moldType": 1, 1164 | "blockNode": null 1165 | }, 1166 | { 1167 | "id": "10-48-40", 1168 | "type": 11, 1169 | "rolNum": 48, 1170 | "rowNum": 40, 1171 | "layerNum": 10, 1172 | "moldType": 1, 1173 | "blockNode": null 1174 | }, 1175 | { 1176 | "id": "10-16-40", 1177 | "type": 9, 1178 | "rolNum": 16, 1179 | "rowNum": 40, 1180 | "layerNum": 10, 1181 | "moldType": 1, 1182 | "blockNode": null 1183 | }, 1184 | { 1185 | "id": "10-40-40", 1186 | "type": 4, 1187 | "rolNum": 40, 1188 | "rowNum": 40, 1189 | "layerNum": 10, 1190 | "moldType": 1, 1191 | "blockNode": null 1192 | }, 1193 | { 1194 | "id": "10-20-20", 1195 | "type": 7, 1196 | "rolNum": 20, 1197 | "rowNum": 20, 1198 | "layerNum": 10, 1199 | "moldType": 1, 1200 | "blockNode": null 1201 | }, 1202 | { 1203 | "id": "10-36-20", 1204 | "type": 1, 1205 | "rolNum": 36, 1206 | "rowNum": 20, 1207 | "layerNum": 10, 1208 | "moldType": 1, 1209 | "blockNode": null 1210 | }, 1211 | { 1212 | "id": "10-13-52", 1213 | "type": 3, 1214 | "rolNum": 13, 1215 | "rowNum": 52, 1216 | "layerNum": 10, 1217 | "moldType": 2, 1218 | "blockNode": null 1219 | }, 1220 | { 1221 | "id": "10-43-52", 1222 | "type": 7, 1223 | "rolNum": 43, 1224 | "rowNum": 52, 1225 | "layerNum": 10, 1226 | "moldType": 2, 1227 | "blockNode": null 1228 | } 1229 | ], 1230 | "11": [ 1231 | { 1232 | "id": "11-12-28", 1233 | "type": 3, 1234 | "rolNum": 12, 1235 | "rowNum": 28, 1236 | "layerNum": 11, 1237 | "moldType": 1, 1238 | "blockNode": null 1239 | }, 1240 | { 1241 | "id": "11-28-16", 1242 | "type": 8, 1243 | "rolNum": 28, 1244 | "rowNum": 16, 1245 | "layerNum": 11, 1246 | "moldType": 1, 1247 | "blockNode": null 1248 | }, 1249 | { 1250 | "id": "11-44-28", 1251 | "type": 8, 1252 | "rolNum": 44, 1253 | "rowNum": 28, 1254 | "layerNum": 11, 1255 | "moldType": 1, 1256 | "blockNode": null 1257 | }, 1258 | { 1259 | "id": "11-28-8", 1260 | "type": 5, 1261 | "rolNum": 28, 1262 | "rowNum": 8, 1263 | "layerNum": 11, 1264 | "moldType": 1, 1265 | "blockNode": null 1266 | }, 1267 | { 1268 | "id": "11-12-36", 1269 | "type": 2, 1270 | "rolNum": 12, 1271 | "rowNum": 36, 1272 | "layerNum": 11, 1273 | "moldType": 1, 1274 | "blockNode": null 1275 | }, 1276 | { 1277 | "id": "11-44-36", 1278 | "type": 14, 1279 | "rolNum": 44, 1280 | "rowNum": 36, 1281 | "layerNum": 11, 1282 | "moldType": 1, 1283 | "blockNode": null 1284 | }, 1285 | { 1286 | "id": "11-20-12", 1287 | "type": 4, 1288 | "rolNum": 20, 1289 | "rowNum": 12, 1290 | "layerNum": 11, 1291 | "moldType": 1, 1292 | "blockNode": null 1293 | }, 1294 | { 1295 | "id": "11-36-12", 1296 | "type": 2, 1297 | "rolNum": 36, 1298 | "rowNum": 12, 1299 | "layerNum": 11, 1300 | "moldType": 1, 1301 | "blockNode": null 1302 | }, 1303 | { 1304 | "id": "11-14-52", 1305 | "type": 5, 1306 | "rolNum": 14, 1307 | "rowNum": 52, 1308 | "layerNum": 11, 1309 | "moldType": 2, 1310 | "blockNode": null 1311 | }, 1312 | { 1313 | "id": "11-42-52", 1314 | "type": 10, 1315 | "rolNum": 42, 1316 | "rowNum": 52, 1317 | "layerNum": 11, 1318 | "moldType": 2, 1319 | "blockNode": null 1320 | } 1321 | ], 1322 | "12": [ 1323 | { 1324 | "id": "12-28-20", 1325 | "type": 7, 1326 | "rolNum": 28, 1327 | "rowNum": 20, 1328 | "layerNum": 12, 1329 | "moldType": 1, 1330 | "blockNode": null 1331 | }, 1332 | { 1333 | "id": "12-8-32", 1334 | "type": 3, 1335 | "rolNum": 8, 1336 | "rowNum": 32, 1337 | "layerNum": 12, 1338 | "moldType": 1, 1339 | "blockNode": null 1340 | }, 1341 | { 1342 | "id": "12-16-32", 1343 | "type": 4, 1344 | "rolNum": 16, 1345 | "rowNum": 32, 1346 | "layerNum": 12, 1347 | "moldType": 1, 1348 | "blockNode": null 1349 | }, 1350 | { 1351 | "id": "12-8-40", 1352 | "type": 1, 1353 | "rolNum": 8, 1354 | "rowNum": 40, 1355 | "layerNum": 12, 1356 | "moldType": 1, 1357 | "blockNode": null 1358 | }, 1359 | { 1360 | "id": "12-16-40", 1361 | "type": 8, 1362 | "rolNum": 16, 1363 | "rowNum": 40, 1364 | "layerNum": 12, 1365 | "moldType": 1, 1366 | "blockNode": null 1367 | }, 1368 | { 1369 | "id": "12-40-32", 1370 | "type": 10, 1371 | "rolNum": 40, 1372 | "rowNum": 32, 1373 | "layerNum": 12, 1374 | "moldType": 1, 1375 | "blockNode": null 1376 | }, 1377 | { 1378 | "id": "12-48-32", 1379 | "type": 8, 1380 | "rolNum": 48, 1381 | "rowNum": 32, 1382 | "layerNum": 12, 1383 | "moldType": 1, 1384 | "blockNode": null 1385 | }, 1386 | { 1387 | "id": "12-40-40", 1388 | "type": 3, 1389 | "rolNum": 40, 1390 | "rowNum": 40, 1391 | "layerNum": 12, 1392 | "moldType": 1, 1393 | "blockNode": null 1394 | }, 1395 | { 1396 | "id": "12-48-40", 1397 | "type": 1, 1398 | "rolNum": 48, 1399 | "rowNum": 40, 1400 | "layerNum": 12, 1401 | "moldType": 1, 1402 | "blockNode": null 1403 | }, 1404 | { 1405 | "id": "12-16-8", 1406 | "type": 2, 1407 | "rolNum": 16, 1408 | "rowNum": 8, 1409 | "layerNum": 12, 1410 | "moldType": 1, 1411 | "blockNode": null 1412 | }, 1413 | { 1414 | "id": "12-24-8", 1415 | "type": 4, 1416 | "rolNum": 24, 1417 | "rowNum": 8, 1418 | "layerNum": 12, 1419 | "moldType": 1, 1420 | "blockNode": null 1421 | }, 1422 | { 1423 | "id": "12-32-8", 1424 | "type": 13, 1425 | "rolNum": 32, 1426 | "rowNum": 8, 1427 | "layerNum": 12, 1428 | "moldType": 1, 1429 | "blockNode": null 1430 | }, 1431 | { 1432 | "id": "12-40-8", 1433 | "type": 6, 1434 | "rolNum": 40, 1435 | "rowNum": 8, 1436 | "layerNum": 12, 1437 | "moldType": 1, 1438 | "blockNode": null 1439 | }, 1440 | { 1441 | "id": "12-15-52", 1442 | "type": 1, 1443 | "rolNum": 15, 1444 | "rowNum": 52, 1445 | "layerNum": 12, 1446 | "moldType": 2, 1447 | "blockNode": null 1448 | }, 1449 | { 1450 | "id": "12-41-52", 1451 | "type": 8, 1452 | "rolNum": 41, 1453 | "rowNum": 52, 1454 | "layerNum": 12, 1455 | "moldType": 2, 1456 | "blockNode": null 1457 | } 1458 | ], 1459 | "13": [ 1460 | { 1461 | "id": "13-28-16", 1462 | "type": 8, 1463 | "rolNum": 28, 1464 | "rowNum": 16, 1465 | "layerNum": 13, 1466 | "moldType": 1, 1467 | "blockNode": null 1468 | }, 1469 | { 1470 | "id": "13-12-28", 1471 | "type": 4, 1472 | "rolNum": 12, 1473 | "rowNum": 28, 1474 | "layerNum": 13, 1475 | "moldType": 1, 1476 | "blockNode": null 1477 | }, 1478 | { 1479 | "id": "13-12-36", 1480 | "type": 2, 1481 | "rolNum": 12, 1482 | "rowNum": 36, 1483 | "layerNum": 13, 1484 | "moldType": 1, 1485 | "blockNode": null 1486 | }, 1487 | { 1488 | "id": "13-44-28", 1489 | "type": 14, 1490 | "rolNum": 44, 1491 | "rowNum": 28, 1492 | "layerNum": 13, 1493 | "moldType": 1, 1494 | "blockNode": null 1495 | }, 1496 | { 1497 | "id": "13-44-36", 1498 | "type": 10, 1499 | "rolNum": 44, 1500 | "rowNum": 36, 1501 | "layerNum": 13, 1502 | "moldType": 1, 1503 | "blockNode": null 1504 | }, 1505 | { 1506 | "id": "13-4-40", 1507 | "type": 10, 1508 | "rolNum": 4, 1509 | "rowNum": 40, 1510 | "layerNum": 13, 1511 | "moldType": 1, 1512 | "blockNode": null 1513 | }, 1514 | { 1515 | "id": "13-52-40", 1516 | "type": 1, 1517 | "rolNum": 52, 1518 | "rowNum": 40, 1519 | "layerNum": 13, 1520 | "moldType": 1, 1521 | "blockNode": null 1522 | }, 1523 | { 1524 | "id": "13-20-40", 1525 | "type": 12, 1526 | "rolNum": 20, 1527 | "rowNum": 40, 1528 | "layerNum": 13, 1529 | "moldType": 1, 1530 | "blockNode": null 1531 | }, 1532 | { 1533 | "id": "13-36-40", 1534 | "type": 6, 1535 | "rolNum": 36, 1536 | "rowNum": 40, 1537 | "layerNum": 13, 1538 | "moldType": 1, 1539 | "blockNode": null 1540 | }, 1541 | { 1542 | "id": "13-16-52", 1543 | "type": 9, 1544 | "rolNum": 16, 1545 | "rowNum": 52, 1546 | "layerNum": 13, 1547 | "moldType": 2, 1548 | "blockNode": null 1549 | }, 1550 | { 1551 | "id": "13-40-52", 1552 | "type": 12, 1553 | "rolNum": 40, 1554 | "rowNum": 52, 1555 | "layerNum": 13, 1556 | "moldType": 2, 1557 | "blockNode": null 1558 | }, 1559 | { 1560 | "id": "13-12-12", 1561 | "type": 2, 1562 | "rolNum": 12, 1563 | "rowNum": 12, 1564 | "layerNum": 13, 1565 | "moldType": 1, 1566 | "blockNode": null 1567 | }, 1568 | { 1569 | "id": "13-20-12", 1570 | "type": 9, 1571 | "rolNum": 20, 1572 | "rowNum": 12, 1573 | "layerNum": 13, 1574 | "moldType": 1, 1575 | "blockNode": null 1576 | }, 1577 | { 1578 | "id": "13-36-12", 1579 | "type": 10, 1580 | "rolNum": 36, 1581 | "rowNum": 12, 1582 | "layerNum": 13, 1583 | "moldType": 1, 1584 | "blockNode": null 1585 | }, 1586 | { 1587 | "id": "13-44-12", 1588 | "type": 7, 1589 | "rolNum": 44, 1590 | "rowNum": 12, 1591 | "layerNum": 13, 1592 | "moldType": 1, 1593 | "blockNode": null 1594 | } 1595 | ], 1596 | "14": [ 1597 | { 1598 | "id": "14-8-32", 1599 | "type": 8, 1600 | "rolNum": 8, 1601 | "rowNum": 32, 1602 | "layerNum": 14, 1603 | "moldType": 1, 1604 | "blockNode": null 1605 | }, 1606 | { 1607 | "id": "14-16-32", 1608 | "type": 5, 1609 | "rolNum": 16, 1610 | "rowNum": 32, 1611 | "layerNum": 14, 1612 | "moldType": 1, 1613 | "blockNode": null 1614 | }, 1615 | { 1616 | "id": "14-12-40", 1617 | "type": 4, 1618 | "rolNum": 12, 1619 | "rowNum": 40, 1620 | "layerNum": 14, 1621 | "moldType": 1, 1622 | "blockNode": null 1623 | }, 1624 | { 1625 | "id": "14-40-32", 1626 | "type": 4, 1627 | "rolNum": 40, 1628 | "rowNum": 32, 1629 | "layerNum": 14, 1630 | "moldType": 1, 1631 | "blockNode": null 1632 | }, 1633 | { 1634 | "id": "14-48-32", 1635 | "type": 4, 1636 | "rolNum": 48, 1637 | "rowNum": 32, 1638 | "layerNum": 14, 1639 | "moldType": 1, 1640 | "blockNode": null 1641 | }, 1642 | { 1643 | "id": "14-44-40", 1644 | "type": 10, 1645 | "rolNum": 44, 1646 | "rowNum": 40, 1647 | "layerNum": 14, 1648 | "moldType": 1, 1649 | "blockNode": null 1650 | }, 1651 | { 1652 | "id": "14-28-20", 1653 | "type": 5, 1654 | "rolNum": 28, 1655 | "rowNum": 20, 1656 | "layerNum": 14, 1657 | "moldType": 1, 1658 | "blockNode": null 1659 | }, 1660 | { 1661 | "id": "14-24-40", 1662 | "type": 10, 1663 | "rolNum": 24, 1664 | "rowNum": 40, 1665 | "layerNum": 14, 1666 | "moldType": 1, 1667 | "blockNode": null 1668 | }, 1669 | { 1670 | "id": "14-32-40", 1671 | "type": 3, 1672 | "rolNum": 32, 1673 | "rowNum": 40, 1674 | "layerNum": 14, 1675 | "moldType": 1, 1676 | "blockNode": null 1677 | } 1678 | ], 1679 | "15": [ 1680 | { 1681 | "id": "15-8-28", 1682 | "type": 4, 1683 | "rolNum": 8, 1684 | "rowNum": 28, 1685 | "layerNum": 15, 1686 | "moldType": 1, 1687 | "blockNode": null 1688 | }, 1689 | { 1690 | "id": "15-16-28", 1691 | "type": 2, 1692 | "rolNum": 16, 1693 | "rowNum": 28, 1694 | "layerNum": 15, 1695 | "moldType": 1, 1696 | "blockNode": null 1697 | }, 1698 | { 1699 | "id": "15-12-36", 1700 | "type": 5, 1701 | "rolNum": 12, 1702 | "rowNum": 36, 1703 | "layerNum": 15, 1704 | "moldType": 1, 1705 | "blockNode": null 1706 | }, 1707 | { 1708 | "id": "15-40-28", 1709 | "type": 3, 1710 | "rolNum": 40, 1711 | "rowNum": 28, 1712 | "layerNum": 15, 1713 | "moldType": 1, 1714 | "blockNode": null 1715 | }, 1716 | { 1717 | "id": "15-48-28", 1718 | "type": 12, 1719 | "rolNum": 48, 1720 | "rowNum": 28, 1721 | "layerNum": 15, 1722 | "moldType": 1, 1723 | "blockNode": null 1724 | }, 1725 | { 1726 | "id": "15-44-36", 1727 | "type": 7, 1728 | "rolNum": 44, 1729 | "rowNum": 36, 1730 | "layerNum": 15, 1731 | "moldType": 1, 1732 | "blockNode": null 1733 | }, 1734 | { 1735 | "id": "15-28-24", 1736 | "type": 1, 1737 | "rolNum": 28, 1738 | "rowNum": 24, 1739 | "layerNum": 15, 1740 | "moldType": 1, 1741 | "blockNode": null 1742 | }, 1743 | { 1744 | "id": "15-28-16", 1745 | "type": 14, 1746 | "rolNum": 28, 1747 | "rowNum": 16, 1748 | "layerNum": 15, 1749 | "moldType": 1, 1750 | "blockNode": null 1751 | } 1752 | ], 1753 | "16": [ 1754 | { 1755 | "id": "16-12-32", 1756 | "type": 7, 1757 | "rolNum": 12, 1758 | "rowNum": 32, 1759 | "layerNum": 16, 1760 | "moldType": 1, 1761 | "blockNode": null 1762 | }, 1763 | { 1764 | "id": "16-44-32", 1765 | "type": 8, 1766 | "rolNum": 44, 1767 | "rowNum": 32, 1768 | "layerNum": 16, 1769 | "moldType": 1, 1770 | "blockNode": null 1771 | }, 1772 | { 1773 | "id": "16-28-28", 1774 | "type": 1, 1775 | "rolNum": 28, 1776 | "rowNum": 28, 1777 | "layerNum": 16, 1778 | "moldType": 1, 1779 | "blockNode": null 1780 | }, 1781 | { 1782 | "id": "16-4-24", 1783 | "type": 3, 1784 | "rolNum": 4, 1785 | "rowNum": 24, 1786 | "layerNum": 16, 1787 | "moldType": 1, 1788 | "blockNode": null 1789 | }, 1790 | { 1791 | "id": "16-4-32", 1792 | "type": 1, 1793 | "rolNum": 4, 1794 | "rowNum": 32, 1795 | "layerNum": 16, 1796 | "moldType": 1, 1797 | "blockNode": null 1798 | }, 1799 | { 1800 | "id": "16-52-24", 1801 | "type": 10, 1802 | "rolNum": 52, 1803 | "rowNum": 24, 1804 | "layerNum": 16, 1805 | "moldType": 1, 1806 | "blockNode": null 1807 | }, 1808 | { 1809 | "id": "16-52-32", 1810 | "type": 5, 1811 | "rolNum": 52, 1812 | "rowNum": 32, 1813 | "layerNum": 16, 1814 | "moldType": 1, 1815 | "blockNode": null 1816 | }, 1817 | { 1818 | "id": "16-12-40", 1819 | "type": 14, 1820 | "rolNum": 12, 1821 | "rowNum": 40, 1822 | "layerNum": 16, 1823 | "moldType": 1, 1824 | "blockNode": null 1825 | }, 1826 | { 1827 | "id": "16-44-40", 1828 | "type": 9, 1829 | "rolNum": 44, 1830 | "rowNum": 40, 1831 | "layerNum": 16, 1832 | "moldType": 1, 1833 | "blockNode": null 1834 | } 1835 | ], 1836 | "17": [ 1837 | { 1838 | "id": "17-16-32", 1839 | "type": 13, 1840 | "rolNum": 16, 1841 | "rowNum": 32, 1842 | "layerNum": 17, 1843 | "moldType": 1, 1844 | "blockNode": null 1845 | }, 1846 | { 1847 | "id": "17-40-32", 1848 | "type": 14, 1849 | "rolNum": 40, 1850 | "rowNum": 32, 1851 | "layerNum": 17, 1852 | "moldType": 1, 1853 | "blockNode": null 1854 | }, 1855 | { 1856 | "id": "17-28-32", 1857 | "type": 4, 1858 | "rolNum": 28, 1859 | "rowNum": 32, 1860 | "layerNum": 17, 1861 | "moldType": 1, 1862 | "blockNode": null 1863 | }, 1864 | { 1865 | "id": "17-28-24", 1866 | "type": 10, 1867 | "rolNum": 28, 1868 | "rowNum": 24, 1869 | "layerNum": 17, 1870 | "moldType": 1, 1871 | "blockNode": null 1872 | } 1873 | ], 1874 | "18": [ 1875 | { 1876 | "id": "18-20-32", 1877 | "type": 9, 1878 | "rolNum": 20, 1879 | "rowNum": 32, 1880 | "layerNum": 18, 1881 | "moldType": 1, 1882 | "blockNode": null 1883 | }, 1884 | { 1885 | "id": "18-36-32", 1886 | "type": 2, 1887 | "rolNum": 36, 1888 | "rowNum": 32, 1889 | "layerNum": 18, 1890 | "moldType": 1, 1891 | "blockNode": null 1892 | }, 1893 | { 1894 | "id": "18-12-28", 1895 | "type": 6, 1896 | "rolNum": 12, 1897 | "rowNum": 28, 1898 | "layerNum": 18, 1899 | "moldType": 1, 1900 | "blockNode": null 1901 | }, 1902 | { 1903 | "id": "18-44-28", 1904 | "type": 2, 1905 | "rolNum": 44, 1906 | "rowNum": 28, 1907 | "layerNum": 18, 1908 | "moldType": 1, 1909 | "blockNode": null 1910 | } 1911 | ], 1912 | "19": [ 1913 | { 1914 | "id": "19-20-28", 1915 | "type": 5, 1916 | "rolNum": 20, 1917 | "rowNum": 28, 1918 | "layerNum": 19, 1919 | "moldType": 1, 1920 | "blockNode": null 1921 | }, 1922 | { 1923 | "id": "19-36-28", 1924 | "type": 3, 1925 | "rolNum": 36, 1926 | "rowNum": 28, 1927 | "layerNum": 19, 1928 | "moldType": 1, 1929 | "blockNode": null 1930 | }, 1931 | { 1932 | "id": "19-8-24", 1933 | "type": 4, 1934 | "rolNum": 8, 1935 | "rowNum": 24, 1936 | "layerNum": 19, 1937 | "moldType": 1, 1938 | "blockNode": null 1939 | }, 1940 | { 1941 | "id": "19-8-32", 1942 | "type": 13, 1943 | "rolNum": 8, 1944 | "rowNum": 32, 1945 | "layerNum": 19, 1946 | "moldType": 1, 1947 | "blockNode": null 1948 | }, 1949 | { 1950 | "id": "19-48-24", 1951 | "type": 8, 1952 | "rolNum": 48, 1953 | "rowNum": 24, 1954 | "layerNum": 19, 1955 | "moldType": 1, 1956 | "blockNode": null 1957 | }, 1958 | { 1959 | "id": "19-48-32", 1960 | "type": 8, 1961 | "rolNum": 48, 1962 | "rowNum": 32, 1963 | "layerNum": 19, 1964 | "moldType": 1, 1965 | "blockNode": null 1966 | } 1967 | ], 1968 | "20": [ 1969 | { 1970 | "id": "20-16-32", 1971 | "type": 14, 1972 | "rolNum": 16, 1973 | "rowNum": 32, 1974 | "layerNum": 20, 1975 | "moldType": 1, 1976 | "blockNode": null 1977 | }, 1978 | { 1979 | "id": "20-24-32", 1980 | "type": 14, 1981 | "rolNum": 24, 1982 | "rowNum": 32, 1983 | "layerNum": 20, 1984 | "moldType": 1, 1985 | "blockNode": null 1986 | }, 1987 | { 1988 | "id": "20-32-32", 1989 | "type": 5, 1990 | "rolNum": 32, 1991 | "rowNum": 32, 1992 | "layerNum": 20, 1993 | "moldType": 1, 1994 | "blockNode": null 1995 | }, 1996 | { 1997 | "id": "20-40-32", 1998 | "type": 11, 1999 | "rolNum": 40, 2000 | "rowNum": 32, 2001 | "layerNum": 20, 2002 | "moldType": 1, 2003 | "blockNode": null 2004 | }, 2005 | { 2006 | "id": "20-12-20", 2007 | "type": 14, 2008 | "rolNum": 12, 2009 | "rowNum": 20, 2010 | "layerNum": 20, 2011 | "moldType": 1, 2012 | "blockNode": null 2013 | }, 2014 | { 2015 | "id": "20-44-20", 2016 | "type": 7, 2017 | "rolNum": 44, 2018 | "rowNum": 20, 2019 | "layerNum": 20, 2020 | "moldType": 1, 2021 | "blockNode": null 2022 | } 2023 | ], 2024 | "21": [ 2025 | { 2026 | "id": "21-12-28", 2027 | "type": 7, 2028 | "rolNum": 12, 2029 | "rowNum": 28, 2030 | "layerNum": 21, 2031 | "moldType": 1, 2032 | "blockNode": null 2033 | }, 2034 | { 2035 | "id": "21-20-28", 2036 | "type": 6, 2037 | "rolNum": 20, 2038 | "rowNum": 28, 2039 | "layerNum": 21, 2040 | "moldType": 1, 2041 | "blockNode": null 2042 | }, 2043 | { 2044 | "id": "21-36-28", 2045 | "type": 2, 2046 | "rolNum": 36, 2047 | "rowNum": 28, 2048 | "layerNum": 21, 2049 | "moldType": 1, 2050 | "blockNode": null 2051 | }, 2052 | { 2053 | "id": "21-44-28", 2054 | "type": 9, 2055 | "rolNum": 44, 2056 | "rowNum": 28, 2057 | "layerNum": 21, 2058 | "moldType": 1, 2059 | "blockNode": null 2060 | } 2061 | ] 2062 | }, 2063 | "layers": [ 2064 | "1", 2065 | "2", 2066 | "3", 2067 | "4", 2068 | "5", 2069 | "6", 2070 | "7", 2071 | "8", 2072 | "9", 2073 | "10", 2074 | "11", 2075 | "12", 2076 | "13", 2077 | "14", 2078 | "15", 2079 | "16", 2080 | "17", 2081 | "18", 2082 | "19", 2083 | "20", 2084 | "21" 2085 | ], 2086 | "operations": [ 2087 | "21-12-28", 2088 | "20-44-20", 2089 | "13-44-12", 2090 | "21-44-28", 2091 | "16-44-40", 2092 | "13-20-12", 2093 | "17-28-24", 2094 | "14-24-40", 2095 | "13-36-12", 2096 | "21-20-28", 2097 | "12-40-8", 2098 | "5-48-16", 2099 | "20-16-32", 2100 | "20-24-32", 2101 | "20-12-20", 2102 | "21-36-28", 2103 | "13-12-12", 2104 | "12-16-8", 2105 | "19-8-24", 2106 | "12-24-8", 2107 | "11-20-12", 2108 | "16-4-24", 2109 | "14-32-40", 2110 | "4-4-0", 2111 | "13-52-40", 2112 | "10-36-20", 2113 | "5-8-8", 2114 | "13-36-40", 2115 | "4-52-16", 2116 | "3-12-4", 2117 | "5-48-8", 2118 | "4-4-8", 2119 | "3-44-4", 2120 | "19-8-32", 2121 | "12-32-8", 2122 | "4-52-8", 2123 | "20-32-32", 2124 | "19-20-28", 2125 | "11-28-8", 2126 | "19-48-24", 2127 | "19-48-32", 2128 | "9-36-4", 2129 | "16-52-24", 2130 | "13-4-40", 2131 | "9-20-4", 2132 | "16-4-32", 2133 | "2-28-0", 2134 | "2-16-0", 2135 | "20-40-32", 2136 | "4-52-0", 2137 | "1-32-0", 2138 | "19-36-28", 2139 | "3-4-4", 2140 | "3-44-12", 2141 | "18-44-28", 2142 | "18-36-32", 2143 | "11-36-12", 2144 | "18-20-32", 2145 | "13-16-52", 2146 | "2-8-0", 2147 | "17-40-32", 2148 | "16-12-40", 2149 | "15-28-16", 2150 | "13-20-40", 2151 | "13-40-52", 2152 | "1-24-0", 2153 | "16-44-32", 2154 | "5-8-16", 2155 | "12-41-52", 2156 | "15-44-36", 2157 | "11-42-52", 2158 | "3-52-4", 2159 | "14-44-40", 2160 | "3-52-12", 2161 | "10-43-52", 2162 | "2-28-40", 2163 | "2-48-8", 2164 | "17-28-32", 2165 | "3-12-12", 2166 | "16-28-28", 2167 | "15-28-24", 2168 | "12-15-52", 2169 | "11-14-52", 2170 | "15-40-28", 2171 | "10-13-52", 2172 | "16-52-32", 2173 | "9-12-52", 2174 | "14-28-20", 2175 | "15-48-28", 2176 | "14-40-32", 2177 | "14-48-32", 2178 | "8-11-52", 2179 | "9-44-52", 2180 | "7-10-52", 2181 | "1-24-40", 2182 | "18-12-28", 2183 | "17-16-32", 2184 | "4-4-16", 2185 | "3-4-12", 2186 | "1-32-40", 2187 | "16-12-32", 2188 | "2-8-8", 2189 | "10-20-20", 2190 | "13-44-36", 2191 | "13-44-28", 2192 | "12-40-32", 2193 | "15-12-36", 2194 | "6-9-52", 2195 | "1-4-4", 2196 | "5-8-52", 2197 | "15-8-28", 2198 | "1-12-4", 2199 | "12-48-32", 2200 | "13-28-16", 2201 | "14-8-32", 2202 | "14-12-40", 2203 | "2-40-0", 2204 | "2-48-0", 2205 | "1-12-12", 2206 | "8-45-52", 2207 | "12-28-20", 2208 | "12-48-40", 2209 | "4-7-52", 2210 | "1-52-12", 2211 | "12-40-40", 2212 | "11-44-36", 2213 | "3-6-52", 2214 | "2-5-52", 2215 | "10-48-40", 2216 | "7-46-52", 2217 | "1-4-52", 2218 | "1-52-4", 2219 | "15-16-28", 2220 | "14-16-32", 2221 | "13-12-36", 2222 | "1-44-20", 2223 | "13-12-28", 2224 | "12-8-32", 2225 | "6-47-52", 2226 | "11-44-28", 2227 | "11-28-16", 2228 | "12-16-40", 2229 | "10-32-12", 2230 | "12-16-32", 2231 | "10-40-40", 2232 | "10-24-12", 2233 | "12-8-40", 2234 | "10-40-32", 2235 | "10-48-32", 2236 | "9-28-8", 2237 | "9-44-36", 2238 | "9-44-28", 2239 | "8-48-32", 2240 | "11-12-28", 2241 | "11-12-36", 2242 | "8-40-28", 2243 | "10-8-32", 2244 | "10-16-32", 2245 | "10-8-40", 2246 | "9-12-28", 2247 | "8-8-28", 2248 | "1-44-4", 2249 | "9-32-16", 2250 | "7-48-28", 2251 | "1-44-12", 2252 | "8-32-8", 2253 | "8-40-36", 2254 | "7-40-32", 2255 | "6-44-28", 2256 | "8-24-8", 2257 | "1-4-12", 2258 | "10-16-40", 2259 | "5-48-52", 2260 | "7-28-8", 2261 | "9-12-36", 2262 | "8-16-32", 2263 | "9-24-16", 2264 | "7-16-28", 2265 | "5-48-28", 2266 | "8-8-36", 2267 | "7-16-36", 2268 | "7-8-32", 2269 | "6-12-36", 2270 | "8-28-16", 2271 | "7-32-16", 2272 | "6-32-12", 2273 | "7-24-16", 2274 | "5-8-36", 2275 | "7-48-36", 2276 | "6-12-28", 2277 | "6-24-12", 2278 | "6-44-36", 2279 | "5-24-8", 2280 | "5-40-36", 2281 | "4-44-32", 2282 | "3-48-36", 2283 | "5-32-16", 2284 | "4-28-12", 2285 | "3-32-8", 2286 | "3-40-28", 2287 | "2-44-28", 2288 | "3-24-16", 2289 | "1-48-28", 2290 | "5-16-28", 2291 | "4-12-32", 2292 | "3-8-28", 2293 | "2-32-12", 2294 | "4-49-52", 2295 | "3-50-52", 2296 | "2-24-12", 2297 | "2-51-52", 2298 | "3-16-36", 2299 | "2-12-36", 2300 | "1-32-16", 2301 | "2-44-36", 2302 | "2-12-28", 2303 | "1-16-28", 2304 | "1-12-20", 2305 | "1-24-8", 2306 | "1-40-36", 2307 | "1-8-36", 2308 | "1-52-52" 2309 | ] 2310 | }; --------------------------------------------------------------------------------