Ejemplo n.º 1
0
def parseBoard(name: str) -> GameBoard:
    bData = TMPL_BOARDS[name]
    shape = tuple(bData['shape'])
    board = GameBoard(shape, name)

    terrain = np.full(shape,
                      TERRAIN_TYPE[bData['default']].level,
                      dtype='uint8')

    for tName, tData in bData['terrain'].items():
        level = TERRAIN_TYPE[tName].level
        for elem in tData:
            if 'line' in elem:
                e = elem['line']
                fillLine(terrain, (e[0], e[1]), (e[2], e[3]), level)
            if 'region' in elem:
                start, end = elem['region'].split(',')
                terrain[parse_slice(start), parse_slice(end)] = level
            if 'row_alternate' in elem:
                low, high = elem['row_alternate']
                for i in range(board.shape[0]):
                    j = low if i % 2 == 0 else high
                    terrain[i, j] = level

    board.addTerrain(terrain)

    return board
Ejemplo n.º 2
0
def addObjectives(board: GameBoard, team: str, objective: str, value) -> None:
    """Add an objective for a given team to the board using the given values."""
    other = BLUE if team == RED else RED
    obj = None
    if objective == 'eliminate_opponent':
        obj = GoalEliminateOpponent(team, other)
    if objective == 'reach_point':
        value = [tuple(w) for w in value]
        obj = GoalReachPoint(team, board.shape, value)
    if objective == 'defend_point':
        value = [tuple(w) for w in value]
        obj = GoalDefendPoint(team, other, board.shape, value)
    if objective == 'max_turn':
        obj = GoalMaxTurn(team, value)
    if obj:
        board.addObjectives(obj)
Ejemplo n.º 3
0
    def setUp(self):
        collect()

        self.shape = (8, 8)
        self.board = GameBoard(self.shape)
        self.state = GameState(self.shape)

        self.blue_tank = buildFigure('Tank', (4, 6), BLUE)
        self.red_tank = buildFigure('Tank', (4, 1), RED)
        self.red_inf = buildFigure('Infantry', (1, 4), RED)

        self.state.addFigure(self.red_tank, self.red_inf, self.blue_tank)

        los_on_target = self.state.getLOS(self.blue_tank)

        self.los_tank = los_on_target[self.red_tank.index]
        self.los_inf = los_on_target[self.red_inf.index]
Ejemplo n.º 4
0
    def setUp(self):
        collect()

        shape = (16, 16)
        self.board = GameBoard(shape)
        self.state = GameState(shape)

        self.tank = buildFigure('Tank', (8, 8), RED)
        self.state.addFigure(self.tank)
Ejemplo n.º 5
0
    def buildSupportAttacks(self, board: GameBoard, state: GameState,
                            figure: Figure) -> List[AttackGround]:
        """Returns a list of all possible SupportAttack actions that can be performed."""

        supports = []

        for _, weapon in figure.weapons.items():
            if weapon.smoke:
                grounds = board.getRange(figure.position, weapon.max_range)
                for ground in grounds:
                    supports.append(
                        self.actionAttackGround(figure, ground, weapon))

        return supports
Ejemplo n.º 6
0
    def setUp(self):
        collect()

        shape = (16, 16)
        self.board = GameBoard(shape)
        self.state = GameState(shape)

        self.red_tank = buildFigure('Tank', (0, 6), RED)
        self.red_inf = buildFigure('Infantry', (0, 12), RED)

        self.blue_tank = buildFigure('Tank', (15, 6), BLUE)
        self.blue_inf = buildFigure('Infantry', (15, 12), BLUE)

        self.state.addFigure(self.red_tank, self.red_inf, self.blue_tank,
                             self.blue_inf)
