def initialize_segments(options, config_path, config_segments): seen_segment_names = set() ret = [] for i, segment in enumerate(config_segments[:-1]): seg_type = parse_segment_type(segment) platform = get_platform(options) segment_class = get_base_segment_class(seg_type, platform) if segment_class == None: # Look in extensions segment_class = get_extension_class(options, config_path, seg_type, platform) if segment_class == None: log.write( f"fatal error: could not load segment type '{seg_type}'\n(hint: confirm your extension directory is configured correctly)", status="error") return 2 segment = segment_class(segment, config_segments[i + 1], options) if segment_class.require_unique_name: if segment.name in seen_segment_names: segment.error("segment name is not unique") seen_segment_names.add(segment.name) ret.append(segment) return ret
def round(self): # Each round, every player should get its turn for player in self.players: if not player.is_bankrupt(): self.turn(player) if player.is_bankrupt(): player.bankrupt() self.info_dic["bankrupt_turn"][player.num] = self.cur_round if util.verbose: log.write( "player {} has bankrupted, return all properties to the bank.\n" .format(player.num)) self.bankrupt_count += 1 if len(self.players) - self.bankrupt_count <= 1: for i in self.players: if not i.is_bankrupt(): if util.verbose: log.write("player {} wins\n".format(i.num)) self.info_dic["bankrupt_turn"][i.num] = -1 self.info_dic["winner"] = i.num self.info_dic["end"] = self.cur_round return True if util.verbose: log.write("\n") for player in self.players: if util.verbose: log.write("player {} has {} cash.\n".format( player.num, player.cash)) if util.verbose: log.write("\n") return False
def turn(self, player): # Get number of eyes on dice dice1, dice2 = diceThrow() if util.verbose: log.write("player {0} rolls two dices, {1} and {2}.\n".format( player.num, dice1, dice2)) # Move the player to new position, goingToJail True is 3 doubles thrown player.move(self.board, dice1, dice2) # Get tile type tileType = self.board.getTileType(player.position) # Set to go to jail if on 'Go To Jail' tile if tileType == "gotojail": player.go_to_jail() # Do chance card if player has landed on a chance tile elif player.position in Board.TILES_CHANCE: player.doChanceCard(self.chancePile.pullCard(), self.board) # Do commmunity card if player has landed on a community chest tile elif player.position in Board.TILES_COMMUNITY: player.doCommunityCard(self.communityPile.pullCard(), self.board) elif Board.TILE_BUILDING[player.position] is not None: building = Board.TILE_BUILDING[player.position] if building.owner is None or building.owner.num == player.num: player.buy_building(Board.TILE_BUILDING[player.position]) elif building.owner is not None and building.owner != player.num: fined = int(building.cur_price * 0.2) player.fine_money(fined, other=building.owner) # equivalent to trading for building_to_sell in player.building_to_sell_list: for other_player in self.players: if not other_player.is_bankrupt(): boundary = other_player.choose_boundary( other_player.strategy, other_player.strategy_para) if other_player != player and other_player.cash - building_to_sell.cur_price >= boundary: other_player.cash -= building_to_sell.cur_price building_to_sell.set_owner(other_player) other_player.building.append(building_to_sell) player.cash += int(building_to_sell.cur_price * 0.1) if util.verbose: log.write( "player {0} successfully sell land {1} to player {2}, get the remaining {3}, player {0} currently has {4}, player {2} has {5}.\n" .format(player.num, building_to_sell.name, other_player.num, building_to_sell.cur_price * 0.1, player.cash, other_player.cash)) break player.building_to_sell_list = [] # Log the fact that a player has landed on a tile, after all movements self.board.hit(player.position) # Go again if not on jail and has thrown double if tileType != "jail" and dice1 == dice2: self.turn(player)
def doCommunityCard(self, card, board): # Go to given position if card is of the advance kind # Check the type of the chance card # card for moving if util.verbose: log.write("player {0} get a community card {1}.\n".format( self.num, card)) if card.kind == "advance": self.position = card.value if self.position == board.TILES_JAIL[0]: self.at_jail = True if util.verbose: log.write("player {0} moves to {1}.\n".format( self.num, board.TILE_NAME[self.position])) # card for get money elif card.kind == "cash": self.cash += card.value if util.verbose: log.write( "player {0} gets {1} cash, currently has {2} cash.\n". format(self.num, card.value, self.cash)) # card for tax elif card.kind == "tax": fined = card.value[0] * self.house + card.value[1] * self.hotel self.fine_money(fined) if util.verbose: log.write( "player {0} pay {1} tax, currently has {2} cash.\n".format( self.num, fined, self.cash))
def get_extension_class(options, config_path, seg_type): ext_dir = get_extension_dir(options, config_path) if ext_dir == None: return None try: ext_spec = importlib.util.spec_from_file_location( f"segtypes.{seg_type}", os.path.join(ext_dir, f"{seg_type}.py")) ext_mod = importlib.util.module_from_spec(ext_spec) ext_spec.loader.exec_module(ext_mod) except Exception as err: log.write(err, status="error") return None return getattr(ext_mod, "PS2Seg" + seg_type[0].upper() + seg_type[1:])
def run(self): # Play the game for a given amount of rounds end = False for i in range(0, self.rounds): # dev_print("round", i) self.cur_round = i if util.verbose: log.write("round {0}:\n".format(i)) end = self.round() if util.verbose: log.write("\n") if end: break # for player in self.players: # dev_print("player {0}: cash {1}, property {2}".format(player.num, player.cash, player.total_property())) if not end: self.info_dic["end"] = -1 return self.info_dic
def create_c_file(self, funcs_text, asm_out_dir, c_path): c_lines = self.get_c_preamble() for func in funcs_text: func_name = self.parent.get_symbol(func, type="func", local_only=True).name # Terrible hack to "auto-decompile" empty functions # TODO move disassembly into funcs_text or somewhere we can access it from here if (options.get_auto_decompile_empty_functions() and len(funcs_text[func][0]) == 3 and funcs_text[func][0][1][-3:] in ["$ra", "$31"] and funcs_text[func][0][2][-3:] == "nop"): c_lines.append("void " + func_name + "(void) {") c_lines.append("}") else: if options.get_compiler() in [GCC, SN64]: if options.get_use_legacy_include_asm(): rel_asm_out_dir = asm_out_dir.relative_to( options.get_nonmatchings_path()) c_lines.append( f'INCLUDE_ASM(s32, "{rel_asm_out_dir / self.name}", {func_name});' ) else: c_lines.append( f'INCLUDE_ASM("{asm_out_dir / self.name}", {func_name});' ) else: asm_outpath = Path( os.path.join(asm_out_dir, self.name, func_name + ".s")) rel_asm_outpath = os.path.relpath(asm_outpath, options.get_base_path()) c_lines.append(f'#pragma GLOBAL_ASM("{rel_asm_outpath}")') c_lines.append("") Path(c_path).parent.mkdir(parents=True, exist_ok=True) with open(c_path, "w") as f: f.write("\n".join(c_lines)) log.write(f"Wrote {self.name} to {c_path}")
def fine_money(self, fined, other=None): boundary = self.choose_boundary(self.strategy, self.strategy_para) if self.cash - fined < boundary: building_to_sell = self.find_min_house_to_sell(fined) # dev_print(self.building) if building_to_sell is not None: building_to_sell.sell() # dev_print("here", building_to_sell) self.building.remove(building_to_sell) sell_price = int(building_to_sell.cur_price * 0.9) self.cash += sell_price self.building_to_sell_list.append(building_to_sell) if util.verbose: log.write( "player {0} sells the property on {1} to the bank for {2} cash, currently has {3}.\n" .format(self.num, building_to_sell.name, sell_price, self.cash)) self.cash -= fined if other is not None: other.cash += fined if util.verbose: log.write( "player {0} lands on player {1}'s property, player {0} gives {2} to player {1}, now player {0} has {3}, player {1} has {4}.\n" .format(self.num, other.num, fined, self.cash, other.cash)) else: if util.verbose: log.write( "player {0} is fined {1} by the country, currently has {2}.\n" .format(self.num, fined, self.cash))
def get_extension_segment_class(seg_type): platform = options.get_platform() ext_path = options.get_extensions_path() if not ext_path: log.error( f"could not load presumed extended segment type '{seg_type}' because no extensions path is configured" ) try: ext_spec = importlib.util.spec_from_file_location( f"{platform}.segtypes.{seg_type}", ext_path / f"{seg_type}.py") ext_mod = importlib.util.module_from_spec(ext_spec) ext_spec.loader.exec_module(ext_mod) except Exception as err: log.write(err, status="error") log.error( f"could not load segment type '{seg_type}'\n(hint: confirm your extension directory is configured correctly)" ) return getattr( ext_mod, f"{platform.upper()}Seg{seg_type[0].upper()}{seg_type[1:]}")
def create_c_file(self, asm_out_dir, c_path): c_lines = self.get_c_preamble() for func in self.text_section.symbolList: assert isinstance(func, spimdisasm.mips.symbols.SymbolFunction) # Terrible hack to "auto-decompile" empty functions if (options.get_auto_decompile_empty_functions() and func.instructions[0].isJrRa() and func.instructions[1].isNop()): c_lines.append("void " + func.getName() + "(void) {") c_lines.append("}") else: if options.get_compiler() in [GCC, SN64]: if options.get_use_legacy_include_asm(): rel_asm_out_dir = asm_out_dir.relative_to( options.get_nonmatchings_path()) c_lines.append( f'INCLUDE_ASM(s32, "{rel_asm_out_dir / self.name}", {func.getName()});' ) else: c_lines.append( f'INCLUDE_ASM("{asm_out_dir / self.name}", {func.getName()});' ) else: asm_outpath = Path( os.path.join(asm_out_dir, self.name, func.getName() + ".s")) rel_asm_outpath = os.path.relpath(asm_outpath, options.get_base_path()) c_lines.append(f'#pragma GLOBAL_ASM("{rel_asm_outpath}")') c_lines.append("") Path(c_path).parent.mkdir(parents=True, exist_ok=True) with open(c_path, "w") as f: f.write("\n".join(c_lines)) log.write(f"Wrote {self.name} to {c_path}")
def create_c_file(self, funcs_text, asm_out_dir, c_path): c_lines = self.get_c_preamble() for func in funcs_text: func_name = self.parent.get_symbol(func, type="func", local_only=True).name # Terrible hack to "auto-decompile" empty functions # TODO move disassembly into funcs_text or somewhere we can access it from here if len(funcs_text[func][0]) == 3 and funcs_text[func][0][1][-3:] == "$ra" and funcs_text[func][0][2][-3:] == "nop": c_lines.append("void " + func_name + "(void) {") c_lines.append("}") else: if options.get_compiler() == "GCC": c_lines.append("INCLUDE_ASM(s32, \"{}\", {});".format(self.name, func_name)) else: asm_outpath = Path(os.path.join(asm_out_dir, self.dir, self.name, func_name + ".s")) rel_asm_outpath = os.path.relpath(asm_outpath, options.get_base_path()) c_lines.append(f"#pragma GLOBAL_ASM(\"{rel_asm_outpath}\")") c_lines.append("") Path(c_path).parent.mkdir(parents=True, exist_ok=True) with open(c_path, "w") as f: f.write("\n".join(c_lines)) log.write(f"Wrote {self.name} to {c_path}")
def buy_building(self, building): assert isinstance(building, Building) if building.owner is None: # the player can buy the building # based on the player's strategy, decide how much cash could be used to buy buildings boundary = self.choose_boundary(self.strategy, self.strategy_para) if self.cash - building.base_price >= boundary: self.cash -= building.base_price self.building.append(building) building.set_owner(self) self.land += 1 if util.verbose: log.write( "player {0} buys a land on {1}, costs {2}, currently has {3} cash.\n" .format(self.num, building.name, building.base_price, self.cash)) else: return False else: if building.owner.num == self.num: # the player is the owner of the building boundary = self.choose_boundary(self.strategy, self.strategy_para) if self.cash - building.base_price >= boundary: if building.level == 0: self.cash -= building.base_price self.land -= 1 self.house += 1 building.improve() if util.verbose: log.write( 'player {0} upgrades the land on {1} to a house, costs {2}, currently has {3} cash.\n' .format(self.num, building.name, building.base_price, self.cash)) elif building.level == 1: self.cash -= building.base_price self.house -= 1 self.hotel += 1 building.improve() if util.verbose: log.write( 'player {0} upgrades the house on {1} to a hotel, costs {2}, currently has {3} cash.\n' .format(self.num, building.name, building.base_price, self.cash)) else: return False else: raise PermissionError( "You have no right to upgrade the property.\n") return True
def do_statistics(seg_sizes, rom_bytes, seg_split, seg_cached): unk_size = seg_sizes.get("unk", 0) rest_size = 0 total_size = len(rom_bytes) for typ in seg_sizes: if typ != "unk": rest_size += seg_sizes[typ] known_ratio = rest_size / total_size unk_ratio = unk_size / total_size log.write(f"Split {fmt_size(rest_size)} ({known_ratio:.2%}) in defined segments") for typ in seg_sizes: if typ != "unk": tmp_size = seg_sizes[typ] tmp_ratio = tmp_size / total_size log.write(f"{typ:>20}: {fmt_size(tmp_size):>8} ({tmp_ratio:.2%}) {Fore.GREEN}{seg_split[typ]} split{Style.RESET_ALL}, {Style.DIM}{seg_cached[typ]} cached") log.write(f"{'unknown':>20}: {fmt_size(unk_size):>8} ({unk_ratio:.2%}) from unknown bin files")
def experiment(configs, fold_paths, train_path, test_path, log_dir): for index, config in enumerate(configs): session_log_dir = os.path.join(log_dir, "session_{}".format(datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))) print("\nEXPERIMENT: {}/{}".format(index+1, len(configs))) print(config) config["log_dir"] = session_log_dir config["class_weight"] = { 0: 1, 1: 1 } config["verbose"] = 2 train_result, dev_result, test_result = k_fold_experiment( config=config, fold_paths=fold_paths, train_path=train_path, test_path=test_path ) log_result(train_result, dev_result, test_result) write(session_log_dir, "train", train_result, config["hparams"]) write(session_log_dir, "dev", dev_result, config["hparams"]) write(session_log_dir, "test", test_result, config["hparams"])
def main(config_path, out_dir, target_path, modes, verbose, ignore_cache=False): # Load config with open(config_path) as f: config = yaml.safe_load(f.read()) options = config.get("options") options["modes"] = modes options["verbose"] = verbose if not out_dir: out_dir = options.get("out_dir", None) if not out_dir: print( "Error: Output dir not specified as a command line arg or via the config yaml (out_dir)" ) sys.exit(2) else: out_dir = os.path.join(Path(config_path).parent, out_dir) if not target_path: target_path = options.get("target_path", None) if not target_path: print( "Error: Target binary path not specified as a command line arg or via the config yaml (target_path)" ) sys.exit(2) else: target_path = os.path.join(out_dir, target_path) with open(target_path, "rb") as f: rom_bytes = f.read() # Create main output dir Path(out_dir).mkdir(parents=True, exist_ok=True) symbol_addrs_path = get_symbol_addrs_path(out_dir, options) undefined_syms_path = get_undefined_syms_path(out_dir, options) all_symbols = gather_symbols(symbol_addrs_path, undefined_syms_path) symbol_ranges = [s for s in all_symbols if s.size > 4] platform = get_platform(options) processed_segments = [] ld_sections = [] seg_sizes = {} seg_split = {} seg_cached = {} # Load cache cache_path = get_cache_path(out_dir, options) try: with open(cache_path, "rb") as f: cache = pickle.load(f) except Exception: cache = {} # Initialize segments all_segments = initialize_segments(options, config_path, config["segments"]) for segment in all_segments: if platform == "n64" and type( segment) == N64SegCode: # remove special-case sometime segment_symbols, other_symbols = get_segment_symbols( segment, all_symbols, all_segments) segment.seg_symbols = segment_symbols segment.ext_symbols = other_symbols segment.all_symbols = all_symbols segment.symbol_ranges = symbol_ranges segment.check() typ = segment.type if segment.type == "bin" and segment.is_name_default(): typ = "unk" if typ not in seg_sizes: seg_sizes[typ] = 0 seg_split[typ] = 0 seg_cached[typ] = 0 seg_sizes[typ] += segment.size if len(segment.errors) == 0: if segment.should_run(): # Check cache cached = segment.cache() if not ignore_cache and cached == cache.get( segment.unique_id()): # Cache hit seg_cached[typ] += 1 else: # Cache miss; split cache[segment.unique_id()] = cached segment.did_run = True segment.split(rom_bytes, out_dir) if len(segment.errors) == 0: processed_segments.append(segment) seg_split[typ] += 1 log.dot(status=segment.status()) ld_sections.append(segment.get_ld_section()) for segment in processed_segments: segment.postsplit(processed_segments) log.dot(status=segment.status()) # Write ldscript if "ld" in options["modes"] or "all" in options["modes"]: if verbose: log.write(f"saving {config['basename']}.ld") write_ldscript(config['basename'], out_dir, ld_sections, options) undefined_syms_to_write = [ s for s in all_symbols if s.referenced and not s.defined and not s.type == "func" ] undefined_funcs_to_write = [ s for s in all_symbols if s.referenced and not s.defined and s.type == "func" ] # Write undefined_funcs_auto.txt undefined_funcs_auto_path = get_undefined_funcs_auto_path(out_dir, options) to_write = undefined_funcs_to_write if len(to_write) > 0: with open(undefined_funcs_auto_path, "w", newline="\n") as f: for symbol in to_write: f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n") # write undefined_syms_auto.txt undefined_syms_auto_path = get_undefined_syms_auto_path(out_dir, options) to_write = undefined_syms_to_write if len(to_write) > 0: with open(undefined_syms_auto_path, "w", newline="\n") as f: for symbol in to_write: f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n") # print warnings during split/postsplit for segment in all_segments: if len(segment.warnings) > 0: log.write( f"{Style.DIM}0x{segment.rom_start:06X}{Style.RESET_ALL} {segment.type} {Style.BRIGHT}{segment.name}{Style.RESET_ALL}:" ) for warn in segment.warnings: log.write("warning: " + warn, status="warn") log.write("") # empty line # Statistics unk_size = seg_sizes.get("unk", 0) rest_size = 0 total_size = len(rom_bytes) for typ in seg_sizes: if typ != "unk": rest_size += seg_sizes[typ] assert (unk_size + rest_size == total_size) known_ratio = rest_size / total_size unk_ratio = unk_size / total_size log.write( f"Split {fmt_size(rest_size)} ({known_ratio:.2%}) in defined segments") for typ in seg_sizes: if typ != "unk": tmp_size = seg_sizes[typ] tmp_ratio = tmp_size / total_size log.write( f"{typ:>20}: {fmt_size(tmp_size):>8} ({tmp_ratio:.2%}) {Fore.GREEN}{seg_split[typ]} split{Style.RESET_ALL}, {Style.DIM}{seg_cached[typ]} cached" ) log.write( f"{'unknown':>20}: {fmt_size(unk_size):>8} ({unk_ratio:.2%}) from unknown bin files" ) # Save cache if cache != {}: if verbose: print("Writing cache") with open(cache_path, "wb") as f: pickle.dump(cache, f) return 0 # no error
def main(rom_path, config_path, repo_path, modes, verbose, ignore_cache=False): with open(rom_path, "rb") as f: rom_bytes = f.read() # Create main output dir Path(repo_path).mkdir(parents=True, exist_ok=True) # Load config with open(config_path) as f: config = yaml.safe_load(f.read()) options = config.get("options") options["modes"] = modes options["verbose"] = verbose symbol_addrs_path = get_symbol_addrs_path(repo_path, options) undefined_syms_path = get_undefined_syms_path(repo_path, options) provided_symbols, c_func_labels_to_add, special_labels, ranges = gather_symbols( symbol_addrs_path, undefined_syms_path) platform = get_platform(options) processed_segments = [] ld_sections = [] defined_funcs = {} undefined_funcs = set() undefined_syms = set() seg_sizes = {} seg_split = {} seg_cached = {} # Load cache cache_path = get_cache_path(repo_path, options) try: with open(cache_path, "rb") as f: cache = pickle.load(f) except Exception: cache = {} # Initialize segments all_segments = initialize_segments(options, config_path, config["segments"]) for segment in all_segments: if platform == "n64" and type( segment) == N64SegCode: # remove special-case sometime segment.all_functions = defined_funcs segment.provided_symbols = provided_symbols segment.special_labels = special_labels segment.c_labels_to_add = c_func_labels_to_add segment.symbol_ranges = ranges segment.check() tp = segment.type if segment.type == "bin" and segment.is_name_default(): tp = "unk" if tp not in seg_sizes: seg_sizes[tp] = 0 seg_split[tp] = 0 seg_cached[tp] = 0 seg_sizes[tp] += segment.size if len(segment.errors) == 0: if segment.should_run(): # Check cache cached = segment.cache() if not ignore_cache and cached == cache.get( segment.unique_id()): # Cache hit seg_cached[tp] += 1 else: # Cache miss; split cache[segment.unique_id()] = cached segment.did_run = True segment.split(rom_bytes, repo_path) if len(segment.errors) == 0: processed_segments.append(segment) if platform == "n64" and type( segment) == N64SegCode: # edge case undefined_funcs |= segment.glabels_to_add defined_funcs = { **defined_funcs, **segment.glabels_added } undefined_syms |= segment.undefined_syms_to_add seg_split[tp] += 1 log.dot(status=segment.status()) ld_sections.append(segment.get_ld_section()) for segment in processed_segments: segment.postsplit(processed_segments) log.dot(status=segment.status()) # Write ldscript if "ld" in options["modes"] or "all" in options["modes"]: if verbose: log.write(f"saving {config['basename']}.ld") write_ldscript(config['basename'], repo_path, ld_sections, options) # Write undefined_funcs_auto.txt undefined_funcs_auto_path = get_undefined_funcs_auto_path( repo_path, options) if verbose: log.write(f"saving {undefined_funcs_auto_path}") c_predefined_funcs = set(provided_symbols.keys()) to_write = sorted(undefined_funcs - set(defined_funcs.values()) - c_predefined_funcs) if len(to_write) > 0: with open(undefined_funcs_auto_path, "w", newline="\n") as f: for line in to_write: f.write(line + " = 0x" + line.split("_")[1][:8].upper() + ";\n") # write undefined_syms_auto.txt undefined_syms_auto_path = get_undefined_syms_auto_path(repo_path, options) if verbose: log.write(f"saving {undefined_syms_auto_path}") to_write = sorted(undefined_syms, key=lambda x: x[0]) if len(to_write) > 0: with open(undefined_syms_auto_path, "w", newline="\n") as f: for sym in to_write: f.write(f"{sym[0]} = 0x{sym[1]:X};\n") # print warnings and errors during split/postsplit had_error = False for segment in all_segments: if len(segment.warnings) > 0 or len(segment.errors) > 0: log.write( f"{Style.DIM}0x{segment.rom_start:06X}{Style.RESET_ALL} {segment.type} {Style.BRIGHT}{segment.name}{Style.RESET_ALL}:" ) for warn in segment.warnings: log.write("warning: " + warn, status="warn") for error in segment.errors: log.write("error: " + error, status="error") had_error = True log.write("") # empty line if had_error: return 1 # Statistics unk_size = seg_sizes.get("unk", 0) rest_size = 0 total_size = len(rom_bytes) for tp in seg_sizes: if tp != "unk": rest_size += seg_sizes[tp] assert (unk_size + rest_size == total_size) known_ratio = rest_size / total_size unk_ratio = unk_size / total_size log.write( f"Split {fmt_size(rest_size)} ({known_ratio:.2%}) in defined segments") for tp in seg_sizes: if tp != "unk": tmp_size = seg_sizes[tp] tmp_ratio = tmp_size / total_size log.write( f"{tp:>20}: {fmt_size(tmp_size):>8} ({tmp_ratio:.2%}) {Fore.GREEN}{seg_split[tp]} split{Style.RESET_ALL}, {Style.DIM}{seg_cached[tp]} cached" ) log.write( f"{'unknown':>20}: {fmt_size(unk_size):>8} ({unk_ratio:.2%}) from unknown bin files" ) # Save cache if cache != {}: if verbose: print("Writing cache") with open(cache_path, "wb") as f: pickle.dump(cache, f) return 0 # no error
def run_simulation(args): # Init results class for saving the results # r = Results() if args.verbose: util.verbose = True # Print start message dev_print("Starting simulation") # Set simulation variables num_of_players = args.players # Go through set amount of simulations # Start a new game, run it and save the results # dev_print(args.trading_range) # dev_print(args.upgrading_range) strategy = args.strategy # for k in range(num_of_players): # dev_print(np.arange(args.buying_range[k * 3], args.buying_range[k * 3 + 1], args.buying_range[k * 3 + 2])) # single_player_param_list = [] # for params in player_params: # # single_player_param_list.append(generate_combination(num=7, params=params)) # # dev_print(single_player_param_list) # single_player_list = [] player_combination = None if args.mode in [1, 3]: strategy_parameter = [[ args.strategy_parameter[k * 3] + args.strategy_parameter[k * 3 + 1] * i for i in range(int(args.strategy_parameter[k * 3 + 2])) ] for k in range(num_of_players)] income = [[ args.income[k * 3] + args.income[k * 3 + 1] * i for i in range(int(args.income[k * 3 + 2])) ] for k in range(num_of_players)] tax = [[ args.tax[k * 3] + args.tax[k * 3 + 1] * i for i in range(int(args.tax[k * 3 + 2])) ] for k in range(num_of_players)] b_tax = [[ args.building_tax[k * 3] + args.building_tax[k * 3 + 1] * i for i in range(int(args.building_tax[k * 3 + 2])) ] for k in range(num_of_players)] start_capital = [[ args.start_capital[k * 3] + args.start_capital[k * 3 + 1] * i for i in range(int(args.start_capital[k * 3 + 2])) ] for k in range(num_of_players)] player_params = [[ strategy_parameter[k], income[k], tax[k], start_capital[k], b_tax[k] ] for k in range(num_of_players)] # dev_print(player_params) if args.mode == 3: single_player_param_list = [] for params in player_params: single_player_param_list.append( generate_combination(num=5, params=params)) # dev_print(single_player_param_list) single_player_list = [] for num in range(num_of_players): tmp = [] for p in single_player_param_list[num]: tmp.append( Player(num=num, strategy=strategy[num], strategy_para=p[0], income=p[1], tax=p[2], start_capital=p[3], building_tax=p[4])) single_player_list.append(tmp) player_combination = generate_combination( num=num_of_players, params=single_player_list) elif args.mode == 1: n = int(args.tax[2]) player_combination = [] for i in range(n): tmp = [] for num in range(num_of_players): tmp_player = Player( num=num, strategy=strategy[num], strategy_para=strategy_parameter[num][i], income=income[num][i], tax=tax[num][i], start_capital=start_capital[num][i], building_tax=b_tax[num][i]) tmp.append(tmp_player) player_combination.append(tmp) elif args.mode == 2: player_combination = [] para_list = [ args.strategy_parameter, args.income, args.tax, args.start_capital, args.building_tax ] para_combination = generate_combination(5, para_list) for p in para_combination: tmp = [] for i in range(num_of_players): tmp.append( Player(num=i, strategy=args.strategy[0], strategy_para=p[0], income=p[1], tax=p[2], start_capital=p[3], building_tax=p[4])) player_combination.append(tmp) else: raise ValueError("Unknown type.") count = 1 last = time.time() simulation_list = [] for players in player_combination: cur_simulation_dic = {"settings": {}, "details": {}, "results": {}} player_info_lst = [] for i in range(len(players)): cur_player_dic = { "strategy": players[i].strategy, "strategy_para": players[i].strategy_para, "income": players[i].income, "tax": players[i].tax, "start_capital": players[i].start_capital, "building_tax": players[i].building_tax } player_info_lst.append(cur_player_dic) cur_simulation_dic["settings"] = player_info_lst total_rounds = 0 valid_simulation = 0 if util.verbose: log.write("player combination: " + str(players) + "\n") for i in range(1, args.number + 1): if util.verbose: log.write("simulation number" + str(i) + "\n") for n in players: n.reset() g = Game(players, rounds=args.rounds) tmp_info_dic = g.run() if tmp_info_dic["end"] != -1: total_rounds += tmp_info_dic["end"] valid_simulation += 1 cur_simulation_dic["details"][i] = tmp_info_dic if i % 100 == 0: dev_print( "{} out of {} simulation of combination {} finished.". format(i, args.number, count)) # r.addHitResults(g.board.hits) # Calculate the amount of simulations per second now = time.time() duration = now - last avg_time = duration / args.number try: avg_round = total_rounds / valid_simulation except ZeroDivisionError: avg_round = float("inf") last = time.time() cur_simulation_dic["results"]["avg_time"] = avg_time cur_simulation_dic["results"]["avg_round"] = avg_round cur_simulation_dic["results"]["total_time"] = duration cur_simulation_dic["results"][ "end_percent"] = valid_simulation / args.number # speed = i / (now - start) dev_print("ended: ", valid_simulation) dev_print("avg_time: ", avg_time) dev_print("avg_round: ", avg_round) # Display the progress every 1/1000 of the way to begin finished dev_print("{} out of {} combination finished.".format( count, len(player_combination))) count += 1 simulation_list.append(cur_simulation_dic) metadata_dic["simulations"] = simulation_list prod_print(json.dumps(metadata_dic) + "\n") # Print that the simulation is finished dev_print("\nDone!")
def log(self, msg): if self.options.get("verbose", False): log.write(f"{self.type} {self.name}: {msg}")
def doChanceCard(self, card, board): # Check the type of the chance card # card for moving if util.verbose: log.write("player {0} get a chance card {1}.\n".format( self.num, card)) if card.kind == "advance": # Move to next utilities if necessary if card.value == "utility": # Keep track if suitable utilities is found if util.verbose: log.write( "player {0} goes to the nearest utility.\n".format( self.num)) moved = False # Go through possible utilities for pos in board.TILES_UTILITIES: # If player is before current utility, go to that one if self.position < pos: self.position = pos moved = True break # If not yet moved, go to first utilities in array if not moved: self.position = board.TILES_UTILITIES[0] # Move to next railroad if necessary elif card.value == "railroad": # Keep track if suitable railroad is found if util.verbose: log.write( "player {0} goes to the nearest railroad.\n".format( self.num)) moved = False # Go through possible railroad for pos in board.TILES_TRANSPORT: # If player is before current railroad, go to that one if self.position < pos: self.position = pos moved = True break # If not yet moved, go to first railroad in array if not moved: self.position = board.TILES_TRANSPORT[0] # If negative, thus should move back, do that elif card.value <= 0: self.position, _ = self.getNewPosition(card.value, board) if util.verbose: log.write("player {0} moves to {1}.\n".format( self.num, board.TILE_NAME[self.position])) # Move player to given position otherwise else: self.position = card.value if self.position == board.TILES_JAIL[0]: self.at_jail = True if util.verbose: log.write("player {0} moves to {1}.\n".format( self.num, board.TILE_NAME[self.position])) # card for get money elif card.kind == "cash": if self.cash >= 0: self.cash += card.value else: self.fine_money(-self.cash) if util.verbose: log.write( "player {0} gets {1} cash, currently has {2} cash.\n". format(self.num, card.value, self.cash)) # card for tax elif card.kind == "tax": fined = card.value[0] * self.house + card.value[1] * self.hotel self.fine_money(fined) if util.verbose: log.write( "player {0} pay {1} tax, currently has {2} cash.\n".format( self.num, fined, self.cash))
def move(self, board, dice1, dice2): # Determine whether to go to jail due to double throws if not self.at_jail: if dice1 == dice2: # Add one to the number of consecutive doubles self.consecutiveDoubles += 1 # Signal to go to jail if 3 doubles in a row if self.consecutiveDoubles >= 3: self.go_to_jail() # Reset consecutive throws self.consecutiveDoubles = 0 if util.verbose: log.write( "player {0} goes to jail because of 3 consecutive doubles.\n" .format(self.num)) return else: # Reset consecutive doubles every time different numbers are roled self.consecutiveDoubles = 0 # Calculate new position, overflow if necessary newPosition, pass_go = self.getNewPosition(dice1 + dice2, board) # gain money when pass Go if pass_go: tax = self.pay_tax() self.cash += self.income if util.verbose: log.write( "player {0} pays {1} tax and gains {2} because of passing Go, currently has {3} cash.\n" .format(self.num, tax, self.income, self.cash)) if newPosition >= board.TILES_JAIL[0] > self.position: newPosition += 1 # Apply new position self.position = newPosition if util.verbose: log.write("player {0} move to {1}.\n".format( self.num, board.TILE_NAME[self.position])) else: if util.verbose: log.write("player {0} is in jail.\n".format(self.num)) if dice1 == dice2: self.go_out_of_jail() if util.verbose: log.write( "player {0} goes out of jail because of a double.\n". format(self.num)) return else: self.consecutive_not_Doubles += 1 if self.consecutive_not_Doubles >= 3: self.fine_money(50) self.go_out_of_jail() self.consecutive_not_Doubles = 0 if util.verbose: log.write( "player {0} goes out of jail because of paying 50.\n". format(self.num))
def log(self, msg): if options.verbose(): log.write(f"{self.type} {self.name}: {msg}")
def initialize(all_segments): global all_symbols global symbol_ranges all_symbols = [] symbol_ranges = [] # Manual list of func name / addrs for path in options.get_symbol_addrs_paths(): if path.exists(): with open(path) as f: sym_addrs_lines = f.readlines() for line_num, line in enumerate(sym_addrs_lines): line = line.strip() if not line == "" and not line.startswith("//"): comment_loc = line.find("//") line_main = line line_ext = "" if comment_loc != -1: line_ext = line[comment_loc + 2:].strip() line_main = line[:comment_loc].strip() try: line_split = line_main.split("=") name = line_split[0].strip() addr = int(line_split[1].strip()[:-1], 0) except: log.parsing_error_preamble(path, line_num, line) log.write("Line should be of the form") log.write( "<function_name> = <address> // attr0:val0 attr1:val1 [...]" ) log.write( "with <address> in hex preceded by 0x, or dec") log.write("") raise sym = Symbol(addr, given_name=name) if line_ext: for info in line_ext.split(" "): if ":" in info: if info.count(':') > 1: log.parsing_error_preamble( path, line_num, line) log.write(f"Too many ':'s in '{info}'") log.error("") attr_name, attr_val = info.split(":") if attr_name == "": log.parsing_error_preamble( path, line_num, line) log.write( f"Missing attribute name in '{info}', is there extra whitespace?" ) log.error("") if attr_val == "": log.parsing_error_preamble( path, line_num, line) log.write( f"Missing attribute value in '{info}', is there extra whitespace?" ) log.error("") # Non-Boolean attributes try: if attr_name == "type": type = attr_val sym.type = type continue if attr_name == "size": size = int(attr_val, 0) sym.size = size continue if attr_name == "rom": rom_addr = int(attr_val, 0) sym.rom = rom_addr continue except: log.parsing_error_preamble( path, line_num, line) log.write( f"value of attribute '{attr_name}' could not be read:" ) log.write("") raise # Boolean attributes tf_val = ( True if is_truey(attr_val) else False if is_falsey(attr_val) else None) if tf_val is None: log.parsing_error_preamble( path, line_num, line) log.write( f"Invalid Boolean value '{attr_val}' for attribute '{attr_name}', should be one of" ) log.write([*TRUEY_VALS, *FALSEY_VALS]) log.error("") if attr_name == "dead": sym.dead = tf_val continue if attr_name == "defined": sym.defined = tf_val continue if attr_name == "extract": sym.extract = tf_val continue all_symbols.append(sym) # Symbol ranges if sym.size > 4: symbol_ranges.append(sym) is_symbol_isolated(sym, all_segments)
def main(config_path, base_dir, target_path, modes, verbose, use_cache=True): global config log.write(f"splat {VERSION} (powered by spimdisasm {spimdisasm.__version__})") # Load config config = {} for entry in config_path: with open(entry) as f: additional_config = yaml.load(f.read(), Loader=yaml.SafeLoader) config = merge_configs(config, additional_config) options.initialize(config, config_path, base_dir, target_path) options.set("modes", modes) if verbose: options.set("verbose", True) with options.get_target_path().open("rb") as f2: rom_bytes = f2.read() if "sha1" in config: sha1 = hashlib.sha1(rom_bytes).hexdigest() e_sha1 = config["sha1"].lower() if e_sha1 != sha1: log.error(f"sha1 mismatch: expected {e_sha1}, was {sha1}") # Create main output dir options.get_base_path().mkdir(parents=True, exist_ok=True) processed_segments: List[Segment] = [] seg_sizes: Dict[str, int] = {} seg_split: Dict[str, int] = {} seg_cached: Dict[str, int] = {} # Load cache if use_cache: try: with options.get_cache_path().open("rb") as f3: cache = pickle.load(f3) if verbose: log.write(f"Loaded cache ({len(cache.keys())} items)") except Exception: cache = {} else: cache = {} # invalidate entire cache if options change if use_cache and cache.get("__options__") != config.get("options"): if verbose: log.write("Options changed, invalidating cache") cache = { "__options__": config.get("options"), } configure_disassembler() # Initialize segments all_segments = initialize_segments(config["segments"]) # Load and process symbols symbols.initialize(all_segments) # Assign symbols to segments assign_symbols_to_segments() if options.mode_active("code"): symbols.initialize_spim_context(all_segments) # Resolve raster/palette siblings if options.mode_active("img"): palettes.initialize(all_segments) # Scan scan_bar = tqdm.tqdm(all_segments, total=len(all_segments)) for segment in scan_bar: assert isinstance(segment, Segment) scan_bar.set_description(f"Scanning {brief_seg_name(segment, 20)}") typ = segment.type if segment.type == "bin" and segment.is_name_default(): typ = "unk" if typ not in seg_sizes: seg_sizes[typ] = 0 seg_split[typ] = 0 seg_cached[typ] = 0 seg_sizes[typ] += 0 if segment.size is None else segment.size if segment.should_scan(): # Check cache but don't write anything if use_cache: if segment.cache() == cache.get(segment.unique_id()): continue segment.did_run = True segment.scan(rom_bytes) processed_segments.append(segment) seg_split[typ] += 1 # Split for segment in tqdm.tqdm( all_segments, total=len(all_segments), desc=f"Splitting {brief_seg_name(segment, 20)}", ): if use_cache: cached = segment.cache() if cached == cache.get(segment.unique_id()): # Cache hit seg_cached[typ] += 1 continue else: # Cache miss; split cache[segment.unique_id()] = cached if segment.should_split(): segment.split(rom_bytes) if options.mode_active("ld"): global linker_writer linker_writer = LinkerWriter() for segment in tqdm.tqdm( all_segments, total=len(all_segments), desc=f"Writing linker script {brief_seg_name(segment, 20)}", ): linker_writer.add(segment) linker_writer.save_linker_script() linker_writer.save_symbol_header() # write elf_sections.txt - this only lists the generated sections in the elf, not subsections # that the elf combines into one section if options.get_create_elf_section_list_auto(): section_list = "" for segment in all_segments: section_list += "." + to_cname(segment.name) + "\n" with open(options.get_elf_section_list_path(), "w", newline="\n") as f: f.write(section_list) # Write undefined_funcs_auto.txt if options.get_create_undefined_funcs_auto(): to_write = [ s for s in symbols.all_symbols if s.referenced and not s.defined and not s.dead and s.type == "func" ] to_write.sort(key=lambda x: x.vram_start) with open(options.get_undefined_funcs_auto_path(), "w", newline="\n") as f: for symbol in to_write: f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n") # write undefined_syms_auto.txt if options.get_create_undefined_syms_auto(): to_write = [ s for s in symbols.all_symbols if s.referenced and not s.defined and not s.dead and s.type not in {"func", "label", "jtbl_label"} ] to_write.sort(key=lambda x: x.vram_start) with open(options.get_undefined_syms_auto_path(), "w", newline="\n") as f: for symbol in to_write: f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n") # print warnings during split for segment in all_segments: if len(segment.warnings) > 0: log.write( f"{Style.DIM}0x{segment.rom_start:06X}{Style.RESET_ALL} {segment.type} {Style.BRIGHT}{segment.name}{Style.RESET_ALL}:" ) for warn in segment.warnings: log.write("warning: " + warn, status="warn") log.write("") # empty line # Statistics do_statistics(seg_sizes, rom_bytes, seg_split, seg_cached) # Save cache if cache != {} and use_cache: if verbose: log.write("Writing cache") with open(options.get_cache_path(), "wb") as f4: pickle.dump(cache, f4)
def main(config_path, base_dir, target_path, modes, verbose, use_cache=True): global config # Load config with open(config_path) as f: config = yaml.load(f.read(), Loader=yaml.SafeLoader) options.initialize(config, config_path, base_dir, target_path) options.set("modes", modes) if verbose: options.set("verbose", True) with options.get_target_path().open("rb") as f2: rom_bytes = f2.read() if "sha1" in config: sha1 = hashlib.sha1(rom_bytes).hexdigest() e_sha1 = config["sha1"] if e_sha1 != sha1: log.error(f"sha1 mismatch: expected {e_sha1}, was {sha1}") # Create main output dir options.get_base_path().mkdir(parents=True, exist_ok=True) processed_segments: List[Segment] = [] seg_sizes: Dict[str, int] = {} seg_split: Dict[str, int] = {} seg_cached: Dict[str, int] = {} # Load cache if use_cache: try: with options.get_cache_path().open("rb") as f3: cache = pickle.load(f3) if verbose: log.write(f"Loaded cache ({len(cache.keys())} items)") except Exception: cache = {} else: cache = {} # invalidate entire cache if options change if use_cache and cache.get("__options__") != config.get("options"): if verbose: log.write("Options changed, invalidating cache") cache = { "__options__": config.get("options"), } # Initialize segments all_segments = initialize_segments(config["segments"]) # Load and process symbols if options.mode_active("code"): log.write("Loading and processing symbols") symbols.initialize(all_segments) # Resolve raster/palette siblings if options.mode_active("img"): palettes.initialize(all_segments) # Scan log.write("Starting scan") for segment in all_segments: typ = segment.type if segment.type == "bin" and segment.is_name_default(): typ = "unk" if typ not in seg_sizes: seg_sizes[typ] = 0 seg_split[typ] = 0 seg_cached[typ] = 0 seg_sizes[typ] += 0 if segment.size is None else segment.size if segment.should_scan(): # Check cache but don't write anything if use_cache: if segment.cache() == cache.get(segment.unique_id()): continue if segment.needs_symbols: segment_symbols, other_symbols = get_segment_symbols( segment, all_segments) segment.given_seg_symbols = segment_symbols segment.given_ext_symbols = other_symbols segment.did_run = True segment.scan(rom_bytes) processed_segments.append(segment) seg_split[typ] += 1 log.dot(status=segment.status()) # Split log.write("Starting split") for segment in all_segments: if use_cache: cached = segment.cache() if cached == cache.get(segment.unique_id()): # Cache hit seg_cached[typ] += 1 continue else: # Cache miss; split cache[segment.unique_id()] = cached if segment.should_split(): segment.split(rom_bytes) log.dot(status=segment.status()) if options.mode_active("ld"): global linker_writer linker_writer = LinkerWriter() for segment in all_segments: linker_writer.add(segment) linker_writer.save_linker_script() linker_writer.save_symbol_header() # Write undefined_funcs_auto.txt to_write = [ s for s in symbols.all_symbols if s.referenced and not s.defined and not s.dead and s.type == "func" ] if len(to_write) > 0: with open(options.get_undefined_funcs_auto_path(), "w", newline="\n") as f: for symbol in to_write: f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n") # write undefined_syms_auto.txt to_write = [ s for s in symbols.all_symbols if s.referenced and not s.defined and not s.dead and not s.type == "func" ] if len(to_write) > 0: with open(options.get_undefined_syms_auto_path(), "w", newline="\n") as f: for symbol in to_write: f.write(f"{symbol.name} = 0x{symbol.vram_start:X};\n") # print warnings during split for segment in all_segments: if len(segment.warnings) > 0: log.write( f"{Style.DIM}0x{segment.rom_start:06X}{Style.RESET_ALL} {segment.type} {Style.BRIGHT}{segment.name}{Style.RESET_ALL}:" ) for warn in segment.warnings: log.write("warning: " + warn, status="warn") log.write("") # empty line # Statistics do_statistics(seg_sizes, rom_bytes, seg_split, seg_cached) # Save cache if cache != {} and use_cache: if verbose: log.write("Writing cache") with open(options.get_cache_path(), "wb") as f4: pickle.dump(cache, f4)
def initialize(all_segments: "List[Segment]"): global all_symbols global all_symbols_dict global symbol_ranges all_symbols = [] all_symbols_dict = {} symbol_ranges = [] def get_seg_for_name(name: str) -> Optional["Segment"]: for segment in all_segments: if segment.name == name: return segment return None # Manual list of func name / addrs for path in options.get_symbol_addrs_paths(): if path.exists(): with open(path) as f: sym_addrs_lines = f.readlines() for line_num, line in enumerate( tqdm.tqdm(sym_addrs_lines, desc=f"Loading symbols ({path.stem})")): line = line.strip() if not line == "" and not line.startswith("//"): comment_loc = line.find("//") line_main = line line_ext = "" if comment_loc != -1: line_ext = line[comment_loc + 2:].strip() line_main = line[:comment_loc].strip() try: line_split = line_main.split("=") name = line_split[0].strip() addr = int(line_split[1].strip()[:-1], 0) except: log.parsing_error_preamble(path, line_num, line) log.write("Line should be of the form") log.write( "<function_name> = <address> // attr0:val0 attr1:val1 [...]" ) log.write( "with <address> in hex preceded by 0x, or dec") log.write("") raise sym = Symbol(addr, given_name=name) ignore_sym = False if line_ext: for info in line_ext.split(" "): if ":" in info: if info.count(":") > 1: log.parsing_error_preamble( path, line_num, line) log.write(f"Too many ':'s in '{info}'") log.error("") attr_name, attr_val = info.split(":") if attr_name == "": log.parsing_error_preamble( path, line_num, line) log.write( f"Missing attribute name in '{info}', is there extra whitespace?" ) log.error("") if attr_val == "": log.parsing_error_preamble( path, line_num, line) log.write( f"Missing attribute value in '{info}', is there extra whitespace?" ) log.error("") # Non-Boolean attributes try: if attr_name == "type": type = attr_val sym.type = type continue if attr_name == "size": size = int(attr_val, 0) sym.given_size = size continue if attr_name == "rom": rom_addr = int(attr_val, 0) sym.rom = rom_addr continue if attr_name == "segment": seg = get_seg_for_name(attr_val) if seg is None: log.parsing_error_preamble( path, line_num, line) log.write( f"Cannot find segment '{attr_val}'" ) log.error("") else: # Add segment to symbol, symbol to segment sym.segment = seg seg.add_symbol(sym) continue except: log.parsing_error_preamble( path, line_num, line) log.write( f"value of attribute '{attr_name}' could not be read:" ) log.write("") raise # Boolean attributes tf_val = ( True if is_truey(attr_val) else False if is_falsey(attr_val) else None) if tf_val is None: log.parsing_error_preamble( path, line_num, line) log.write( f"Invalid Boolean value '{attr_val}' for attribute '{attr_name}', should be one of" ) log.write([*TRUEY_VALS, *FALSEY_VALS]) log.error("") else: if attr_name == "dead": sym.dead = tf_val continue if attr_name == "defined": sym.defined = tf_val continue if attr_name == "extract": sym.extract = tf_val continue if attr_name == "ignore": ignore_sym = tf_val continue if ignore_sym: ignored_addresses.add(sym.vram_start) ignore_sym = False continue sym.user_declared = True add_symbol(sym) # Symbol ranges if sym.size > 4: symbol_ranges.append(sym)