def decode_ant_vision_2d_examples(encoded_examples: Tuple[ndarray, ndarray]) -> List[AntVision2DExample]: gst = GameStateTranslator() features, labels = encoded_examples feature_example_count = features.shape[0] feature_row_min = 0 - floor(features.shape[1] / 2) feature_row_max = 0 + floor(features.shape[1] / 2) feature_col_min = 0 - floor(features.shape[2] / 2) feature_col_max = 0 + floor(features.shape[2] / 2) row_nums = seq(range(feature_row_min, feature_row_max)).to_list() col_nums = seq(range(feature_col_min, feature_col_max)).to_list() if features.shape[3] != 7: raise ValueError( 'Only implemented for 7 channel encoding since down_sampling eliminates information') items = [] for ex_index in range(feature_example_count): example_features: Dict[Position, PositionState] = {} for row_index, row_num in enumerate(row_nums): for col_index, col_num in enumerate(col_nums): position = Position(row_num, col_num) enum_val = gst.convert_array_to_enum(features[ex_index, row_index, col_index].tolist(), PositionState) example_features[position] = enum_val direction = gst.convert_array_to_enum(labels[ex_index].tolist(), Direction) items.append(AntVision2DExample(example_features, direction)) return items
def test_create_nn_input(self): game_state = create_test_game_state() test_ant = game_state.game_turns[0].ants.get(Position(1, 19)) ant_vision = game_state.game_map.get_positions_within_distance( test_ant.position, game_state.view_radius_squared) translator = GameStateTranslator() nn_input = translator.convert_to_1d_example(test_ant, game_state) self.assertIsNotNone(nn_input) self.assertEqual((len(ant_vision) - 1), len(nn_input.features))
def test_convert_enums_to_array(self): translator = GameStateTranslator() array = translator.convert_enum_to_array(PositionState.LAND, PositionState) self.assertEqual([0, 0, 0, 0, 0, 0, 1], array) self.assertEqual( PositionState.LAND, translator.convert_array_to_enum(array, PositionState)) self.assertIsNone( translator.convert_array_to_enum([0, 0, 0, 0, 0, 0, 0], PositionState))
def encode_map_examples(examples: List[AntMapExample], channel_count: int) -> Tuple[ndarray, ndarray]: gst = GameStateTranslator() if len(examples) == 0: return numpy.empty([0, 43, 39, 7], dtype=int), numpy.empty([0, 5], dtype=int) ex = examples[0] features = numpy.zeros([len(examples), ex.row_count, ex.column_count, channel_count], dtype=int) for e_index, e in enumerate(examples): for r in range(ex.row_count): for c in range(ex.column_count): key = Position(r, c) features[e_index, r, c] = down_sample(gst, e.features[key], channel_count) labels = [gst.convert_enum_to_array(ex.label, Direction) for ex in examples] return numpy.array(features), numpy.array(labels)
def __init__(self, game_identifier: str, name: BotName, model_path: str): super().__init__(game_identifier, name) self.game_options: Dict[str, int] = {} self.game_map: GameMap = None self.visible_ants: Dict[Position, VisibleAnt] = {} self.visible_food: Set[Position] = set() self.visible_hills: Dict[Position, VisibleHill] = {} self.pending_orders: List[Order] = [] self.channel_count = 7 self.gst = GameStateTranslator() self.model: Model = keras.models.load_model(model_path) print(self.model.input.shape)
def map_to_input( task: Tuple[str, EncodingType, str]) -> Tuple[np.ndarray, np.ndarray]: bot_name, type, game_path = task channel_count = 7 gst = GameStateTranslator() if type == EncodingType.ANT_VISION_2D: feature_cache_path = game_path.replace( '.json', f'_ANT_VISION_2D_FEATURES_{bot_name}_{channel_count}.npy') label_cache_path = game_path.replace( '.json', f'_ANT_VISION_2D_LABELS_{bot_name}_{channel_count}.npy') if os.path.exists(feature_cache_path): return np.load(feature_cache_path), np.load(label_cache_path) gs = load_game_state(game_path) try: ant_vision = gst.convert_to_2d_ant_vision(bot_name, [gs]) features, labels = enc.encode_2d_examples(ant_vision, channel_count) print(f'Saving {feature_cache_path}') np.save(feature_cache_path, features) np.save(label_cache_path, labels) return features, labels except: print(f'Failed to load ${game_path}') return np.empty([0, 12, 12, 7]), np.empty([0, 5]) elif type == EncodingType.MAP_2D: feature_cache_path = game_path.replace( '.json', f'_ANT_VISION_2DMAP_FEATURES_{bot_name}_{channel_count}.npy') label_cache_path = game_path.replace( '.json', f'_ANT_VISION_2DMAP_LABELS_{bot_name}_{channel_count}.npy') if os.path.exists(feature_cache_path): return np.load(feature_cache_path), np.load(label_cache_path) gs = load_game_state(game_path) try: ant_vision = gst.convert_to_antmap(bot_name, [gs]) features, labels = enc.encode_map_examples(ant_vision, channel_count) print(f'Saving {feature_cache_path}') np.save(feature_cache_path, features) np.save(label_cache_path, labels) return features, labels except: print(f'Failed to load ${game_path}') return np.empty([0, 43, 39, 7]), np.empty([0, 5]) else: raise NotImplementedError()
def decode_map_examples(encoded_examples: Tuple[ndarray, ndarray]) -> List[AntMapExample]: features, labels = encoded_examples items = [] gst = GameStateTranslator() row_count = features.shape[1] col_count = features.shape[2] for ex_index in range(features.shape[0]): example_features: Dict[Position, PositionState] = {} for row_num in range(features.shape[1]): for col_num in range(features.shape[2]): position = Position(row_num, col_num) enum_val = gst.convert_array_to_enum(features[ex_index, row_num, col_num].tolist(), PositionState) example_features[position] = enum_val direction = gst.convert_array_to_enum(labels[ex_index].tolist(), Direction) items.append(AntMapExample(example_features, direction, row_count, col_count)) return items
def test_encode_2d_map(self): bot_to_emulate = 'pkmiec_1' gsg = GameStateGenerator() gst = GameStateTranslator() test_game_state = gsg.generate_from_file(self.data_path) expected_map = gst.convert_to_antmap(bot_to_emulate, [test_game_state]) actual_encoded_map = map_to_input( (bot_to_emulate, EncodingType.MAP_2D, self.data_path)) actual_decoded_map = decode_map_examples(actual_encoded_map) for index, expected in enumerate(expected_map): self.assertEqual(expected.label, actual_decoded_map[index].label) for expected_pos in expected.features.keys(): self.assertEqual( expected.features[expected_pos], actual_decoded_map[index].features[expected_pos])
def profile_encoding(): bot_to_emulate = 'memetix_1' game_paths = [ f for f in glob.glob( f'{os.getcwd()}\\training\\tests\\test_data\\**\\*.json') ] test_games = game_paths[2:3] gst = GameStateTranslator() gsg = GameStateGenerator() pr = cProfile.Profile() pr.enable() game_states = seq(test_games).map( lambda path: load_game_state(path, gsg)).to_list() mv_features, mv_labels = enc.encode_map_examples( gst.convert_to_global_antmap(bot_to_emulate, game_states), 7) pr.disable() # pr.print_stats(sort='cumtime') pr.dump_stats('ants_example_python.profile')
def down_sample(gst: GameStateTranslator, ps: PositionState, channel_count: int): if channel_count == 7: return gst.convert_enum_to_array(ps, PositionState) elif channel_count == 3: if ps == PositionState.FRIENDLY_ANT or ps == PositionState.FRIENDLY_HILL: return [1, 0, 0] elif ps == PositionState.HOSTILE_ANT or ps == PositionState.HOSTILE_HILL: return [0, 1, 0] elif ps == PositionState.FOOD: return [0, 0, 1] else: return [0, 0, 0] else: raise ValueError('Not implemented')
def __init__(self, game_paths: List[str], batch_size: int, bot_to_emulate: str, channel_count=7, dataset_type: DatasetType = DatasetType.TRAINING): self.batch_size = batch_size self.channel_count = channel_count self.bot_to_emulate = bot_to_emulate self.game_paths = sk.utils.shuffle(game_paths) self.gst = GameStateTranslator() self.gsg = GameStateGenerator() self.game_indexes: List[GameIndex] = [] self.loaded_indexes: List[LoadedIndex] = [] self.max_load_count = 10 self.dataset_type = dataset_type if len(game_paths) == 0: raise ValueError( 'Must provide at least one game path for the index')
class NNBot(Bot): def __init__(self, game_identifier: str, name: BotName, model_path: str): super().__init__(game_identifier, name) self.game_options: Dict[str, int] = {} self.game_map: GameMap = None self.visible_ants: Dict[Position, VisibleAnt] = {} self.visible_food: Set[Position] = set() self.visible_hills: Dict[Position, VisibleHill] = {} self.pending_orders: List[Order] = [] self.channel_count = 7 self.gst = GameStateTranslator() self.model: Model = keras.models.load_model(model_path) print(self.model.input.shape) def start(self, start_data: str): self.game_options = seq(start_data.split('\n')) \ .filter(lambda line: line != '') \ .map(lambda opt: (opt.split(' ')[0], int(opt.split(' ')[1]))) \ .to_dict() self.game_map = create_map(self.game_options['rows'], self.game_options['cols']) def convert_pos_to_state(self, pos: Position) -> PositionState: if self.visible_ants.get(pos) is not None: return PositionState.FRIENDLY_ANT if self.visible_ants[ pos].is_friendly() else PositionState.HOSTILE_ANT if self.visible_hills.get(pos) is not None: return PositionState.FRIENDLY_HILL if self.visible_hills.get( pos).is_friendly() else PositionState.HOSTILE_HILL if pos in self.visible_food: return PositionState.FOOD return PositionState.WATER if self.game_map.get_terrain( pos) == TerrainType.WATER else PositionState.LAND def create_predictions( self, ants: List[VisibleAnt]) -> List[Tuple[VisibleAnt, Direction]]: def map_to_position_state( ant: VisibleAnt) -> Dict[Position, PositionState]: ant_vision = self.game_map.get_positions_within_distance( ant.position, self.game_options['viewradius2'], use_absolute=False, crop_to_square=True) position_states = { av: self.convert_pos_to_state( self.game_map.wrap_position( ant.position.row + av.row, ant.position.column + av.column)) for av in ant_vision } return position_states def convert_prediction_to_direction( ant: VisibleAnt, prediction: List) -> Tuple[VisibleAnt, Direction]: pred = [0] * 5 pred[numpy.array(prediction).argmax()] = 1 d: Direction = self.gst.convert_array_to_enum(pred, Direction) return ant, d position_states = seq(ants).map(map_to_position_state).to_list() features = encode_2d_features(position_states, self.gst, self.channel_count) predictions = self.model.predict(features) mapped_predictions = [ convert_prediction_to_direction(ants[index], prediction) for index, prediction in enumerate(predictions) ] return mapped_predictions def create_orders(self) -> List[Order]: friendly_ants = seq(self.visible_ants.values()) \ .filter(lambda a: a.is_friendly()) \ .to_list() pending_orders = seq(friendly_ants) \ .map(lambda va: Order(va.position, Direction.NONE, self.game_map.adjacent_movement_position(va.position, Direction.NONE))) \ .to_list() predictions: List[Tuple[ VisibleAnt, Direction]] = self.create_predictions(friendly_ants) pass_through_count = 0 while seq(pending_orders).filter( lambda po: po.dir == Direction.NONE).len( ) > 0 and pass_through_count < 3: for index, order in enumerate(pending_orders): # pylint: disable=cell-var-from-loop matching_prediction = seq(predictions).find( lambda t: t[0].position == order.position) new_order_position = self.game_map.adjacent_movement_position( order.position, matching_prediction[1]) # pylint: disable=cell-var-from-loop conflicting_order = seq(pending_orders).find( lambda po: po.next_position == new_order_position) if conflicting_order is None: pending_orders[index] = Order(order.position, matching_prediction[1], new_order_position) pass_through_count += 1 return pending_orders def play_turn(self, play_turn_data: str): def parse_segments(line: str) -> Tuple[str, Position, Optional[int]]: segments = line.split(' ') return segments[0], Position(int(segments[1]), int( segments[2])), int(segments[3]) if len(segments) == 4 else None input_data = seq(play_turn_data.split('\n')) \ .filter(lambda line: line != '') \ .map(parse_segments) \ .to_list() seq(input_data).filter(lambda t: t[0] == 'w').for_each( lambda t: self.game_map.update_terrain(t[1], TerrainType.WATER)) self.visible_hills = seq(input_data).filter(lambda t: t[0] == 'h').map( lambda t: (t[1], VisibleHill(t[1], t[2]))).to_dict() self.visible_ants = seq(input_data).filter(lambda t: t[0] == 'a').map( lambda t: (t[1], VisibleAnt(t[1], t[2]))).to_dict() self.visible_food = seq(input_data).filter(lambda t: t[0] == 'f').map( lambda t: t[1]).to_set() self.pending_orders = self.create_orders() def read_lines(self): orders = seq(self.pending_orders).map(str).to_list() return orders
def test_create_2d_ant_vision(self): game_state = create_test_game_state() translator = GameStateTranslator() translated = translator.convert_to_2d_ant_vision( 'pkmiec_1', [game_state]) self.assertIsNotNone(translated)
def encode_2d_examples(examples: List[AntVision2DExample], channel_count: int) -> Tuple[ndarray, ndarray]: gst = GameStateTranslator() features = encode_2d_features(seq(examples).map(lambda e: e.features).to_list(), gst, channel_count) labels = numpy.array([gst.convert_enum_to_array(ex.label, Direction) for ex in examples]) return features, labels
import cProfile import glob from ants_ai.training.neural_network.encoders.game_state_translator import GameStateTranslator from ants_ai.training.tests.test_utils import create_test_game_state from ants_ai.training.game_state.generator import GameStateGenerator from functional import seq import jsonpickle import os from ants_ai.training.game_state.game_state import GameState from ants_ai.training.neural_network.encoders import encoders as enc game_state = create_test_game_state() translator = GameStateTranslator() def load_game_state(path: str, gsg: GameStateGenerator) -> GameState: with open(path, "r") as f: json_data = f.read() pr = jsonpickle.decode(json_data) return gsg.generate(pr) def convert_game_state(): bot_to_emulate = 'memetix_1' game_paths = [ f for f in glob.glob( f'{os.getcwd()}\\training\\tests\\test_data\\**\\*.json') ] test_games = game_paths[2:3] gst = GameStateTranslator()