Ejemplo n.º 7
0
    def testMoveOnRoad(self):
        shape = (1, 16)
        board = GameBoard(shape)

        t = buildFigure('Tank', (0, 0), RED)
        i = buildFigure('Infantry', (0, 15), RED)

        stateTank = GameState(shape)
        stateTank.addFigure(t)

        stateInf = GameState(shape)
        stateInf.addFigure(i)

        # movements without road
        nTankNoRoad = len(GM.buildMovements(board, stateTank, t))
        nInfNoRoad = len(GM.buildMovements(board, stateInf, i))

        # adding road
        road = np.zeros(shape, 'uint8')
        road[0, :] = TERRAIN_TYPE['ROAD'].level
        board.addTerrain(road)

        # test for vehicles
        nTankRoad = len(GM.buildMovements(board, stateTank, t))
        nInfRoad = len(GM.buildMovements(board, stateInf, i))

        # tank
        self.assertNotEqual(nTankRoad, nTankNoRoad,
                            'road has no influence for tank')
        self.assertEqual(nTankRoad, 8, 'invalid distance with road for tank')
        self.assertEqual(nTankNoRoad, 6,
                         'invalid distance without road for tank')
        self.assertEqual(nTankRoad - nTankNoRoad, 2,
                         'road does not increase by 2 the distance for tank')

        # infantry
        self.assertNotEqual(nInfRoad, nInfNoRoad,
                            'road has no influence on infantry')
        self.assertEqual(nInfRoad, 4,
                         'invalid distance with road for infantry')
        self.assertEqual(nInfNoRoad, 3,
                         'invalid distance without road  for infantry')
        self.assertEqual(
            nInfRoad - nInfNoRoad, 1,
            'road does not increase by 1 the distance for infantry')

        # test for road change
        board.terrain[0, 0] = 0
        board.terrain[0, 15] = 0

        nTankRoad = len(GM.buildMovements(board, stateTank, t))
        nInfRoad = len(GM.buildMovements(board, stateInf, i))

        self.assertEqual(nTankRoad, 8, 'invalid distance for tank')
        self.assertEqual(nInfRoad, 4, 'invalid distance for infantry')
Ejemplo n.º 8
0
def scroll(board: GameBoard):
    x, y = board.shape

    objectiveMarks = board.getObjectiveMark()

    for i in range(0, x):
        for j in range(0, y):
            p = Hex(i, j)
            x = p.tuple()

            index = board.terrain[x]
            tt = TYPE_TERRAIN[index]

            h = Hexagon(p, tt, board.geography[x],
                        p.cube() in objectiveMarks, tt.blockLos, tt.color)

            yield h
