def randomized_select(self, select_range, priority_fn, lowestPriority=False): solution = list() total_profit = 0 bag = Bag(self.P, self.M, self.constraints) options = list() for item in self.items: options.append((item, priority_fn(item))) options.sort(key=lambda x: -x[1]) if lowestPriority: options = list(reversed(options)) options = [x[0] for x in options] while len(options) > 0 and not bag.full(): items = options[:min(select_range, len(options))] item = items[int(random() * len(items))] options.remove(item) print(" progress: {0:.2f} %".format(max(bag._weight / bag.P, bag._cost/bag.M) * 100), end="\r") if bag.has_enough_weight_for(item.weight) and bag.has_enough_money_for(item.cost): bag.take(item) solution.append(item) total_profit += item.profit new_options = list() for x in options: if bag.can_take(x.classNumber): new_options.append(x) options = new_options return (total_profit, solution)
def greedy_on_fn(self, priority_fn, lowestPriority=False): solution = list() total_profit = 0 bag = Bag(self.P, self.M, self.constraints) queue = get_priority_queue(self.items, priority_fn, lowestPriority) while not queue.isEmpty() and not bag.full(): item = queue.pop() #print(" remaining items: {0:.2f}%".format(queue.count / self.N * 100), end="\r") print(" progress: {0:.2f} %".format(max(bag._weight / bag.P, bag._cost/bag.M) * 100), end="\r") if bag.has_enough_weight_for(item.weight) and bag.has_enough_money_for(item.cost): if bag.can_take(item.classNumber): solution.append(item) bag.take(item) total_profit += item.profit return (total_profit, solution)
def deliver_one(instructions, meta_request, db_connection_info=MongoConnectionInfo()): connected_bag = Bag(db_connection_info) package = connected_bag.take(meta_request) package_content = io.BytesIO(package) return gz_unbox(unbox_instructions=instructions, mem=package_content)
def run_algorithm(self, num_solution_before_stop=100000, time_out=1000000): """ This is where we implement our logic and algorithms Useful Parameters: self.P -- max weight we can carry self.M -- max purchasing power in dollars self.N -- total number of avaliable items self.C -- total number of constraints self.items -- all items avaliable for choice self.constraints -- a Constraint class with constraints """ # STEP: Create a hashmap from class number to its items item_map = dict() for item in self.items: if item.classNumber not in item_map: item_map[item.classNumber] = set() item_map[item.classNumber].add(item) # STEP: Calculate the total weight, cost, value, and profit of each class def get_class_stats(items): total_weight = 0 total_cost = 0 total_value = 0 total_profit = 0 for item in items: total_weight += item.weight total_cost += item.cost total_value += item.value total_profit += item.profit return (total_weight, total_cost, total_value, total_profit) class_stats = dict() # Format: key: class -> value: (weight, cost, value, profit) for classNumber in item_map.keys(): class_stats[classNumber] = get_class_stats(item_map[classNumber]) # STEP: Create a BAG instance bag = Bag(self.P, self.M, self.constraints) # STEP: PriorityQueues of class's values fn_extract_profit_per_weight_ratio = lambda x: x.profit_per_weight_ratio() def fn_extractclass_ratio(x): weight, _, _, profit = class_stats[x] if weight == 0: ratio = float("inf") else: ratio = profit / weight return ratio class_queue = PriorityQueue(lowest_priority=False) # based on class's item profit_per_weight_ratio for classNumber in item_map.keys(): class_queue.push(classNumber, fn_extractclass_ratio(classNumber)) def add_to_queue(items, fn_extract_priority, queue): for item in items: priority_value = fn_extract_priority(item) queue.push(item, -priority_value) return queue def get_queue_of_items(items, fn_extract_priority): queue = PriorityQueue(lowest_priority=False) return add_to_queue(items, fn_extract_priority, queue) # STEP: pick from the bag with highest ratio solutions_found = dict() num_solution_found = 0 iteration = 0 class_not_used_due_to_conflict = Queue() add_back_conflicts = True while num_solution_found <= num_solution_before_stop and iteration <= time_out: while not class_queue.isEmpty() and iteration <= time_out: iteration += 1 if iteration % (time_out / 1000) == 0: print("iteration {0} -- rate: {1:.2f} %".format(iteration, iteration / time_out * 100), end="\r") if not class_not_used_due_to_conflict.isEmpty(): class_to_use = class_not_used_due_to_conflict.pop() add_back_conflicts = not add_back_conflicts else: class_to_use = class_queue.pop() add_back_conflicts = not add_back_conflicts if bag.can_take(class_to_use): items_queue = get_queue_of_items(item_map[class_to_use], \ fn_extract_profit_per_weight_ratio) item = items_queue.pop() while bag.take(item): if not items_queue.isEmpty(): item = items_queue.pop() else: break num_solution_found += 1 solutions_found[bag.score()] = bag.items() print("solution {0} found".format(num_solution_found)) else: class_not_used_due_to_conflict.push(class_to_use) if num_solution_found >= num_solution_before_stop: break # print("iteration {0}".format(iteration)) iteration += 1 if add_back_conflicts: add_to_queue(class_not_used_due_to_conflict.list, fn_extractclass_ratio, class_queue) if num_solution_found >= num_solution_before_stop: break # STEP: return the best combination found bestSolution = [] bestProfit = 0 for profit, soln in solutions_found.items(): if profit > bestProfit: bestProfit = profit bestSolution = soln return bestSolution
class Gameplay: def __init__(self) -> None: self.matrix = Matrix() self.bag = Bag() self.piece: Piece self.score = Score() self.input: Input self.cancel_input: Input self.popups: List[Popup] = [] self.holder: Optional[Piece] = None self.hold_lock = False self.level = 1 self.countdown = 3 self.countdown_last = ctx.now - 1.0 self.game_over = False self.game_over_sent = False self.last_fall: float self.fall_interval = 1.0 self.last_piece_movement_counter = 0 self.t_spin = False self.clearing = False self.clearing_rows: List[int] = [] self.clearing_last: float self.garbage_adding = False self.garbage_hole = 0 self.garbage_left = 0 self.garbage_last: float self.send = False self.cancel = False def get_matrix(self) -> Matrix: return self.matrix def get_piece(self) -> Piece: return self.piece def get_bag(self) -> Bag: return self.bag def get_popups(self) -> List[Popup]: return self.popups def clear_popups(self) -> None: self.popups = [] def set_device(self, device: Device) -> None: self.input = Input(device) self.cancel_input = Input(device) def initialize(self) -> None: self.input.bind({ "down": self.action_down, "right": self.action_right, "left": self.action_left, "rotate_right": self.action_rotate_right, "rotate_left": self.action_rotate_left, "soft_fall": self.action_soft_fall, "hard_fall": self.action_hard_fall, "hold": self.action_hold, }) self.cancel_input.bind({"cancel": self.action_cancel}) self.new_piece() def action_cancel(self) -> None: self.cancel = True def action_down(self) -> None: if self.piece.move(0, 1, self.matrix.collision): self.reset_fall() ctx.mixer.play("move") def action_right(self) -> None: if self.piece.move(1, 0, self.matrix.collision): ctx.mixer.play("move") if self.piece.touching_floor: self.reset_fall() def action_left(self) -> None: if self.piece.move(-1, 0, self.matrix.collision): ctx.mixer.play("move") if self.piece.touching_floor: self.reset_fall() def action_rotate_right(self) -> None: if self.piece.rotate(self.matrix.collision, clockwise=True): ctx.mixer.play("rotate") if self.piece.touching_floor: self.reset_fall() def action_rotate_left(self) -> None: if self.piece.rotate(self.matrix.collision, clockwise=False): ctx.mixer.play("rotate") if self.piece.touching_floor: self.reset_fall() def action_soft_fall(self) -> None: rows = self.piece.fall(self.matrix.collision) if rows > 0: ctx.mixer.play("soft_fall") self.reset_fall() self.score.update_soft_drop(rows) def action_hard_fall(self) -> None: rows = self.piece.fall(self.matrix.collision) self.lock_piece() if rows > 0: ctx.mixer.play("hard_fall") self.score.update_hard_drop(rows) def action_hold(self) -> None: if self.hold_lock: ctx.mixer.play("hold_fail") return self.hold_lock = True if self.holder is not None: self.holder, self.piece = self.piece, self.holder self.reset_piece() else: self.holder = self.piece self.new_piece() self.send = True ctx.mixer.play("hold") def new_piece(self) -> None: self.send = True self.piece = self.bag.take() self.piece.reset() self.reset_fall() if self.matrix.collision(self.piece): self.game_over = True if self.garbage_left > 0: self.garbage_adding = True self.garbage_last = ctx.now def reset_piece(self) -> None: self.piece.reset() for rows in range(self.piece.shape.grid[0].height, 0, -1): if self.piece.move(0, rows, self.matrix.collision): break self.reset_fall() def reset_fall(self) -> None: self.last_fall = ctx.now def lock_piece(self) -> None: self.hold_lock = False self.t_spin = False if self.matrix.collision( self.piece) or not self.matrix.lock(self.piece): self.game_over = True else: if TSpin.detect(self.matrix, self.piece): self.t_spin = True self.new_piece() if self.game_over: return rows = self.matrix.get_full_rows() if rows: popup = self.score.update_clear(self.level, rows, self.t_spin) ctx.mixer.play("erase" + str(len(rows))) self.clear_rows(rows) self.popups.append(popup) else: self.score.reset_combo() def clear_rows(self, rows: List[int]) -> None: self.clearing = True self.clearing_rows = rows self.clearing_last = ctx.now + 0.15 for row in rows: self.matrix.erase_row(row) def add_garbage(self, hole: int, count: int) -> None: self.garbage_hole = hole self.garbage_left = count def update(self) -> None: self.cancel_input.update() if self.clearing: if ctx.now - self.clearing_last > 0.02: self.send = True self.matrix.collapse_row(self.clearing_rows.pop(0)) self.clearing_last = ctx.now ctx.mixer.play("line_fall") if not self.clearing_rows: self.clearing = False self.reset_piece() elif self.garbage_adding: if ctx.now - self.garbage_last > 0.03: self.send = True self.matrix.add_garbage(self.garbage_hole) self.garbage_last = ctx.now ctx.mixer.play("garbage") self.garbage_left -= 1 if self.garbage_left == 0: self.garbage_adding = False self.reset_piece() if self.game_over: if not self.game_over_sent: self.game_over_sent = True self.send = True return if self.countdown >= 0: if ctx.now - self.countdown_last > 1.0: self.send = True self.countdown_last = ctx.now ctx.mixer.play("countdown") if self.countdown == 0: self.popups.append( Popup("GO!", size=6, color="green", duration=0.4)) ctx.mixer.play("go") ctx.mixer.play_music("main_theme") else: self.popups.append( Popup(str(self.countdown), size=6, duration=0.4)) self.countdown -= 1 return self.input.update() if self.piece.movement_counter != self.last_piece_movement_counter: self.send = True self.last_piece_movement_counter = self.piece.movement_counter if ctx.now - self.last_fall > self.fall_interval: self.send = True if self.piece.move(0, 1, self.matrix.collision): self.reset_fall() else: self.lock_piece() def draw(self, x: int, y: int, draw_piece=True) -> None: self.matrix.draw(x, y) if draw_piece and self.piece: self.matrix.get_ghost(self.piece).draw(x, y) self.piece.draw(x, y) self.score.draw(x, y - 70) self.bag.draw(x + 340, y + 70) if self.holder is not None: holder_x = int(x - 65 - self.holder.shape.get_width(0) * 11.25) self.holder.shape.draw(0, holder_x, y + 60, 22, 1.0) else: shape.SHAPE_HOLD_NONE.draw(0, x - 85, y + 60, 22, 1.0) Text.draw("Hold", centerx=x - 75, top=y + 20) Text.draw("Next", centerx=x + 370, top=y + 20)