예제 #1
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'
        )
예제 #2
0
    def canShoot(self, board: GameBoard, state: GameState, figure: Figure,
                 target: Figure, weapon: Weapon) -> tuple:
        """Check if the given weapon can shoot against the given target."""

        if not weapon.isAvailable():
            raise ValueError(f'{weapon} not available for {figure}')

        if not weapon.hasAmmo():
            raise ValueError(f'{weapon} does not have enough ammo')

        if figure.stat == stat('LOADED'):
            raise ValueError(
                f'{weapon} cannot hit {target}: unit is LOADED in a vehicle')

        if target.stat == stat('LOADED'):
            raise ValueError(
                f'{weapon} cannot hit {target}: target is LOADED in a vehicle')

        if target.stat == stat('HIDDEN'):
            raise ValueError(f'{weapon} cannot hit {target}: target is HIDDEN')

        if weapon.antitank:
            # can shoot only against vehicles
            validTarget = target.kind == 'vehicle'
        else:
            # can shoot against infantry and others only
            validTarget = target.kind != 'vehicle'

        if not validTarget:
            raise ValueError(
                f'{weapon} cannot hit {target}: target is not valid')

        lines = state.getLOS(target)
        lof = lines[figure.index]

        if weapon.curved:
            # at least one has Line-Of-Sight on target
            canHit = False
            guard = None
            los = []
            for idx, line in lines.items():
                possibleGuard = state.figures[figure.team][idx]
                if possibleGuard.killed:
                    continue

                canHit = self.checkLine(board, state, line)
                if canHit:
                    los = line
                    guard = possibleGuard
                    break

        else:
            # Line-Of-Sight and Line-Of-Fire are equivalent
            los = lof
            canHit = self.checkLine(board, state, lof)
            guard = figure

        if not canHit:
            raise ValueError(
                f'{weapon} cannot hit {target} from {figure.position}: no LOS on target'
            )

        if not weapon.max_range >= len(lof) - 1:
            raise ValueError(
                f'{weapon} cannot hit {target} from {figure.position}: out of max range'
            )

        return figure, target, guard, weapon, los, lof