Ejemplo n.º 9
0
class TestLOS(unittest.TestCase):

    def setUp(self):
        collect()

        self.shape = (8, 8)
        self.board = GameBoard(self.shape)
        self.state = GameState(self.shape)

        self.blue_tank = buildFigure('Tank', (4, 6), BLUE)
        self.red_tank = buildFigure('Tank', (4, 1), RED)
        self.red_inf = buildFigure('Infantry', (1, 4), RED)

        self.state.addFigure(self.red_tank, self.red_inf, self.blue_tank)

        los_on_target = self.state.getLOS(self.blue_tank)

        self.los_tank = los_on_target[self.red_tank.index]
        self.los_inf = los_on_target[self.red_inf.index]

    def testNoBlockers(self):
        self.assertTrue(GM.checkLine(self.board, self.state, self.los_tank), 'tank has no LOS on target')
        self.assertTrue(GM.checkLine(self.board, self.state, self.los_inf), 'infantry has no LOS on target')

    def testDirectBlock(self):
        blocker = np.zeros(self.shape, 'uint8')
        blocker[4, 4] = 1  # continuously adding 1 will cycle through the type of terrains

        # road
        self.board.addTerrain(blocker)

        self.assertTrue(GM.checkLine(self.board, self.state, self.los_tank), 'road: tank has no LOS on target')
        self.assertTrue(GM.checkLine(self.board, self.state, self.los_inf), 'road: infantry has no LOS on target')

        # isolated tree
        self.board.addTerrain(blocker)

        self.assertFalse(GM.checkLine(self.board, self.state, self.los_tank), 'tree: tank has LOS on target')
        self.assertTrue(GM.checkLine(self.board, self.state, self.los_inf), 'tree: infantry has no LOS on target')

        # forest
        self.board.addTerrain(blocker)

        self.assertFalse(GM.checkLine(self.board, self.state, self.los_tank), 'forest: tank has LOS on target')
        self.assertTrue(GM.checkLine(self.board, self.state, self.los_inf), 'forest: infantry has no LOS on target')

        # wooden building
        self.board.addTerrain(blocker)

        self.assertFalse(GM.checkLine(self.board, self.state, self.los_tank), 'urban: tank has LOS on target')
        self.assertTrue(GM.checkLine(self.board, self.state, self.los_inf), 'urban: infantry has no LOS on target')

        # concrete building
        self.board.addTerrain(blocker)

        self.assertFalse(GM.checkLine(self.board, self.state, self.los_tank), 'building: tank has LOS on target')
        self.assertTrue(GM.checkLine(self.board, self.state, self.los_inf), 'building: infantry has no LOS on target')

    def testForestBlock(self):
        blocker = np.zeros(self.shape, 'uint8')
        blocker[4, 4] = TERRAIN_TYPE['FOREST'].level
        blocker[3, 6] = TERRAIN_TYPE['FOREST'].level
        blocker[4, 6] = TERRAIN_TYPE['FOREST'].level
        blocker[5, 6] = TERRAIN_TYPE['FOREST'].level
        self.board.addTerrain(blocker)

        self.assertFalse(GM.checkLine(self.board, self.state, self.los_tank), 'forest: tank has LOS on target')
        self.assertFalse(GM.checkLine(self.board, self.state, self.los_inf), 'forest: infantry has LOS on target')

    def testForestMarginNoBlock(self):
        blocker = np.zeros(self.shape, 'uint8')
        blocker[4, 6] = TERRAIN_TYPE['FOREST'].level
        blocker[3, 7] = TERRAIN_TYPE['FOREST'].level
        blocker[4, 7] = TERRAIN_TYPE['FOREST'].level
        blocker[5, 7] = TERRAIN_TYPE['FOREST'].level
        self.board.addTerrain(blocker)

        self.assertTrue(GM.checkLine(self.board, self.state, self.los_tank), 'forest: tank has LOS on target')
        self.assertTrue(GM.checkLine(self.board, self.state, self.los_inf), 'forest: infantry has LOS on target')

    def testBuildingBlock(self):
        blocker = np.zeros(self.shape, 'uint8')
        blocker[4, 4] = TERRAIN_TYPE['CONCRETE_BUILDING'].level
        blocker[3, 6] = TERRAIN_TYPE['CONCRETE_BUILDING'].level
        blocker[4, 6] = TERRAIN_TYPE['CONCRETE_BUILDING'].level
        blocker[5, 6] = TERRAIN_TYPE['CONCRETE_BUILDING'].level
        self.board.addTerrain(blocker)

        self.assertFalse(GM.checkLine(self.board, self.state, self.los_tank), 'urban: tank has LOS on target')
        self.assertFalse(GM.checkLine(self.board, self.state, self.los_inf), 'urban: infantry has LOS on target')

    def testArmoredUnitBlock(self):
        dst = Hex(3, 5).cube()
        m1 = GM.actionMove(self.board, self.state, self.red_tank, destination=dst)

        # we move the tank in a blocking position
        GM.step(self.board, self.state, m1)

        los_on_target = self.state.getLOS(self.blue_tank)
        self.los_inf = los_on_target[self.red_inf.index]

        self.assertFalse(GM.checkLine(self.board, self.state, self.los_inf), 'armored: inf has LOS on target')

    def testIndirectFire(self):
        blocker = np.zeros(self.shape, 'uint8')
        blocker[2, 5] = TERRAIN_TYPE['CONCRETE_BUILDING'].level
        blocker[3, 5] = TERRAIN_TYPE['CONCRETE_BUILDING'].level
        self.board.addTerrain(blocker)

        # we replace the blue tank with an infantry so we can use the mortar for an indirect hit
        self.state.clearFigures(BLUE)
        blue_inf = buildFigure('Infantry', (4, 6), BLUE)
        self.state.addFigure(blue_inf)

        los_on_target = self.state.getLOS(blue_inf)
        self.los_inf = los_on_target[self.red_inf.index]

        self.assertFalse(GM.checkLine(self.board, self.state, self.los_inf), 'indirect: infantry has LOS on target')

        # self.blue_tank.kind = FigureType.INFANTRY

        self.assertTrue(
            GM.canShoot(self.board, self.state, self.red_inf, blue_inf, self.red_inf.weapons['MT']),
            'indirect: infantry cannot shot at the target'
        )
