Пример #1
0
def board_private_company_info():
    coord = request.args.get("coord")
    company = request.args.get("company")
    phase = request.args.get("phase")

    default_offset = {"x": 0, "y": 0}
    private_company_offsets = get_private_offsets(get_game(g.game_name))
    offset_data = private_company_offsets.get(company, {})
    coord_offset = offset_data.get(coord, {}).get("offset", default_offset)

    if set(coord_offset.keys()) == {"x", "y"}:
        offset = coord_offset
    else:
        game = get_game(g.game_name)
        for offset_phase in sorted(coord_offset,
                                   key=game.phases.index,
                                   reverse=True):
            if game.compare_phases(offset_phase, phase) >= 0:
                offset = coord_offset[offset_phase]
                break
        else:
            # This indicates a special offset will be needed in later phases,
            # but we can use the default offset for now.
            offset = default_offset

    info = {"offset": offset}

    return jsonify({"info": info})
Пример #2
0
def legal_tiles():
    game = get_game(g.game_name)

    coord = request.args.get("coord")

    LOG.info(f"Legal tiles request for {coord}.")

    legal_tile_ids = _legal_tile_ids_by_coord(get_game(g.game_name), coord)
    legal_tile_ids.sort(key=lambda tile_id:
                        f"{game.tiles[tile_id].upgrade_level}-{tile_id:0>3}")

    LOG.info(f"Legal tiles response for {coord}: {legal_tile_ids}")

    return jsonify({"legal-tile-ids": legal_tile_ids})
Пример #3
0
def _get_split_city_stations(coord, tile_id, orientation):
    game = get_game(g.game_name)
    board = get_board(game)
    cell = board.cell(coord)

    if tile_id and orientation:
        split_city_space = placedtile.SplitCity.place(cell,
                                                      game.tiles[tile_id],
                                                      orientation)
    else:
        split_city_space = board.get_space(cell)

    split_city_station_coords = set()
    for branch in split_city_space.capacity.keys():
        unique_exit_coords = [
            branch_key for branch_key in branch if len(branch_key) == 1
        ]
        if unique_exit_coords:
            # A unique exit coord is a sequence of length 1, so we need to extract it
            split_city_station_coords.add(str(
                sorted(unique_exit_coords)[0][0]))
        else:
            split_city_station_coords.add(str(sorted(branch)[0]))

    return split_city_station_coords
Пример #4
0
def _phase_from_trains(train_strs_json):
    train_strs = json.loads(train_strs_json)
    if train_strs:
        train_info = get_train_info(g.game_name)
        return max(
            train.phase
            for train in trains_mod.convert(train_info, ",".join(train_strs)))
    else:
        return get_game(g.game_name).phases[0]
Пример #5
0
def legal_token_coords():
    game = get_game(g.game_name)
    private_companies = game.get_game_submodule("private_companies")
    if not private_companies:
        return jsonify({"coords": {}})

    LOG.info("Legal private company token coordinates request.")

    private_company_coords = private_companies.PRIVATE_COMPANY_COORDS

    LOG.info(
        f"Legal private company token coordinates response: {private_company_coords}"
    )

    return jsonify({"coords": private_company_coords})
Пример #6
0
def calculate_worker(game_name, railroads_state_rows, private_companies_rows, board_state_rows, railroad_name):
    game = get_game(game_name)
    board_state = boardstate.load(game, [dict(zip(boardstate.FIELDNAMES, row)) for row in board_state_rows if any(val for val in row)])
    railroad_dict = railroads.load(game, board_state, [dict(zip(railroads.FIELDNAMES, row)) for row in railroads_state_rows if any(val for val in row)])
    game.capture_phase(railroad_dict)

    private_companies = game.get_game_submodule("private_companies")
    if private_companies:
        private_companies.load(game, board_state, railroad_dict, [dict(zip(private_companies.FIELDNAMES, row)) for row in private_companies_rows if any(val for val in row)])
    board_state.validate()

    if railroad_name not in railroad_dict:
        valid_railroads = ", ".join(railroad_dict.keys())
        raise ValueError(f"Railroad chosen: \"{railroad_name}\". Valid railroads: {valid_railroads}")

    return find_best_routes(game, board_state, railroad_dict, railroad_dict[railroad_name])
Пример #7
0
def closable_railroads():
    LOG.info("Closable railroads request.")

    game = get_game(g.game_name)
    closable_railroads = _get_closable_railroads(game)

    LOG.info(f"Closable railroads response: {closable_railroads}")

    railroads_info = get_railroad_info(game)
    return jsonify({
        "railroads": list(sorted(closable_railroads)),
        "home-cities": {
            railroad: railroads_info[railroad]["home"]
            for railroad in closable_railroads
        }
    })
