def update_state_opponent(self, world, count):
		enemy = []
		for hockeyist in world.hockeyists:
			if (hockeyist.teammate or hockeyist.type == HockeyistType.GOALIE or
					hockeyist.state == HockeyistState.RESTING):
				continue

			if hockeyist.angle == world.puck.angle:
				enemy.append(hockeyist)

		if len(enemy) != count:
			self.both_enemy_catch = False
			return None

		if count == 2:
			if Unit.get_distance_to_unit(enemy[0], enemy[1]) < world.width / 8:
				self.both_enemy_catch = True
Exemple #2
0
def test_get_distance_to_unit():
    unit1 = Unit(x=0, y=0)
    unit2 = Unit(x=3, y=4)

    assert unit1.get_distance_to_unit(unit2) == 5
Exemple #3
0
class Strategy:
    def __init__(self, me, world, game):
        #print "================ " + str(world.tick)

        self.me = me
        self.world = world
        self.game = game

        self.move_turn = None
        self.move_speed_up = None
        self.move_action = None
        self.move_pass_angle = None
        self.move_pass_power = None

        self.angle = self.me.angle

        speed = sqrt(self.me.speed_x * self.me.speed_x +
                     self.me.speed_y * self.me.speed_y)
        if self.me.speed_y > 0.0 and self.angle > 0.0:
            self.speed = speed
        elif self.me.speed_y > 0.0 and self.angle < 0.0:
            self.speed = -speed
        elif self.me.speed_y < 0.0 and self.angle > 0.0:
            self.speed = -speed
        elif self.me.speed_y < 0.0 and self.angle < 0.0:
            self.speed = speed
        elif self.me.speed_x > 0.0 and -pi / 2.0 < self.angle < pi / 2.0:
            self.speed = speed
        else:
            self.speed = -speed

        self.player = self.world.get_my_player()
        self.opponentPlayer = self.world.get_opponent_player()

        self.myUnits = [
            hockeyist for hockeyist in self.world.hockeyists
            if hockeyist.teammate and hockeyist.id != self.me.id
            and hockeyist.type != HockeyistType.GOALIE
            and hockeyist.state != HockeyistState.RESTING
        ]
        self.myUnits.sort(key=lambda x: self.me.get_distance_to_unit(x))
        self.team_count = len(self.myUnits) + 1

        goalies = [
            hockeyist for hockeyist in self.world.hockeyists
            if hockeyist.teammate and hockeyist.type == HockeyistType.GOALIE
        ]
        if goalies:
            self.goalie = goalies[0]
        else:
            self.goalie = None

        forwards = [
            hockeyist for hockeyist in self.world.hockeyists
            if hockeyist.teammate and hockeyist.type == HockeyistType.FORWARD
        ]
        if forwards:
            self.forward = forwards[0]
        else:
            self.forward = None

        versatiles = [
            hockeyist for hockeyist in self.world.hockeyists
            if hockeyist.teammate and hockeyist.type == HockeyistType.VERSATILE
        ]
        if versatiles:
            self.versatile = versatiles[0]
        else:
            self.versatile = None

        defenders = [
            hockeyist for hockeyist in self.world.hockeyists if
            hockeyist.teammate and hockeyist.type == HockeyistType.DEFENCEMAN
        ]
        if defenders:
            self.defender = defenders[0]
        else:
            self.defender = None

        self.opponentUnits = [
            hockeyist for hockeyist in self.world.hockeyists
            if not hockeyist.teammate and hockeyist.type !=
            HockeyistType.GOALIE and hockeyist.state != HockeyistState.RESTING
        ]
        self.opponentUnits.sort(key=lambda x: self.me.get_distance_to_unit(x))

        self.rink_center_x = 0.5 * (self.game.rink_left + self.game.rink_right)
        self.rink_center_y = 0.5 * (self.game.rink_top + self.game.rink_bottom)

        if self.player.net_front < self.rink_center_x:
            self.position = "left"
            forward_x = self.opponentPlayer.net_front - 0.4 * self.game.world_width
            defence_x = self.player.net_front + 3.1 * self.me.radius
        #  defence2_x = self.player.net_front + 4.1*self.me.radius
        else:
            self.position = "right"
            forward_x = self.opponentPlayer.net_front + 0.4 * self.game.world_width
            defence_x = self.player.net_front - 3.1 * self.me.radius
        #   defence2_x = self.player.net_front - 4.1*self.me.radius

        if self.me.y < self.rink_center_y:
            forward_y = self.game.rink_top + 0.2 * self.game.world_height
        else:
            forward_y = self.game.rink_bottom - 0.2 * self.game.world_height

        self.forwardPlace = Unit(9906, 0.0, 0.0, forward_x, forward_y, 0.0,
                                 0.0, 0.0, 0.0)
        self.defendCircle = Unit(9907, 0.0, 1.0 * self.game.stick_length,
                                 defence_x, self.rink_center_y, 0.0, 0.0, 0.0,
                                 0.0)
        #self.defendCircle2 = Unit(9901, 0.0, 1.0*self.game.stick_length,
        #                         defence2_x, self.rink_center_y+self.me.radius,
        #                         0.0, 0.0, 0.0, 0.0)

        self.attackAngle = pi / 2.0 - pi / 6.0

        if self.goalie:
            self.attackCircle = Unit(9908, 1.0, 0.4 * self.game.world_height,
                                     self.opponentPlayer.net_front,
                                     self.rink_center_y, 0.0, 0.0, 0.0, 0.0)
            self.attackPassDistance = 3.0 * self.me.radius
        else:
            self.attackCircle = Unit(9909, 1.0, self.game.world_width,
                                     self.opponentPlayer.net_front,
                                     self.rink_center_y, 0.0, 0.0, 0.0, 0.0)
            self.attackPassDistance = self.game.world_width

    def getStrategy2(self):
        if self.world.puck.owner_hockeyist_id == self.me.id:
            # if self.tryPass('Forward'):
            #     return True
            # else:
            self.setStrategyAttackGate()
            return True

        elif self.me.state == HockeyistState.SWINGING:
            self.move_action = ActionType.CANCEL_STRIKE
            return True

        elif self.world.puck.owner_player_id == self.me.player_id:
            self.setStrategyDefendGate()
            return True

        elif abs(self.me.x -
                 self.player.net_front) < abs(self.myUnits[0].x -
                                              self.player.net_front):
            self.setStrategyDefendGate()
            return True

        else:
            self.setStrategyTakePuck()
            return True

    def getStrategy3(self):
        if self.world.puck.owner_hockeyist_id == self.me.id:
            if self.me.state == HockeyistState.SWINGING or self.me.type == HockeyistType.FORWARD:
                self.setStrategyAttackGate()
                return True
            elif self.me.type != HockeyistType.FORWARD and self.tryPass(
                    'Forward', self.forward):
                print "Pass to forward"
                return True
            elif self.me.type == HockeyistType.DEFENCEMAN and self.tryPass(
                    'Forward', self.versatile):
                print "Pass to versatile"
                return True
            else:
                self.setStrategyAttackGate()
                return True

        elif self.me.state == HockeyistState.SWINGING:
            self.move_action = ActionType.CANCEL_STRIKE
            return True

        if self.me.type == HockeyistType.DEFENCEMAN:
            #print "DEFENCEMAN: Defend gate"
            self.setStrategyDefendGate()
            return True

        if self.me.type == HockeyistType.FORWARD:
            if (  #self.me.get_distance_to_unit(self.attackCircle) < self.attackCircle.radius
                    #or abs(self.me.x - self.attackCircle.x) > abs(self.world.puck.x - self.attackCircle.x)
                    abs(self.world.puck.x - self.attackCircle.x) <
                    0.55 * self.game.world_width
                    or self.me.get_distance_to_unit(
                        self.world.puck) < self.game.stick_length
                    #or self.world.puck.owner_player_id == self.opponentPlayer.id
            ):
                #print "FORWARD: Take puck"
                self.setStrategyTakePuck()
                return True
            elif self.me.get_distance_to_unit(
                    self.forwardPlace) < 1.0 * self.me.radius:
                #print "FORWARD: Stay near opponent gate"
                self.move_turn = self.me.get_angle_to_unit(self.world.puck)
                return True
            else:
                #print "FORWARD: Skate to (" + str(self.forwardPlace.x) + ", " + str(self.forwardPlace.y) + ")"
                self.trySkate(self.forwardPlace.x, self.forwardPlace.y, True)
                return True

        if self.me.type == HockeyistType.VERSATILE:
            if (self.world.puck.owner_hockeyist_id == self.defender.id
                    or self.defender.get_distance_to_unit(self.defendCircle) >
                    2.0 * self.game.stick_length or self.defender == None):
                self.setStrategyDefendGate()
                return True
            elif self.world.puck.owner_player_id == self.me.player_id:
                #print "VERSATILE: Strike opponent"
                self.setStrategyStrikeOpponent()
                return True
            elif self.tryStrikeOpponent():
                return True
            #elif self.world.puck.owner_player_id == self.opponentPlayer.id:
            #    self.setStrategyDefendGate()
            #    return True
            else:
                #print "VERSATILE: Take puck"
                self.setStrategyTakePuck()
                return True

    def calcAcceleration(self, skateX, skateY):

        Tmin = 10000
        a_min = 1.0

        if self.me.get_distance_to(skateX,
                                   skateY) > self.game.world_width / 5.0:
            self.move_turn = self.me.get_angle_to(skateX, skateY)
            self.move_speed_up = 1.0
            return True

        if abs(self.me.get_angle_to(skateX, skateY)) <= pi / 2.0:
            direction = 'forward'
        else:
            direction = 'back'

        for i in range(10):
            (x, y) = (self.me.x, self.me.y)
            v = self.speed
            alpha = self.angle
            a0 = 1.0 - i / 10.0
            T = Tmin

            if direction == 'forward' and a0 < 0.0:
                break
            # if direction == 'back' and self.me.get_distance_to(skateX, skateY) > 100.0 and a < 0.0:
            #     break

            for j in range(100):
                aj = a0 - j * 0.001
                unit = Unit(999 + i * 100 + j, 0.0, 0.0, x, y, 0.0, 0.0, alpha,
                            0.0)
                if (x < self.game.rink_left or x > self.game.rink_right
                        or y < self.game.rink_top
                        or y > self.game.rink_bottom):
                    break

                if unit.get_distance_to(skateX, skateY) < 1.0:
                    T = j
                    break

                if aj > 0.0:
                    v += aj * self.game.hockeyist_speed_up_factor
                else:
                    v += aj * self.game.hockeyist_speed_down_factor

                v = 0.95 * v  # friction

                dalpha = unit.get_angle_to(skateX, skateY)
                if v < 0.0 and dalpha < 0.0:
                    dalpha = dalpha + pi
                elif v < 0.0 and dalpha > 0.0:
                    dalpha = dalpha - pi

                dalpha = copysign(
                    min(abs(dalpha), self.game.hockeyist_turn_angle_factor),
                    dalpha)

                alpha = normAngle(alpha + dalpha)
                (x, y) = (x + v * cos(alpha), y + v * sin(alpha))

            if T < Tmin:
                Tmin = T
                a_min = a0

        alpha = self.me.get_angle_to(skateX, skateY)
        if T == 10000:
            #print self.me.x, self.me.y, skateX, skateY, self.angle, direction, self.speed
            self.move_turn = alpha
            self.move_speed_up = 1.0
        elif direction == 'back' and a_min < 0.0 and alpha < 0.0:
            self.move_turn = alpha + pi
            self.move_speed_up = a_min
        elif direction == 'back' and a_min < 0.0 and alpha > 0.0:
            self.move_turn = alpha - pi
            self.move_speed_up = a_min
        else:
            self.move_turn = alpha
            self.move_speed_up = a_min

        return True

    def tryPass(self, method='Forward', unit=None):
        if not unit:
            unit = self.myUnits[-1]

        puck_can_pass = True
        for opponentUnit in self.opponentUnits:
            if dist2segment(self.me, unit,
                            opponentUnit) < self.game.stick_length:
                puck_can_pass = False

        if ((method == 'Forward'
             and abs(self.me.x - self.opponentPlayer.net_front) -
             abs(unit.x - self.opponentPlayer.net_front) >
             self.game.world_width / 5.0 and puck_can_pass
             and abs(unit.get_angle_to_unit(self.me)) < pi / 3.0)
                #or (method == 'Backward' and puck_can_pass)
                or (method == 'Strike')):

            angle = self.me.get_angle_to_unit(unit)

            if abs(angle) < pi / 3.0:
                self.move_pass_angle = angle

                if method == 'Forward':
                    self.move_pass_power = 0.8
                #elif method == 'Backward':
                #    self.move_pass_power = 0.6
                elif method == 'Strike':
                    self.move_pass_power = 1.0

                self.move_action = ActionType.PASS
                #print "pass " + method
                return True
            else:
                #self.move_turn = angle
                return False

        else:
            return False

    def probTakePuck(self):
        puck = self.world.puck
        puck_speed = sqrt(puck.speed_x * puck.speed_x +
                          puck.speed_y * puck.speed_y)
        return 60.0 + max(self.me.dexterity,
                          self.me.agility) - puck_speed * 5.0

    def setStrategyDefendGate(self):
        #print "====== defence ======"
        if self.probTakePuck() < 100 and self.tryStrikePuck():
            #print "defence: tryStrikePuck"
            return True

        distMe = self.me.get_distance_to_unit(self.world.puck)
        distOpponent = min([
            unit.get_distance_to_unit(self.world.puck)
            for unit in self.opponentUnits
        ])

        # if puck is close - let's catch it!
        if (self.me.type == HockeyistType.VERSATILE
                and distMe < 0.5 * distOpponent
                and self.world.puck.owner_player_id != self.me.player_id
                and self.setStrategyTakePuck()):
            #print "defence: setStrategyTakePuck"
            return True

        if (  #self.me.type == HockeyistType.DEFENCEMAN and
                self.defendCircle.get_distance_to_unit(
                    self.world.puck) < self.defendCircle.radius
                and self.world.puck.owner_player_id != self.me.player_id
                and self.setStrategyTakePuck()):
            #print "defence: setStrategyTakePuck"
            return True

        # To stand or to move
        if self.me.get_distance_to_unit(
                self.defendCircle) < 1.0 * self.me.radius:
            self.move_turn = self.me.get_angle_to_unit(self.world.puck)
            #print "defence: turn to puck"
        else:
            #print "defence: skate"
            self.trySkate(self.defendCircle.x, self.defendCircle.y, True)

        return True

    def tryStrikePuck(self):
        unit = self.world.puck

        if (self.me.get_distance_to_unit(unit) < self.game.stick_length
                and abs(self.me.get_angle_to_unit(unit)) <
                0.5 * self.game.stick_sector):
            self.move_action = ActionType.STRIKE
            #print "strike puck"
            return True
        else:
            return False

    def tryStrikeOpponent(self):
        for unit in self.opponentUnits:
            if (self.me.get_distance_to_unit(unit) < self.game.stick_length
                    and abs(self.me.get_angle_to_unit(unit)) <
                    0.5 * self.game.stick_sector
                    and unit.state != HockeyistState.KNOCKED_DOWN):
                self.move_action = ActionType.STRIKE
                #print "strike opponent"
                return True

        return False

    def setStrategyStrikeOpponent(self):
        if self.tryStrikeOpponent():
            return True

        else:
            units = self.opponentUnits
            units.sort(
                key=lambda x: self.me.get_distance_to_unit(self.forward))
            self.trySkate(units[0].x, units[0].y)
            return True

    def setStrategyTakePuck(self):
        if self.world.puck.owner_player_id == self.me.player_id:
            return False
        elif self.me.get_distance_to_unit(
                self.world.puck) < self.game.stick_length:
            self.move_turn = self.me.get_angle_to_unit(self.world.puck)
            self.move_speed_up = 1.0
            self.move_action = ActionType.TAKE_PUCK
        elif abs(self.player.net_front - self.me.x
                 ) > self.game.world_width / 2.0 and self.tryStrikeOpponent():
            return True
        else:
            puck = self.world.puck
            (max_speed_x, max_speed_y) = (puck.speed_x - self.me.speed_x,
                                          puck.speed_y - self.me.speed_y)
            max_speed = sqrt(max_speed_x * max_speed_x +
                             max_speed_y * max_speed_y)

            if max_speed == 0.0:
                n_tick = 1.0
            elif self.me.get_distance_to_unit(
                    self.world.puck) < self.game.stick_length:
                n_tick = 1.0
            else:
                n_tick = self.me.get_distance_to_unit(
                    self.world.puck) / max_speed

            if n_tick > 40.0: n_tick = 40.0
            if n_tick < 7.0: n_tick = 1.0

            gotoX = self.world.puck.x + self.world.puck.speed_x * n_tick

            if gotoX < self.game.rink_left or gotoX > self.game.rink_right:
                gotoX = self.me.x

            gotoY = self.world.puck.y + self.world.puck.speed_y * n_tick

            if gotoY < self.game.rink_top or gotoY > self.game.rink_bottom:
                gotoY = self.me.y

            self.calcAcceleration(gotoX, gotoY)

            self.move_action = ActionType.TAKE_PUCK

            return True

    def setStrategyAttackGate(self):

        # if the position is good or i am swinging >> let's strike!
        if ((self.me.get_distance_to_unit(
                self.attackCircle) < self.attackCircle.radius
             and abs(self.me.get_angle_to_unit(self.attackCircle)) <
             self.attackAngle) or self.me.state == HockeyistState.SWINGING):
            strikeX = self.opponentPlayer.net_front
            if self.me.y < self.rink_center_y:
                strikeY1 = self.opponentPlayer.net_bottom - self.world.puck.radius
                strikeY2 = self.opponentPlayer.net_bottom - 2.0 * self.world.puck.radius
            else:
                strikeY1 = self.opponentPlayer.net_top + self.world.puck.radius
                strikeY2 = self.opponentPlayer.net_top + 2.0 * self.world.puck.radius

            unit1 = Unit(9910, 0.0, 0.0, strikeX, strikeY1, 0.0, 0.0, 0.0, 0.0)
            unit2 = Unit(9911, 0.0, 0.0, strikeX, strikeY2, 0.0, 0.0, 0.0, 0.0)
            dist1 = min([
                dist2segment(self.me, unit1, opponent)
                for opponent in self.opponentUnits
            ])
            dist2 = min([
                dist2segment(self.me, unit2, opponent)
                for opponent in self.opponentUnits
            ])

            if dist1 < dist2:
                #print "trystrike2 " + str(dist1) + " " + str(dist2)
                self.tryStrike(strikeX, strikeY2)
            else:
                #print "trystrike1 " + str(dist1) + " " + str(dist2)
                self.tryStrike(strikeX, strikeY1)

            return True

        if abs(self.me.x -
               self.opponentPlayer.net_front) > self.game.world_width / 2.0:
            if self.me.y < self.rink_center_y:
                self.trySkate(self.attackCircle.x,
                              0.2 * self.game.world_height)
            else:
                self.trySkate(self.attackCircle.x,
                              0.8 * self.game.world_height)
        else:
            if self.me.y < self.rink_center_y:
                self.trySkate(
                    self.attackCircle.x,
                    self.opponentPlayer.net_bottom - self.world.puck.radius)
            else:
                self.trySkate(
                    self.attackCircle.x,
                    self.opponentPlayer.net_top + self.world.puck.radius)
        return True

    def tryStrike(self, strikeX, strikeY):
        PASS_ACCURACY = pi / 3.0
        STRIKE_ACCURACY = 1.0 * pi / 180.0

        angle = self.me.get_angle_to(strikeX, strikeY)

        self.move_turn = angle
        self.move_speed_up = 1.0

        danger = False
        for opponentUnit in self.opponentUnits:
            if (opponentUnit.get_distance_to_unit(
                    self.me) < 1.1 * self.game.stick_length
                    and abs(opponentUnit.get_angle_to_unit(
                        self.me)) < 0.6 * self.game.stick_sector
                    and opponentUnit.state != HockeyistState.KNOCKED_DOWN):
                danger = True

            if (opponentUnit.get_distance_to_unit(
                    self.world.puck) < 1.1 * self.game.stick_length
                    and abs(opponentUnit.get_angle_to_unit(
                        self.world.puck)) < 0.7 * self.game.stick_sector
                    and opponentUnit.state != HockeyistState.KNOCKED_DOWN):
                danger = True

        if abs(angle) < STRIKE_ACCURACY and self.me.get_distance_to_unit(
                self.attackCircle) > self.attackPassDistance:
            if self.me.swing_ticks < self.game.max_effective_swing_ticks and not danger:
                #print "swing: " + str(self.me.swing_ticks)
                self.move_action = ActionType.SWING

                return True

        if (self.me.state == HockeyistState.SWINGING
                or abs(angle) < STRIKE_ACCURACY):
            #print "strike puck: " + str(self.me.swing_ticks)
            self.move_action = ActionType.STRIKE

            return True

        if (abs(angle) < PASS_ACCURACY
                #and danger
                and self.me.state != HockeyistState.SWINGING and
                self.me.get_distance_to_unit(
                    self.attackCircle) < self.attackPassDistance):
            print "strike pass"
            unit = Unit(9912, 0.0, 0.0, strikeX, strikeY, 0.0, 0.0, 0.0, 0.0)
            self.tryPass('Strike', unit)
            return True

        return False

    def trySkate(self, skateX, skateY, zeroSpeed=False):
        if self.world.puck.owner_hockeyist_id == self.me.id:
            #print "trySkate: calcAcceleration1"
            self.calcAcceleration(skateX, skateY)

            #if self.speed < 0.1:
            test = Unit(
                9913, 0.0, 0.0, self.me.x +
                6.0 * self.me.radius * cos(self.me.angle + self.move_turn),
                self.me.y +
                6.0 * self.me.radius * sin(self.me.angle + self.move_turn),
                0.0, 0.0, 0.0, 0.0)

            dangerUnits = [
                unit for unit in self.opponentUnits
                if unit.get_angle_to_unit(self.me) < pi / 3.0
            ]
            if dangerUnits:
                dangerUnits.sort(key=lambda x: dist2segment(self.me, test, x))
                dist = dist2segment(self.me, test, dangerUnits[0])

                if dist < 10.0 and self.me.get_angle_to_unit(
                        dangerUnits[0]) < 0.0:
                    self.move_turn = self.game.hockeyist_turn_angle_factor
                    #print "me+puck: angle +"
                elif dist < 10.0:
                    self.move_turn = -self.game.hockeyist_turn_angle_factor
                    #print "me+puck: angle -"

            return True

        elif self.tryStrikeOpponent():
            #print "trySkate: tryStrikeOpponent"
            return True

        elif zeroSpeed:
            # i don't have a puck
            # i don't have a puck

            angle = self.me.get_angle_to(skateX, skateY)
            dist = self.me.get_distance_to(skateX, skateY)

            #if dist < 10.0*self.me.radius and abs(angle) > pi/2:
            if abs(angle) > pi / 2.0 and dist < self.game.world_width / 2.0:
                # going back
                if angle > 0.0:
                    self.move_turn = angle - pi
                else:
                    self.move_turn = angle + pi

                if self.speed >= 0.0:
                    self.move_speed_up = -1.0
                elif dist / self.speed > self.speed / self.game.hockeyist_speed_up_factor:
                    self.move_speed_up = self.speed / self.game.hockeyist_speed_up_factor
                else:
                    self.move_speed_up = -1.0

            else:
                # going front

                self.move_turn = angle

                if self.speed <= 0.0:
                    self.move_speed_up = 1.0
                elif dist / self.speed < self.speed / self.game.hockeyist_speed_down_factor:
                    self.move_speed_up = -self.speed / self.game.hockeyist_speed_down_factor
                else:
                    self.move_speed_up = 1.0

            #print "zeroSpeed: " + str(self.move_turn) + " " + str(self.move_speed_up)
            return True

        else:
            #print "trySkate: calcAcceleration2"
            self.calcAcceleration(skateX, skateY)

            if self.speed < 0.1:
                test = Unit(
                    9914, 0.0, 0.0, self.me.x +
                    2.0 * self.me.radius * cos(self.me.angle + self.move_turn),
                    self.me.y +
                    2.0 * self.me.radius * sin(self.me.angle + self.move_turn),
                    0.0, 0.0, 0.0, 0.0)

                dist = min([
                    unit.get_distance_to_unit(test)
                    for unit in self.opponentUnits
                ])
                if test.x < self.game.rink_left or test.x > self.game.rink_right or test.y < self.game.rink_top or test.y > self.game.rink_bottom:
                    dist = 0.0

                if dist < 2.0 and self.me.get_angle_to_unit(
                        self.attackCircle) > 0.0:
                    self.move_turn += self.game.hockeyist_turn_angle_factor
                    #print "me-puck: angle +"
                elif dist < 2.0:
                    self.move_turn -= self.game.hockeyist_turn_angle_factor
                    #print "me-puck: angle -"

            return True
