Python Conference Japan 2012 に参加していたのですが、会場で開催されていた Top of Pythonista 決定戦で一位になりました。
Rubyプログラマなのに...
Pythonは学生時代に勉強しながら、アルバイト先のユーティリティ作成や卒研の実装とかをしていたのですが、社会人になってから一回ちょっとしたユーティリティを書いた以外ではほとんど使わず、勉強もおろそかにしていて柴田さんのみんPyぐらいしか読んでないような状態でした。
というわけで、かれこれ6年ぶりぐらいの本気のPythonプログラミングでしたが、非常に楽しかったです。
問題はまだ表に出てないかもしれないけど、いちおう僕が書いたプログラムを晒しておきます。printデバッグとかの部分で僕の苦労した箇所がわかります(汗
import sys import json from functools import total_ordering def run(input, output, width, height): f = open(input) json_file = f.read() f.close() objs = json.loads(json_file) parser = Parser(objs, output, int(width), int(height)) parser.run() class Parser: def __init__(self, objs, output, width, height): self.logos = Logos(objs) self.matrix = Matrix(width, height) self.output = output def run(self): while self.matrix.next_pos(): range_x = self.matrix.next_range_x() range_y = self.matrix.next_range_y() logo = self.logos.min_item(range_x, range_y) if (logo == None): self.matrix.set_notput(range_x) else: self.matrix.put(logo) self.logos.remove(logo) #self.matrix.show() result = self.matrix.to_json() f = open(self.output, 'w') f.write(result) f.close() return class Matrix: empty = 0 puted = 1 notput = 2 def __init__(self, width, height): self.width = width self.height = height #self.matrix = width * [ height * [self.empty]] self.matrix = self.makematrix() self.start_pos = tuple([0, 0]) self.putlogos = [] def makematrix(self): matrix = [] for x in range(0, self.width): _matrix = [] for y in range(0, self.height): _matrix.append(self.empty) matrix.append(_matrix) return matrix def next_pos(self): #print("next_pos") for y in range(0, self.height): for x in range(0, self.width): #print(x, y, self.matrix[x][y]) if (self.matrix[x][y] == self.empty): self.start_pos = tuple([x, y]) #print("start_pos", self.start_pos) return True return False def next_range_y(self): range_y = 0 x = self.start_pos[0] for y in range(self.start_pos[1], self.height): if (self.matrix[x][y] != self.empty): return range_y range_y = range_y + 1 return range_y def next_range_x(self): y = self.start_pos[1] range_x = 0 for x in range(self.start_pos[0], self.width): if (self.matrix[x][y] != self.empty): return range_x range_x = range_x + 1 return range_x def put(self, logo): rect_to = tuple([self.start_pos[0] + logo.width, self.start_pos[1] + logo.height]) self.draw(self.puted, rect_to) self.putlogos.append(tuple([logo, self.start_pos[0], self.start_pos[1]])) return def set_notput(self, range_x): #print("run set_nonput") nonput_point = self.get_nonput_point(range_x) if (nonput_point == None): return False #print(nonput_point) self.draw(self.notput, nonput_point) return True def draw(self, type, rect_to): #print(["draw ", self.start_pos, rect_to, type]) #print("check point ", "271 1", self.matrix[271][1]) for x in range(self.start_pos[0], rect_to[0] + 1): #print("line ", x) for y in range(self.start_pos[1], rect_to[1] + 1): #print("draw! ", x, y, type) self.matrix[x][y] = type #print("end draw") def get_nonput_point(self, range_x): x = self.start_pos[0] + range_x + 1#何かある if (x > self.width): rect_to = tuple([self.width - 1, self.start_pos[1]]) self.draw(self.notput, rect_to) return None #print(self.start_pos) #print(range_x) for y in range(self.start_pos[1], self.height): if (self.matrix[x][y] == self.empty): return tuple([x - 1, y - 1]) return None def show(self): print(self.matrix) def to_json(self): array = [] for item in self.putlogos: dict = {} dict["id"] = item[0].id dict["x"] = item[1] dict["y"] = item[2] array.append(dict) return json.dumps(array) class Logos: def __init__(self, objs): self.logos = [] for logoitem in objs: logo = Logo(logoitem) self.logos.append(logo) self.logos.sort() self.logos.reverse() def remove(self, logo): self.logos.remove(logo) def min_item(self, width, height): for logo in self.logos: if logo.width < width: if logo.height < height: return logo return None @total_ordering class Logo: def __init__(self, logoitem): self.height = logoitem["height"] self.width = logoitem["width"] self.score = logoitem["score"] self.name = logoitem["name"] self.id = logoitem["id"] self.range = self.height * self.width # sort def __eq__(self, other): if (other == None): return False return (self.score == other.score) and (self.range == other.range) # 小さいものを逆にする def __lt__(self, other): if (self.score == other.score): return (self.range > other.range) return (self.score < other.score) # print def show(self): print("id: %d, name: %s, score:%d, width: %d, height: %d" % (self.id, self.name, self.score, self.width, self.height)) if __name__ == '__main__': #print(len(sys.argv)) if (len(sys.argv) != 5): print("Usage: python3 %s input output width height" % sys.argv[0]) exit() run(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])
個人的に一番時間がかかったのがprint文のSyntax Errorです。Python3からprint文に()が必要なのに気づくのにすごく時間かかりました。一番苦労したのが文法とか!!!
あと、最初二次元配列の作り方間違えてしまいひどい目にあいました。コメントにそのまんま失敗例が残ってるので笑ってやってくだせぇorz