class Solution(db.Model): __tablename__ = 'solutions' solution_id = db.Column(db.Integer, primary_key=True) file_id = db.Column(db.Integer, db.ForeignKey('savefiles.file_id')) user_id = db.Column(db.Integer, db.ForeignKey('users.user_id')) level_id = db.Column(db.Integer, db.ForeignKey('levels.level_id')) cycle_count = db.Column(db.Integer) symbol_count = db.Column(db.Integer) reactor_count = db.Column(db.Integer) upload_time = db.Column(db.DateTime, default=func.now()) description = db.Column(db.String(255)) youtube = db.Column(db.String(255)) approved = db.Column(db.Boolean, default=True) savefile = db.relationship('SaveFile', backref='solutions') user = db.relationship('User', backref='solutions') level = db.relationship('Level', backref='solutions') def __init__(self, file_id, user_id, level_id, cycle_count, symbol_count, reactor_count, approved=True): self.file_id = file_id self.user_id = user_id self.level_id = level_id self.cycle_count = cycle_count self.symbol_count = symbol_count self.reactor_count = reactor_count self.approved = approved
class OfficialScores(db.Model): __tablename__ = 'official_scores' level_id = db.Column(db.Integer, db.ForeignKey('levels.level_id'), primary_key=True) fetch_date = db.Column(db.Date, primary_key=True, default=func.now()) reactor_counts = db.Column(db.String(255)) symbol_counts = db.Column(db.String(255)) cycle_counts = db.Column(db.String(255)) level = db.relationship('Level', backref='official_scores')
class FixedComponent(db.Model): __tablename__ = 'components_fixed' fixedcomponent_id = db.Column(db.Integer, primary_key=True) level_id = db.Column(db.Integer, db.ForeignKey('levels.level_id')) type = db.Column(db.String(255)) x = db.Column(db.Integer) y = db.Column(db.Integer) level = db.relationship('Level', backref=db.backref( 'fixedcomponents', order_by=(x, y), cascade='save-update, merge, delete'))
class Pipe(db.Model): __tablename__ = 'pipes' pipe_id = db.Column(db.Integer, primary_key=True) component_id = db.Column(db.Integer, db.ForeignKey('components.component_id')) output_id = db.Column(db.Integer) x = db.Column(db.Integer) y = db.Column(db.Integer) component = db.relationship('Component', backref=db.backref( 'pipes', cascade='save-update, merge, delete')) def __init__(self, component_id, output_id, x, y): self.component_id = component_id self.output_id = output_id self.x = x self.y = y
class Component(db.Model): __tablename__ = 'components' component_id = db.Column(db.Integer, primary_key=True) solution_id = db.Column(db.Integer, db.ForeignKey('solutions.solution_id')) type = db.Column(db.String(255)) x = db.Column(db.Integer) y = db.Column(db.Integer) solution = db.relationship('Solution', backref=db.backref( 'components', order_by=(x, y), cascade='save-update, merge, delete')) def __init__(self, solution_id, type, x, y): self.solution_id = solution_id self.type = type self.x = x self.y = y
class SaveFile(db.Model): __tablename__ = 'savefiles' file_id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('users.user_id')) upload_time = db.Column(db.DateTime, default=func.now()) user = db.relationship('User', backref='savefiles') def __init__(self, user_id): self.user_id = user_id def process(self, approve_all=True): approve_all = bool(approve_all) user = User.query.filter_by(user_id=self.user_id).one() filename = savefiles.path(user.username + '-' + str(self.file_id) + '.user') conn = sqlite3.connect(filename) conn.row_factory = sqlite3.Row c = conn.cursor() uploaded = 0 skipped = 0 recalc_levels = set() levels = Level.query.all() for level in levels: c.execute("SELECT * FROM Level WHERE id = ? AND passed = 1", (level.internal_name, )) level_row = c.fetchone() if level_row: # check if a solution with the same statistics already exists # if it does, this is (probably?) a duplicate try: existing_solution = (Solution.query.filter( and_(Solution.level_id == level.level_id, Solution.user_id == self.user_id, Solution.cycle_count == level_row['cycles'], Solution.symbol_count == level_row['symbols'], Solution.reactor_count == level_row['reactors'])).one()) skipped += 1 continue except NoResultFound: uploaded += 1 recalc_levels.add(level.level_id) solution = Solution(self.file_id, self.user_id, level.level_id, level_row['cycles'], level_row['symbols'], level_row['reactors'], approve_all) db.session.add(solution) db.session.commit() c.execute("SELECT * FROM Component WHERE level_id = ?", (level.internal_name, )) component_rows = c.fetchall() for component_row in component_rows: component = Component(solution.solution_id, component_row['type'], component_row['x'], component_row['y']) db.session.add(component) db.session.commit() c.execute("SELECT * FROM Member WHERE component_id = ?", (component_row['rowid'], )) member_rows = c.fetchall() for member_row in member_rows: member = Member( component.component_id, member_row['type'], member_row['arrow_dir'], member_row['choice'], member_row['layer'], member_row['x'], member_row['y'], member_row['element_type'], member_row['element']) db.session.add(member) c.execute("SELECT * FROM Pipe WHERE component_id = ?", (component_row['rowid'], )) pipe_rows = c.fetchall() for pipe_row in pipe_rows: pipe = Pipe(component.component_id, pipe_row['output_id'], pipe_row['x'], pipe_row['y']) db.session.add(pipe) db.session.commit() # recalculate the ranks if everything is auto-approved if approve_all: for level_id in recalc_levels: SolutionRank.recalculate(level_id) return (uploaded, skipped)
class Member(db.Model): __tablename__ = 'members' member_id = db.Column(db.Integer, primary_key=True) component_id = db.Column(db.Integer, db.ForeignKey('components.component_id')) type = db.Column(db.String(255)) arrow_dir = db.Column(db.Integer) choice = db.Column(db.Integer) layer = db.Column(db.Integer) x = db.Column(db.Integer) y = db.Column(db.Integer) element_type = db.Column(db.Integer) element = db.Column(db.Integer) component = db.relationship('Component', backref=db.backref( 'members', cascade='save-update, merge, delete')) @property def color(self): if self.layer in (16, 32): return "blue" elif self.layer in (64, 128): return "red" else: return "feature" ARROW_DIRS = {180: "l", -90: "u", 0: "r", 90: "d"} ELEMENTS = str.split( 'XX H He Li Be B C N O F Ne Na Mg Al Si P S Cl Ar K ' 'Ca Sc Ti V Cr Mn Fe Co Ni Cu Zn Ga Ge As Se Br Kr ' 'Rb Sr Y Zr Nb Mo Tc Ru Rh Pd Ag Cd In Sn Sb Te I Xe ' 'Cs Ba La Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu ' 'Hf Ta W Re Os Ir Pt Au Hg Tl Pb Bi Po At Rn Fr Ra ' 'Ac Th Pa U Np Pu Am Cm Bk Cf Es Fm Md No Lr Rf Db Sg ' 'Bh Hs Mt') def __init__(self, component_id, type, arrow_dir, choice, layer, x, y, element_type, element): self.component_id = component_id self.type = type self.arrow_dir = arrow_dir self.choice = choice self.layer = layer self.x = x self.y = y self.element_type = element_type self.element = element @property def image_name(self): variant = "" if self.type == "feature-bonder": return "feature-bonder.png" elif self.type == "feature-bonder-minus": return "feature-bonder_minus.png" elif self.type == "feature-bonder-plus": return "feature-bonder_plus.png" elif self.type == "feature-fuser": return "feature-fuser.png" elif self.type == "feature-sensor": return "feature-sensor.png" elif self.type == "feature-splitter": return "feature-splitter.png" elif self.type == "feature-tunnel": return "feature-tunnel.png" elif self.type == "instr-arrow": return self.color + "-arrow_" + self.ARROW_DIRS[ self.arrow_dir] + ".png" elif self.type == "instr-bond": if self.choice == 0: variant = "_plus" elif self.choice == 1: variant = "_minus" return self.color + "-bond" + variant + ".png" elif self.type == "instr-control": if self.choice == 0: variant = "a" elif self.choice == 1: variant = "b" elif self.choice == 2: variant = "c" elif self.choice == 3: variant = "d" return self.color + "-control_" + variant + "_" + self.ARROW_DIRS[ self.arrow_dir] + ".png" elif self.type == "instr-debug": return self.color + "-debug.png" elif self.type == "instr-fuse": return self.color + "-fuse.png" elif self.type == "instr-grab": if self.choice == 0: variant = "grab_drop" elif self.choice == 1: variant = "grab" elif self.choice == 2: variant = "drop" return self.color + "-" + variant + ".png" elif self.type == "instr-input": if self.choice == 0: variant = "1" elif self.choice == 1: variant = "2" return self.color + "-in_" + variant + ".png" elif self.type == "instr-output": if self.choice == 0: variant = "1" elif self.choice == 1: variant = "2" return self.color + "-out_" + variant + ".png" elif self.type == "instr-rotate": if self.choice == 0: variant = "cw" elif self.choice == 1: variant = "ccw" return self.color + "-rotate_" + variant + ".png" elif self.type == "instr-sensor": return self.color + "-sensor_" + self.ARROW_DIRS[ self.arrow_dir] + ".png" elif self.type == "instr-split": return self.color + "-split.png" elif self.type == "instr-start": return self.color + "-start_" + self.ARROW_DIRS[ self.arrow_dir] + ".png" elif self.type == "instr-swap": return self.color + "-swap.png" elif self.type == "instr-sync": return self.color + "-sync.png" elif self.type == "instr-toggle": return self.color + "-toggle_" + self.ARROW_DIRS[ self.arrow_dir] + ".png"
class SolutionRank(db.Model): __tablename__ = 'solution_ranks' solution_id = db.Column(db.Integer, db.ForeignKey('solutions.solution_id'), primary_key=True) leaderboard_id = db.Column(db.Integer, db.ForeignKey('leaderboards.leaderboard_id'), primary_key=True) level_id = db.Column(db.Integer, db.ForeignKey('levels.level_id'), primary_key=True) reactors = db.Column(db.Integer, primary_key=True, default=0) rank = db.Column(db.Integer) solution = db.relationship('Solution', backref=db.backref( 'ranks', cascade='save-update, merge, delete')) leaderboard = db.relationship('Leaderboard', backref=db.backref( 'ranks', cascade='save-update, merge, delete')) def __init__(self, solution_id, leaderboard_id, level_id, rank, reactors=0): self.solution_id = solution_id self.leaderboard_id = leaderboard_id self.level_id = level_id self.rank = rank self.reactors = reactors @property def rank_str(self): if self.rank % 10 == 1 and self.rank % 100 != 11: return str(self.rank) + 'st' elif self.rank % 10 == 2 and self.rank % 100 != 12: return str(self.rank) + 'nd' elif self.rank % 10 == 3 and self.rank % 100 != 13: return str(self.rank) + 'rd' else: return str(self.rank) + 'th' @staticmethod def recalculate(level_id): SolutionRank.query.filter(SolutionRank.level_id == level_id).delete() # cycles # first do the "any reactors" leaderboard users = set() rank = 1 solutions = (Solution.query.filter( and_(Solution.level_id == level_id, Solution.approved == True)).order_by('cycle_count', 'symbol_count', 'reactor_count', 'upload_time').all()) for solution in solutions: if solution.user_id not in users: users.add(solution.user_id) solution_rank = SolutionRank(solution.solution_id, 1, solution.level_id, rank) db.session.add(solution_rank) rank += 1 # then any individual reactor counts if necessary if solution.level.outside_view: reactor_options = (db.session.query(Solution.reactor_count).filter( and_(Solution.level_id == level_id, Solution.reactor_count != 0, Solution.approved == True)).distinct().order_by( Solution.reactor_count).all()) for reactor_count in reactor_options: users = set() rank = 1 solutions = (Solution.query.filter( and_(Solution.level_id == level_id, Solution.reactor_count == reactor_count[0], Solution.approved == True)).order_by( 'cycle_count', 'symbol_count', 'upload_time').all()) for solution in solutions: if solution.user_id not in users: users.add(solution.user_id) solution_rank = SolutionRank(solution.solution_id, 1, solution.level_id, rank, reactor_count[0]) db.session.add(solution_rank) rank += 1 # symbols # first do the "any reactors" leaderboard users = set() rank = 1 solutions = (Solution.query.filter( and_(Solution.level_id == level_id, Solution.approved == True)).order_by('symbol_count', 'cycle_count', 'reactor_count', 'upload_time').all()) for solution in solutions: if solution.user_id not in users: users.add(solution.user_id) solution_rank = SolutionRank(solution.solution_id, 2, solution.level_id, rank) db.session.add(solution_rank) rank += 1 # then any individual reactor counts if necessary if solution.level.outside_view: reactor_options = (db.session.query(Solution.reactor_count).filter( and_(Solution.level_id == level_id, Solution.reactor_count != 0)).distinct().order_by( Solution.reactor_count).all()) for reactor_count in reactor_options: users = set() rank = 1 solutions = (Solution.query.filter( and_(Solution.level_id == level_id, Solution.reactor_count == reactor_count[0], Solution.approved == True)).order_by( 'symbol_count', 'cycle_count', 'upload_time').all()) for solution in solutions: if solution.user_id not in users: users.add(solution.user_id) solution_rank = SolutionRank(solution.solution_id, 2, solution.level_id, rank, reactor_count[0]) db.session.add(solution_rank) rank += 1 db.session.commit()