Пример #8
0
def private_companies_open():
    game = get_game(g.game_name)
    private_companies = game.get_game_submodule("private_companies")
    if not private_companies:
        return jsonify({"private-companies": []})

    LOG.info("Open private companies request.")

    phase = _phase_from_trains(request.args.get("trains"))
    private_companies = [
        private_company for private_company in private_companies.COMPANIES
        if not game.private_is_closed(private_company, phase)
    ]

    LOG.info(f"Open private companies response: {private_companies}")

    return jsonify({"private-companies": private_companies})
Пример #9
0
def legal_orientations():
    coord = request.args.get("coord")
    tile_id = request.args.get("tileId")

    LOG.info(f"Legal orientations request for {tile_id} at {coord}.")

    orientations, translations = _get_orientations(get_game(g.game_name),
                                                   coord, tile_id)

    LOG.info(
        f"Legal orientations response for {tile_id} at {coord}: {orientations}"
    )

    return jsonify({
        "legal-orientations":
        list(sorted(orientations))
        if orientations is not None else orientations,
        "translations":
        translations
    })
Пример #10
0
def main():
    migration_data = migrate.process_migrate_data()

    game = get_game(g.game_name)
    board = get_board(game)

    stop_names = {}
    for cell in board.cells:
        space = board.get_space(cell)
        if space and space.is_stop:
            stop_names[str(cell)] = space.nickname

    termini_boundaries = {
        name: info["boundaries"]
        for name, info in get_termini_boundaries(game).items()
    }

    private_companies = game.get_game_submodule("private_companies")
    private_company_names = private_companies.COMPANIES.keys(
    ) if private_companies else []
    private_company_column_names = [
        PRIVATE_COMPANY_COLUMN_MAP[colname]
        for colname in private_companies.FIELDNAMES
    ] if private_companies else []

    return render_template(
        "index.html",
        private_company_default_token_coords=private_companies.
        PRIVATE_COMPANY_DEFAULT_COORDS if private_companies else {},
        private_company_rownames=private_company_names,
        placed_tiles_colnames=PLACED_TILES_COLUMN_NAMES,
        tile_coords=get_tile_coords(board),
        stop_names=stop_names,
        termini_boundaries=termini_boundaries,
        removable_railroads=_get_removable_railroads(),
        closable_railroads=_get_closable_railroads(game),
        board_layout=_get_board_layout_info(),
        migration_data=migration_data)
Пример #11
0
def _convert_migration_data(migration_data):
    converted_data = {
        "removedRailroadsTable": migration_data.get("removedRailroadsTable",
                                                    ""),
        "privateCompaniesTable": migration_data.get("privateCompaniesTable",
                                                    ""),
        "hideStopPaths": migration_data.get("hideCityPaths", "")
    }

    if "placedTilesTable" in migration_data:
        rotation_map = _get_placement_info(get_game("1846"),
                                           "rotation-map.json")
        converted_data["placedTilesTable"] = []
        for tile_row in json.loads(migration_data["placedTilesTable"]):
            converted_data["placedTilesTable"].append([
                tile_row[0],
                str(tile_row[1]),
                str((int(tile_row[2]) - rotation_map[str(tile_row[1])]) % 6)
            ])
        converted_data["placedTilesTable"] = json.dumps(
            converted_data["placedTilesTable"])

    if "railroadsTable" in migration_data:
        converted_data["railroadsTable"] = []
        for railroad_row in json.loads(migration_data["railroadsTable"]):
            new_stations_coords = []
            for station_coord in railroad_row[2].split(','):
                new_stations_coords.append(
                    f"{station_coord}:{railroad_row[3]}" if station_coord ==
                    "D6" else station_coord)
            converted_data["railroadsTable"].append([
                railroad_row[0], railroad_row[1], ",".join(new_stations_coords)
            ])
        converted_data["railroadsTable"] = json.dumps(
            converted_data["railroadsTable"])

    return converted_data