Ejemplo n.º 10
0
    def step(self,
             board: GameBoard,
             state: GameState,
             action: Action,
             forceHit: bool = False) -> Outcome:
        """Update the given state with the given action in a irreversible way."""

        team: str = action.team  # team performing action
        comment: str = ''

        logger.debug(f'{team} step with {action}')
        state.lastAction = action

        if isinstance(action, Wait):
            logger.debug(f'{action}: {comment}')
            return Outcome(comment=comment)

        if isinstance(action, Pass):
            if isinstance(action, PassFigure):
                f: Figure = state.getFigure(action)  # who performs the action
                f.activated = True
                f.passed = True

            if isinstance(action,
                          PassTeam) and not isinstance(action, Response):
                for f in state.getFigures(team):
                    f.activated = True
                    f.passed = True

            logger.debug(f'{action}: {comment}')

            return Outcome(comment=comment)

        if isinstance(action, Move):
            f: Figure = state.getFigure(action)  # who performs the action
            f.activated = True
            f.moved = True

            f.stat = stat('IN_MOTION')
            if isinstance(action, MoveLoadInto):
                # figure moves inside transporter
                t = state.getTransporter(action)
                t.transportLoad(f)
                comment = f'(capacity: {len(t.transporting)}/{t.transport_capacity})'
            elif f.transported_by > -1:
                # figure leaves transporter
                t = state.getFigureByIndex(team, f.transported_by)
                t.transportUnload(f)
                comment = f'(capacity: {len(t.transporting)}/{t.transport_capacity})'

            state.moveFigure(f, f.position, action.destination)

            for transported in f.transporting:
                t = state.getFigureByIndex(team, transported)
                t.stat = stat('LOADED')
                state.moveFigure(t, t.position, action.destination)

            logger.debug(f'{action}: {comment}')

            return Outcome(comment=comment)

        if isinstance(action, AttackGround):
            f: Figure = state.getFigure(action)  # who performs the action
            x: Cube = action.ground
            w: Weapon = state.getWeapon(action)

            f.stat = stat('NO_EFFECT')
            f.activated = True
            f.attacked = True
            w.shoot()

            if w.smoke:
                cloud = [
                    x + Cube(0, -1, 1),
                    x + Cube(1, -1, 0),
                    x + Cube(1, 0, -1),
                    x + Cube(0, 1, -1),
                    x + Cube(-1, 1, 0),
                    x + Cube(-1, 0, 1),
                ]

                cloud = [(c.distance(f.position), c) for c in cloud]
                cloud = sorted(cloud, key=lambda y: -y[0])

                state.addSmoke([c[1] for c in cloud[1:3]] + [x])

                comment = f'smoke at {x}'

            logger.debug(f'{action}: {comment}')

            return Outcome(comment=comment)

        if isinstance(action, Attack):  # Respond *is* an attack action
            f: Figure = state.getFigure(action)  # who performs the action
            t: Figure = state.getTarget(action)  # target
            # g: Figure = action.guard  # who has line-of-sight on target
            w: Weapon = state.getWeapon(action)
            # los: list = action.los  # line-of-sight on target of guard
            lof: list = action.lof  # line-of-fire on target of figure

            # consume ammunition
            f.stat = stat('NO_EFFECT')
            w.shoot()

            if forceHit:
                score = [0] * w.dices
            else:
                score = np.random.choice(range(1, 21), size=w.dices)

            # attack/response
            if isinstance(action, Response):
                ATK = w.atk_response
                INT = f.int_def
                # can respond only once in a turn
                f.responded = True
            else:
                ATK = w.atk_normal
                INT = f.int_atk
                f.activated = True
                f.attacked = True

            # anti-tank rule
            if state.hasSmoke(lof):
                DEF = t.defense['smoke']
            elif w.antitank and t.kind == 'vehicle':
                DEF = t.defense['antitank']
            else:
                DEF = t.defense['basic']

            TER = board.getProtectionLevel(t.position)
            STAT = f.stat.value + f.bonus
            END = f.endurance

            hitScore = hitScoreCalculator(ATK, TER, DEF, STAT, END, INT)

            success = len([x for x in score if x <= hitScore])

            # target status changes for the _next_ hit
            t.stat = stat('UNDER_FIRE')
            # target can now respond to the fire
            t.attacked_by = f.index

            if success > 0:
                self.applyDamage(state, action, hitScore, score, success, t, w)

                comment = f'success=({success} {score}/{hitScore}) target=({t.hp}/{t.hp_max})'
                if t.hp <= 0:
                    comment += ' KILLED!'

            elif w.curved:
                # missing with curved weapons
                v = np.random.choice(range(1, 21), size=1)
                hitLocation = MISS_MATRIX[team](v)
                missed = state.getFiguresByPos(t.team, hitLocation)
                missed = [m for m in missed if not m.killed]

                comment = f'({success} {score}/{hitScore}): shell missed and hit {hitLocation}: {len(missed)} hit'

                for m in missed:
                    self.applyDamage(state, action, hitScore, score, 1, m, w)

            else:
                logger.debug(f'({success} {score}/{hitScore}): MISS!')

            logger.debug(f'{action}: {comment}')

            return Outcome(
                comment=comment,
                score=score,
                hitScore=hitScore,
                ATK=ATK,
                TER=TER,
                DEF=DEF,
                STAT=STAT,
                END=END,
                INT=INT,
                success=success > 0,
                hits=success,
            )
Ejemplo n.º 11
0
 def checkLine(board: GameBoard, state: GameState,
               line: List[Cube]) -> bool:
     """Returns True if the line is valid (has no obstacles), otherwise False."""
     return not any(
         [state.isObstacle(h) or board.isObstacle(h) for h in line[1:-1]])