diff --git a/roles/host.py b/roles/host.py index 73a9d98cdd0ddae5aa1e12e423481db3461010af..0471074fa6c764de8eea94955588bf678e37adeb 100644 --- a/roles/host.py +++ b/roles/host.py @@ -89,6 +89,16 @@ class Host(object): else: return {'status': 'error'} + def save_solution(self, problem_key): + + problem = self.get_problem(problem_key) + + if problem is not None: + problem.save_best_solution() + return {'status': 'saved'} + else: + return {'status': 'failed'} + def get_request_status(self, request_id): if request_id in self.request: return self.request[request_id].get_status() @@ -122,6 +132,9 @@ class Host(object): elif cmd == 'problem/solution': self.store_solution(params) return {'status': 'received'} + elif cmd == 'problem/save': + problem_key = params['problem'] + return self.save_solution(problem_key) elif cmd == 'request/status': request_id = float(params['request_id']) return self.get_request_status(request_id) diff --git a/static/css/adc2019.css b/static/css/adc2019.css index e0955e8fe57ebb8e8d294b766d69e0da90f69b7f..e070961ff193c0f21a59f23c4760696767f76ed0 100644 --- a/static/css/adc2019.css +++ b/static/css/adc2019.css @@ -60,16 +60,16 @@ body{ display: inline-block; } -#client-control-pane tr.solution-detail-row, -#client-control-pane tr.solution-detail-row td{ +#solution-list-container tr.solution-detail-row, +#solution-list-container tr.solution-detail-row td{ cursor: pointer; } -#client-control-pane tr.solution-detail-row:hover{ +#solution-list-container tr.solution-detail-row:hover{ background-color: rgba(200, 100, 100, .15); } -#client-control-pane tr.solution-detail-row.submit-answer{ +#solution-list-container tr.solution-detail-row.submit-solution{ background-color: rgba(100, 200, 100, .3); } diff --git a/static/js/adc2019.js b/static/js/adc2019.js index 72d16c66c5d354da644ca149c48c847f5708e4f6..347f992d5bb74989466b3290328148521e4a34b7 100644 --- a/static/js/adc2019.js +++ b/static/js/adc2019.js @@ -26,6 +26,10 @@ class StatusView { _this.container.find('.start-button').click(()=>{ _this.start_solver(); }); + + _this.container.find('.save-button').click(()=>{ + _this.save_solution(); + }); _this.container.find('.solution-detail-row td').click((e) => { var solution_id = $(e.target).parent("tr").data("solution-id"); @@ -83,6 +87,23 @@ class StatusView { alert(d); }); } + + // 保存 + save_solution(){ + var _this = this; + + $.ajax({ + type: "POST", + dataType: "json", + url: "/api/problem/save", + data: JSON.stringify({ + "problem": _this.problem_key + }), + contentType: 'application/json' + }).done((d) => { + _this.show_problem(); + }); + } get_request_status(request_id, timeout){ var _this = this; diff --git a/templates/part_problem_status.html b/templates/part_problem_status.html index e3565ac799b766854ccc5ea5b8522969d6b5e6fc..5a74f4f0e79fe01f290e06b5bea6dfbb33f84410 100644 --- a/templates/part_problem_status.html +++ b/templates/part_problem_status.html @@ -22,11 +22,11 @@ {% for k, v in problem.get_solutions().items() %} - {#% if (qdata.best_json == k) and (v.answer != "") %#} - - {#% else %#} + {% if k == problem.best_solution %} + + {% else %} - {#% endif %#} + {% endif %} {{v.timestamp_str}} {{v.worker}} diff --git a/utils/data.py b/utils/data.py index e83a6f639e04ce5941d9889a585deb7b5db786a2..6641d4e2ec951432c51d57f0e82e0a3116c6fde9 100644 --- a/utils/data.py +++ b/utils/data.py @@ -18,6 +18,7 @@ class Problem(object): self.status = 'Ready' self.solutions = dict() self.solution_path = solution_path + self.best_solution = None self._load_problem(problem_path) @@ -105,6 +106,33 @@ class Problem(object): # Save solution solution.save(self.solution_path) + + def save_best_solution(self): + + best_score = None + for k, v in self.solutions.items(): + if v.is_valid_solution(): + _score = v.score + if (best_score is None) or (_score < best_score[1]): + best_score = (k, _score) + + if best_score is not None: + + solution_name = self.name + outpath = f'{self.solution_path}/submit' + + if not os.path.exists(outpath): + os.mkdir(outpath) + + best_solution_key = best_score[0] + + with open(f'{outpath}/{solution_name}.txt', 'w') as fp: + fp.write(self.solutions[best_solution_key].solution) + + with open(f'{outpath}/{solution_name}.json', 'w') as fp: + json.dump(self.solutions[best_solution_key].get_dict(), fp, indent=4) + + self.best_solution = best_solution_key def get_solutions(self): return self.solutions @@ -124,26 +152,21 @@ class Solution(object): self.worker = data['worker'] self.elapsed_time = data['elapsed_time'] self.solution = data['solution'] + self.status = data['status'] + self.size = (None, None) + self.map = None + self.block = dict() self.timestamp = time.time() self._id = str(uuid.uuid4()) - - def get_id(self): - return self._id - - def get_dict(self): - return { - 'id': self._id, - 'timestamp': self.timestamp, - 'request_id': self.request_id, - 'worker': self.worker, - 'elapsed_time': self.elapsed_time, - 'problem': self.problem, - 'solution': self.solution - } - - def get_d3json(self): - + + self._parse_solution() + + def _parse_solution(self): + + if self.status != 'done': + return + board_size = [0, 0] block_num = 0 @@ -155,9 +178,11 @@ class Solution(object): bmap = list() bposition = dict() + state = 0 + while li < len(_lines): _l = _lines[li].strip() - if 'SIZE' in _l: + if (state == 0) and ('SIZE' in _l): board_size_str = _l.strip().split()[1] board_solution_size = [int(v) for v in board_size_str.split('X')] bw = board_solution_size[0] @@ -166,7 +191,8 @@ class Solution(object): li += 1 _l = _lines[li].strip() bmap.append([int(v.strip()) for v in _l.split(',')]) - if 'BLOCK' in _l: + state = 1 + if (state == 1) and ('BLOCK' in _l): p = r'BLOCK#([0-9]+) +@\(([0-9]+), *([0-9]+)\)' m = re.match(p, _l.strip()) bi = int(m.group(1)) @@ -177,16 +203,55 @@ class Solution(object): 'x': bx, 'y': by, } + state = 2 li += 1 + self.size = (bw, bh) + self.map = bmap + self.block = bposition + + @property + def score(self): + if (len(self.size) == 2) and (self.size[0] is not None) and (self.size[1] is not None): + return self.size[0] * self.size[1] + else: + return None + + def is_valid_solution(self): + return self.status == 'done' + + def get_id(self): + return self._id + + def get_dict(self): return { - 'w': bw, - 'h': bh, - 'map': bmap, - 'block': bposition + 'id': self._id, + 'timestamp': self.timestamp, + 'request_id': self.request_id, + 'worker': self.worker, + 'elapsed_time': self.elapsed_time, + 'problem': self.problem, + 'solution': self.solution } + def get_d3json(self): + + if self.state == 'done': + return { + 'w': self.size[0], + 'h': self.size[1], + 'map': self.map, + 'block': self.block + } + else: + return { + 'w': 0, + 'h': 0, + 'map': [[]], + 'block': dict() + } + def save(self, basedir): outdir = f"{basedir}/{self.problem}" if not os.path.exists(outdir):