Exemple #4
0
class Strategy:
    def __init__(self, me, world, game):
        # print "================ " + str(world.tick)

        self.me = me
        self.world = world
        self.game = game

        self.move_turn = None
        self.move_speed_up = None
        self.move_action = None
        self.move_pass_angle = None
        self.move_pass_power = None

        self.angle = self.me.angle

        speed = sqrt(self.me.speed_x * self.me.speed_x + self.me.speed_y * self.me.speed_y)
        if self.me.speed_y > 0.0 and self.angle > 0.0:
            self.speed = speed
        elif self.me.speed_y > 0.0 and self.angle < 0.0:
            self.speed = -speed
        elif self.me.speed_y < 0.0 and self.angle > 0.0:
            self.speed = -speed
        elif self.me.speed_y < 0.0 and self.angle < 0.0:
            self.speed = speed
        elif self.me.speed_x > 0.0 and -pi / 2.0 < self.angle < pi / 2.0:
            self.speed = speed
        else:
            self.speed = -speed

        self.player = self.world.get_my_player()
        self.opponentPlayer = self.world.get_opponent_player()

        self.myUnits = [
            hockeyist
            for hockeyist in self.world.hockeyists
            if hockeyist.teammate
            and hockeyist.id != self.me.id
            and hockeyist.type != HockeyistType.GOALIE
            and hockeyist.state != HockeyistState.RESTING
        ]
        self.myUnits.sort(key=lambda x: self.me.get_distance_to_unit(x))
        self.team_count = len(self.myUnits) + 1

        goalies = [
            hockeyist
            for hockeyist in self.world.hockeyists
            if hockeyist.teammate and hockeyist.type == HockeyistType.GOALIE
        ]
        if goalies:
            self.goalie = goalies[0]
        else:
            self.goalie = None

        forwards = [
            hockeyist
            for hockeyist in self.world.hockeyists
            if hockeyist.teammate and hockeyist.type == HockeyistType.FORWARD
        ]
        if forwards:
            self.forward = forwards[0]
        else:
            self.forward = None

        versatiles = [
            hockeyist
            for hockeyist in self.world.hockeyists
            if hockeyist.teammate and hockeyist.type == HockeyistType.VERSATILE
        ]
        if versatiles:
            self.versatile = versatiles[0]
        else:
            self.versatile = None

        defenders = [
            hockeyist
            for hockeyist in self.world.hockeyists
            if hockeyist.teammate and hockeyist.type == HockeyistType.DEFENCEMAN
        ]
        if defenders:
            self.defender = defenders[0]
        else:
            self.defender = None

        self.opponentUnits = [
            hockeyist
            for hockeyist in self.world.hockeyists
            if not hockeyist.teammate
            and hockeyist.type != HockeyistType.GOALIE
            and hockeyist.state != HockeyistState.RESTING
        ]
        self.opponentUnits.sort(key=lambda x: self.me.get_distance_to_unit(x))

        self.rink_center_x = 0.5 * (self.game.rink_left + self.game.rink_right)
        self.rink_center_y = 0.5 * (self.game.rink_top + self.game.rink_bottom)

        if self.player.net_front < self.rink_center_x:
            self.position = "left"
            forward_x = self.opponentPlayer.net_front - 0.4 * self.game.world_width
            defence_x = self.player.net_front + 3.1 * self.me.radius
        #  defence2_x = self.player.net_front + 4.1*self.me.radius
        else:
            self.position = "right"
            forward_x = self.opponentPlayer.net_front + 0.4 * self.game.world_width
            defence_x = self.player.net_front - 3.1 * self.me.radius
        #   defence2_x = self.player.net_front - 4.1*self.me.radius

        if self.me.y < self.rink_center_y:
            forward_y = self.game.rink_top + 0.2 * self.game.world_height
        else:
            forward_y = self.game.rink_bottom - 0.2 * self.game.world_height

        self.forwardPlace = Unit(9906, 0.0, 0.0, forward_x, forward_y, 0.0, 0.0, 0.0, 0.0)
        self.defendCircle = Unit(
            9907, 0.0, 1.0 * self.game.stick_length, defence_x, self.rink_center_y, 0.0, 0.0, 0.0, 0.0
        )
        # self.defendCircle2 = Unit(9901, 0.0, 1.0*self.game.stick_length,
        #                         defence2_x, self.rink_center_y+self.me.radius,
        #                         0.0, 0.0, 0.0, 0.0)

        self.attackAngle = pi / 2.0 - pi / 6.0

        if self.goalie:
            self.attackCircle = Unit(
                9908,
                1.0,
                0.4 * self.game.world_height,
                self.opponentPlayer.net_front,
                self.rink_center_y,
                0.0,
                0.0,
                0.0,
                0.0,
            )
            self.attackPassDistance = 3.0 * self.me.radius
        else:
            self.attackCircle = Unit(
                9909, 1.0, self.game.world_width, self.opponentPlayer.net_front, self.rink_center_y, 0.0, 0.0, 0.0, 0.0
            )
            self.attackPassDistance = self.game.world_width

    def getStrategy2(self):
        if self.world.puck.owner_hockeyist_id == self.me.id:
            # if self.tryPass('Forward'):
            #     return True
            # else:
            self.setStrategyAttackGate()
            return True

        elif self.me.state == HockeyistState.SWINGING:
            self.move_action = ActionType.CANCEL_STRIKE
            return True

        elif self.world.puck.owner_player_id == self.me.player_id:
            self.setStrategyDefendGate()
            return True

        elif abs(self.me.x - self.player.net_front) < abs(self.myUnits[0].x - self.player.net_front):
            self.setStrategyDefendGate()
            return True

        else:
            self.setStrategyTakePuck()
            return True

    def getStrategy3(self):
        if self.world.puck.owner_hockeyist_id == self.me.id:
            if self.me.state == HockeyistState.SWINGING or self.me.type == HockeyistType.FORWARD:
                self.setStrategyAttackGate()
                return True
            elif self.me.type != HockeyistType.FORWARD and self.tryPass("Forward", self.forward):
                print "Pass to forward"
                return True
            elif self.me.type == HockeyistType.DEFENCEMAN and self.tryPass("Forward", self.versatile):
                print "Pass to versatile"
                return True
            else:
                self.setStrategyAttackGate()
                return True

        elif self.me.state == HockeyistState.SWINGING:
            self.move_action = ActionType.CANCEL_STRIKE
            return True

        if self.me.type == HockeyistType.DEFENCEMAN:
            # print "DEFENCEMAN: Defend gate"
            self.setStrategyDefendGate()
            return True

        if self.me.type == HockeyistType.FORWARD:
            if (  # self.me.get_distance_to_unit(self.attackCircle) < self.attackCircle.radius
                # or abs(self.me.x - self.attackCircle.x) > abs(self.world.puck.x - self.attackCircle.x)
                abs(self.world.puck.x - self.attackCircle.x) < 0.55 * self.game.world_width
                or self.me.get_distance_to_unit(self.world.puck) < self.game.stick_length
                # or self.world.puck.owner_player_id == self.opponentPlayer.id
            ):
                # print "FORWARD: Take puck"
                self.setStrategyTakePuck()
                return True
            elif self.me.get_distance_to_unit(self.forwardPlace) < 1.0 * self.me.radius:
                # print "FORWARD: Stay near opponent gate"
                self.move_turn = self.me.get_angle_to_unit(self.world.puck)
                return True
            else:
                # print "FORWARD: Skate to (" + str(self.forwardPlace.x) + ", " + str(self.forwardPlace.y) + ")"
                self.trySkate(self.forwardPlace.x, self.forwardPlace.y, True)
                return True

        if self.me.type == HockeyistType.VERSATILE:
            if (
                self.world.puck.owner_hockeyist_id == self.defender.id
                or self.defender.get_distance_to_unit(self.defendCircle) > 2.0 * self.game.stick_length
                or self.defender == None
            ):
                self.setStrategyDefendGate()
                return True
            elif self.world.puck.owner_player_id == self.me.player_id:
                # print "VERSATILE: Strike opponent"
                self.setStrategyStrikeOpponent()
                return True
            elif self.tryStrikeOpponent():
                return True
            # elif self.world.puck.owner_player_id == self.opponentPlayer.id:
            #    self.setStrategyDefendGate()
            #    return True
            else:
                # print "VERSATILE: Take puck"
                self.setStrategyTakePuck()
                return True

    def calcAcceleration(self, skateX, skateY):

        Tmin = 10000
        a_min = 1.0

        if self.me.get_distance_to(skateX, skateY) > self.game.world_width / 5.0:
            self.move_turn = self.me.get_angle_to(skateX, skateY)
            self.move_speed_up = 1.0
            return True

        if abs(self.me.get_angle_to(skateX, skateY)) <= pi / 2.0:
            direction = "forward"
        else:
            direction = "back"

        for i in range(10):
            (x, y) = (self.me.x, self.me.y)
            v = self.speed
            alpha = self.angle
            a0 = 1.0 - i / 10.0
            T = Tmin

            if direction == "forward" and a0 < 0.0:
                break
            # if direction == 'back' and self.me.get_distance_to(skateX, skateY) > 100.0 and a < 0.0:
            #     break

            for j in range(100):
                aj = a0 - j * 0.001
                unit = Unit(999 + i * 100 + j, 0.0, 0.0, x, y, 0.0, 0.0, alpha, 0.0)
                if (
                    x < self.game.rink_left
                    or x > self.game.rink_right
                    or y < self.game.rink_top
                    or y > self.game.rink_bottom
                ):
                    break

                if unit.get_distance_to(skateX, skateY) < 1.0:
                    T = j
                    break

                if aj > 0.0:
                    v += aj * self.game.hockeyist_speed_up_factor
                else:
                    v += aj * self.game.hockeyist_speed_down_factor

                v = 0.95 * v  # friction

                dalpha = unit.get_angle_to(skateX, skateY)
                if v < 0.0 and dalpha < 0.0:
                    dalpha = dalpha + pi
                elif v < 0.0 and dalpha > 0.0:
                    dalpha = dalpha - pi

                dalpha = copysign(min(abs(dalpha), self.game.hockeyist_turn_angle_factor), dalpha)

                alpha = normAngle(alpha + dalpha)
                (x, y) = (x + v * cos(alpha), y + v * sin(alpha))

            if T < Tmin:
                Tmin = T
                a_min = a0

        alpha = self.me.get_angle_to(skateX, skateY)
        if T == 10000:
            # print self.me.x, self.me.y, skateX, skateY, self.angle, direction, self.speed
            self.move_turn = alpha
            self.move_speed_up = 1.0
        elif direction == "back" and a_min < 0.0 and alpha < 0.0:
            self.move_turn = alpha + pi
            self.move_speed_up = a_min
        elif direction == "back" and a_min < 0.0 and alpha > 0.0:
            self.move_turn = alpha - pi
            self.move_speed_up = a_min
        else:
            self.move_turn = alpha
            self.move_speed_up = a_min

        return True

    def tryPass(self, method="Forward", unit=None):
        if not unit:
            unit = self.myUnits[-1]

        puck_can_pass = True
        for opponentUnit in self.opponentUnits:
            if dist2segment(self.me, unit, opponentUnit) < self.game.stick_length:
                puck_can_pass = False

        if (
            (
                method == "Forward"
                and abs(self.me.x - self.opponentPlayer.net_front) - abs(unit.x - self.opponentPlayer.net_front)
                > self.game.world_width / 5.0
                and puck_can_pass
                and abs(unit.get_angle_to_unit(self.me)) < pi / 3.0
            )
            # or (method == 'Backward' and puck_can_pass)
            or (method == "Strike")
        ):

            angle = self.me.get_angle_to_unit(unit)

            if abs(angle) < pi / 3.0:
                self.move_pass_angle = angle

                if method == "Forward":
                    self.move_pass_power = 0.8
                # elif method == 'Backward':
                #    self.move_pass_power = 0.6
                elif method == "Strike":
                    self.move_pass_power = 1.0

                self.move_action = ActionType.PASS
                # print "pass " + method
                return True
            else:
                # self.move_turn = angle
                return False

        else:
            return False

    def probTakePuck(self):
        puck = self.world.puck
        puck_speed = sqrt(puck.speed_x * puck.speed_x + puck.speed_y * puck.speed_y)
        return 60.0 + max(self.me.dexterity, self.me.agility) - puck_speed * 5.0

    def setStrategyDefendGate(self):
        # print "====== defence ======"
        if self.probTakePuck() < 100 and self.tryStrikePuck():
            # print "defence: tryStrikePuck"
            return True

        distMe = self.me.get_distance_to_unit(self.world.puck)
        distOpponent = min([unit.get_distance_to_unit(self.world.puck) for unit in self.opponentUnits])

        # if puck is close - let's catch it!
        if (
            self.me.type == HockeyistType.VERSATILE
            and distMe < 0.5 * distOpponent
            and self.world.puck.owner_player_id != self.me.player_id
            and self.setStrategyTakePuck()
        ):
            # print "defence: setStrategyTakePuck"
            return True

        if (  # self.me.type == HockeyistType.DEFENCEMAN and
            self.defendCircle.get_distance_to_unit(self.world.puck) < self.defendCircle.radius
            and self.world.puck.owner_player_id != self.me.player_id
            and self.setStrategyTakePuck()
        ):
            # print "defence: setStrategyTakePuck"
            return True

        # To stand or to move
        if self.me.get_distance_to_unit(self.defendCircle) < 1.0 * self.me.radius:
            self.move_turn = self.me.get_angle_to_unit(self.world.puck)
            # print "defence: turn to puck"
        else:
            # print "defence: skate"
            self.trySkate(self.defendCircle.x, self.defendCircle.y, True)

        return True

    def tryStrikePuck(self):
        unit = self.world.puck

        if (
            self.me.get_distance_to_unit(unit) < self.game.stick_length
            and abs(self.me.get_angle_to_unit(unit)) < 0.5 * self.game.stick_sector
        ):
            self.move_action = ActionType.STRIKE
            # print "strike puck"
            return True
        else:
            return False

    def tryStrikeOpponent(self):
        for unit in self.opponentUnits:
            if (
                self.me.get_distance_to_unit(unit) < self.game.stick_length
                and abs(self.me.get_angle_to_unit(unit)) < 0.5 * self.game.stick_sector
                and unit.state != HockeyistState.KNOCKED_DOWN
            ):
                self.move_action = ActionType.STRIKE
                # print "strike opponent"
                return True

        return False

    def setStrategyStrikeOpponent(self):
        if self.tryStrikeOpponent():
            return True

        else:
            units = self.opponentUnits
            units.sort(key=lambda x: self.me.get_distance_to_unit(self.forward))
            self.trySkate(units[0].x, units[0].y)
            return True

    def setStrategyTakePuck(self):
        if self.world.puck.owner_player_id == self.me.player_id:
            return False
        elif self.me.get_distance_to_unit(self.world.puck) < self.game.stick_length:
            self.move_turn = self.me.get_angle_to_unit(self.world.puck)
            self.move_speed_up = 1.0
            self.move_action = ActionType.TAKE_PUCK
        elif abs(self.player.net_front - self.me.x) > self.game.world_width / 2.0 and self.tryStrikeOpponent():
            return True
        else:
            puck = self.world.puck
            (max_speed_x, max_speed_y) = (puck.speed_x - self.me.speed_x, puck.speed_y - self.me.speed_y)
            max_speed = sqrt(max_speed_x * max_speed_x + max_speed_y * max_speed_y)

            if max_speed == 0.0:
                n_tick = 1.0
            elif self.me.get_distance_to_unit(self.world.puck) < self.game.stick_length:
                n_tick = 1.0
            else:
                n_tick = self.me.get_distance_to_unit(self.world.puck) / max_speed

            if n_tick > 40.0:
                n_tick = 40.0
            if n_tick < 7.0:
                n_tick = 1.0

            gotoX = self.world.puck.x + self.world.puck.speed_x * n_tick

            if gotoX < self.game.rink_left or gotoX > self.game.rink_right:
                gotoX = self.me.x

            gotoY = self.world.puck.y + self.world.puck.speed_y * n_tick

            if gotoY < self.game.rink_top or gotoY > self.game.rink_bottom:
                gotoY = self.me.y

            self.calcAcceleration(gotoX, gotoY)

            self.move_action = ActionType.TAKE_PUCK

            return True

    def setStrategyAttackGate(self):

        # if the position is good or i am swinging >> let's strike!
        if (
            self.me.get_distance_to_unit(self.attackCircle) < self.attackCircle.radius
            and abs(self.me.get_angle_to_unit(self.attackCircle)) < self.attackAngle
        ) or self.me.state == HockeyistState.SWINGING:
            strikeX = self.opponentPlayer.net_front
            if self.me.y < self.rink_center_y:
                strikeY1 = self.opponentPlayer.net_bottom - self.world.puck.radius
                strikeY2 = self.opponentPlayer.net_bottom - 2.0 * self.world.puck.radius
            else:
                strikeY1 = self.opponentPlayer.net_top + self.world.puck.radius
                strikeY2 = self.opponentPlayer.net_top + 2.0 * self.world.puck.radius

            unit1 = Unit(9910, 0.0, 0.0, strikeX, strikeY1, 0.0, 0.0, 0.0, 0.0)
            unit2 = Unit(9911, 0.0, 0.0, strikeX, strikeY2, 0.0, 0.0, 0.0, 0.0)
            dist1 = min([dist2segment(self.me, unit1, opponent) for opponent in self.opponentUnits])
            dist2 = min([dist2segment(self.me, unit2, opponent) for opponent in self.opponentUnits])

            if dist1 < dist2:
                # print "trystrike2 " + str(dist1) + " " + str(dist2)
                self.tryStrike(strikeX, strikeY2)
            else:
                # print "trystrike1 " + str(dist1) + " " + str(dist2)
                self.tryStrike(strikeX, strikeY1)

            return True

        if abs(self.me.x - self.opponentPlayer.net_front) > self.game.world_width / 2.0:
            if self.me.y < self.rink_center_y:
                self.trySkate(self.attackCircle.x, 0.2 * self.game.world_height)
            else:
                self.trySkate(self.attackCircle.x, 0.8 * self.game.world_height)
        else:
            if self.me.y < self.rink_center_y:
                self.trySkate(self.attackCircle.x, self.opponentPlayer.net_bottom - self.world.puck.radius)
            else:
                self.trySkate(self.attackCircle.x, self.opponentPlayer.net_top + self.world.puck.radius)
        return True

    def tryStrike(self, strikeX, strikeY):
        PASS_ACCURACY = pi / 3.0
        STRIKE_ACCURACY = 1.0 * pi / 180.0

        angle = self.me.get_angle_to(strikeX, strikeY)

        self.move_turn = angle
        self.move_speed_up = 1.0

        danger = False
        for opponentUnit in self.opponentUnits:
            if (
                opponentUnit.get_distance_to_unit(self.me) < 1.1 * self.game.stick_length
                and abs(opponentUnit.get_angle_to_unit(self.me)) < 0.6 * self.game.stick_sector
                and opponentUnit.state != HockeyistState.KNOCKED_DOWN
            ):
                danger = True

            if (
                opponentUnit.get_distance_to_unit(self.world.puck) < 1.1 * self.game.stick_length
                and abs(opponentUnit.get_angle_to_unit(self.world.puck)) < 0.7 * self.game.stick_sector
                and opponentUnit.state != HockeyistState.KNOCKED_DOWN
            ):
                danger = True

        if abs(angle) < STRIKE_ACCURACY and self.me.get_distance_to_unit(self.attackCircle) > self.attackPassDistance:
            if self.me.swing_ticks < self.game.max_effective_swing_ticks and not danger:
                # print "swing: " + str(self.me.swing_ticks)
                self.move_action = ActionType.SWING

                return True

        if self.me.state == HockeyistState.SWINGING or abs(angle) < STRIKE_ACCURACY:
            # print "strike puck: " + str(self.me.swing_ticks)
            self.move_action = ActionType.STRIKE

            return True

        if (
            abs(angle) < PASS_ACCURACY
            # and danger
            and self.me.state != HockeyistState.SWINGING
            and self.me.get_distance_to_unit(self.attackCircle) < self.attackPassDistance
        ):
            print "strike pass"
            unit = Unit(9912, 0.0, 0.0, strikeX, strikeY, 0.0, 0.0, 0.0, 0.0)
            self.tryPass("Strike", unit)
            return True

        return False

    def trySkate(self, skateX, skateY, zeroSpeed=False):
        if self.world.puck.owner_hockeyist_id == self.me.id:
            # print "trySkate: calcAcceleration1"
            self.calcAcceleration(skateX, skateY)

            # if self.speed < 0.1:
            test = Unit(
                9913,
                0.0,
                0.0,
                self.me.x + 6.0 * self.me.radius * cos(self.me.angle + self.move_turn),
                self.me.y + 6.0 * self.me.radius * sin(self.me.angle + self.move_turn),
                0.0,
                0.0,
                0.0,
                0.0,
            )

            dangerUnits = [unit for unit in self.opponentUnits if unit.get_angle_to_unit(self.me) < pi / 3.0]
            if dangerUnits:
                dangerUnits.sort(key=lambda x: dist2segment(self.me, test, x))
                dist = dist2segment(self.me, test, dangerUnits[0])

                if dist < 10.0 and self.me.get_angle_to_unit(dangerUnits[0]) < 0.0:
                    self.move_turn = self.game.hockeyist_turn_angle_factor
                    # print "me+puck: angle +"
                elif dist < 10.0:
                    self.move_turn = -self.game.hockeyist_turn_angle_factor
                    # print "me+puck: angle -"

            return True

        elif self.tryStrikeOpponent():
            # print "trySkate: tryStrikeOpponent"
            return True

        elif zeroSpeed:
            # i don't have a puck
            # i don't have a puck

            angle = self.me.get_angle_to(skateX, skateY)
            dist = self.me.get_distance_to(skateX, skateY)

            # if dist < 10.0*self.me.radius and abs(angle) > pi/2:
            if abs(angle) > pi / 2.0 and dist < self.game.world_width / 2.0:
                # going back
                if angle > 0.0:
                    self.move_turn = angle - pi
                else:
                    self.move_turn = angle + pi

                if self.speed >= 0.0:
                    self.move_speed_up = -1.0
                elif dist / self.speed > self.speed / self.game.hockeyist_speed_up_factor:
                    self.move_speed_up = self.speed / self.game.hockeyist_speed_up_factor
                else:
                    self.move_speed_up = -1.0

            else:
                # going front

                self.move_turn = angle

                if self.speed <= 0.0:
                    self.move_speed_up = 1.0
                elif dist / self.speed < self.speed / self.game.hockeyist_speed_down_factor:
                    self.move_speed_up = -self.speed / self.game.hockeyist_speed_down_factor
                else:
                    self.move_speed_up = 1.0

            # print "zeroSpeed: " + str(self.move_turn) + " " + str(self.move_speed_up)
            return True

        else:
            # print "trySkate: calcAcceleration2"
            self.calcAcceleration(skateX, skateY)

            if self.speed < 0.1:
                test = Unit(
                    9914,
                    0.0,
                    0.0,
                    self.me.x + 2.0 * self.me.radius * cos(self.me.angle + self.move_turn),
                    self.me.y + 2.0 * self.me.radius * sin(self.me.angle + self.move_turn),
                    0.0,
                    0.0,
                    0.0,
                    0.0,
                )

                dist = min([unit.get_distance_to_unit(test) for unit in self.opponentUnits])
                if (
                    test.x < self.game.rink_left
                    or test.x > self.game.rink_right
                    or test.y < self.game.rink_top
                    or test.y > self.game.rink_bottom
                ):
                    dist = 0.0

                if dist < 2.0 and self.me.get_angle_to_unit(self.attackCircle) > 0.0:
                    self.move_turn += self.game.hockeyist_turn_angle_factor
                    # print "me-puck: angle +"
                elif dist < 2.0:
                    self.move_turn -= self.game.hockeyist_turn_angle_factor
                    # print "me-puck: angle -"

            return True