Пример #12
0
def _validate_migration_data(migration_data):
    if not isinstance(migration_data, dict):
        LOG.debug(
            f"Migration validation failure: migration_data is not a dict")
        return {"error": "Failed to load migration data."}

    game = get_game("1846")
    railroad_info = get_railroad_info(game)
    private_companies = game.get_game_submodule("private_companies")
    for key, value in migration_data.items():
        # Make sure no control characters or non-ASCII characters are present.
        if not key.isascii() or not key.isprintable() or not value.isascii(
        ) or not value.isprintable():
            LOG.debug(
                f"Migration failure: key or value is not printable ASCII")
            return False

        try:
            migration_data[key] = json.dumps(json.loads(value))
        except Exception as exc:
            LOG.debug(
                f"Migration validation failure[{key}]: value not valid JSON: {value}"
            )
            return False

        if key == "placedTilesTable":
            tiles_json = json.loads(value)
            if not all(len(row) == 3 for row in tiles_json) or not all(
                    str(col).isalnum() for row in tiles_json for col in row):
                LOG.debug(f"Migration validation failure[{key}]: {value}")
                return False
        elif key == "railroadsTable":
            railroads_json = json.loads(value)
            for row in railroads_json:
                if len(row) not in (3,
                                    4) or row[0].strip() not in railroad_info:
                    LOG.debug(
                        f"Migration validation failure[{key}]: row wrong length, or railroad name invalid: {value}"
                    )
                    return False
                if row[1] and row[1].strip():
                    train_strs = [
                        train_str.strip().split("/", 1)
                        for train_str in row[1].strip().split(",")
                    ]
                    if not all(val.strip().isdigit()
                               for train_str in train_strs
                               for val in train_str):
                        LOG.debug(
                            f"Migration validation failure[{key}]: trains malformed: {value}"
                        )
                        return False
                if row[2] and row[2].strip():
                    if not all(station_str.strip().isalnum()
                               for station_str in row[2].strip().split(",")):
                        LOG.debug(
                            f"Migration validation failure[{key}]: stations malformed: {value}"
                        )
                        return False
        elif key == "removedRailroadsTable":
            removed_railroads = json.loads(value)
            for railroad in removed_railroads:
                if railroad.strip() not in railroad_info:
                    LOG.debug(
                        f"Migration validation failure[{key}]: railroad name invalid: {value}"
                    )
                    return False
        elif key == "privateCompaniesTable":
            private_companies_json = json.loads(value)
            for row in private_companies_json:
                if len(row) != 3 \
                        or row[0].strip() not in private_companies.COMPANIES \
                        or (row[1] and row[1].strip() not in railroad_info) \
                        or (row[2] and not row[2].strip().isalnum()):
                    LOG.debug(
                        f"Migration validation failure[{key}]: invalid row: {row}"
                    )
                    return False
        elif key == "hideCityPaths":
            if value not in ("true", "false"):
                LOG.debug(f"Migration validation failure[{key}]: {value}")
                return False
        else:
            LOG.debug(f"Migration validation failure: invalid key: {key}")
            return False

    return True
Пример #13
0
def board_space_info():
    coord = request.args["coord"].strip()
    tile_id = request.args.get("tileId", "").strip()
    orientation = request.args.get("orientation", "").strip()
    phase = request.args.get("phase")

    game = get_game(g.game_name)
    board = get_board(game)
    railroad_info = get_railroad_info(game)
    cell = board.cell(coord)

    station_offsets = get_station_offsets(game)
    if tile_id and orientation:
        offset_data = station_offsets.get("tile", {})
        offset = _get_station_offset(offset_data, tile_id)

        space = placedtile.PlacedTile.place(cell, game.tiles[tile_id],
                                            orientation, board.get_space(cell))
        if isinstance(space, placedtile.SplitCity):
            # In the offset file, branches are indicated by side. To translate
            # into cells, add the orientation, and modulo by 6 to retrieve its
            # neighbor given the orientation.
            offset = {
                str(cell.neighbors[(int(exit) + int(orientation)) % 6]):
                offsetCoords
                for exit, offsetCoords in offset.items()
            }

        if "rotation" in offset:
            offset["rotation"] = math.radians(offset["rotation"])
    else:
        offset_data = station_offsets.get("board", {})
        offset = _get_station_offset(offset_data, coord)
        space = board.get_space(cell)

        if "rotation" in offset:
            offset["rotation"] = math.radians(offset["rotation"])

    if hasattr(space, "capacity"):
        # Stop-gap. I need to figure out what to actually do with capacity keys.
        capacity = sum(space.capacity.values()) if isinstance(
            space.capacity, dict) else space.capacity
    else:
        capacity = 0

    home = [
        railroad for railroad, info_dict in railroad_info.items()
        if info_dict.get("home") == coord
    ]
    if not phase or (game.rules.stations_reserved_until
                     and game.compare_phases(
                         game.rules.stations_reserved_until, phase) < 0):
        reserved = [
            railroad for railroad, info_dict in railroad_info.items()
            if coord in info_dict.get("reserved", [])
        ]
    else:
        reserved = []

    info = {
        "capacity":
        capacity,
        "offset":
        offset,
        "phase":
        getattr(space, "upgrade_level", 0),
        "is-split-city":
        isinstance(space, (boardtile.SplitCity, placedtile.SplitCity)),
        "home-to":
        home,
        "reserved-for":
        reserved
    }

    return jsonify({"info": info})