Пример #1
0
def step(d):
    startTime = time.perf_counter()

    d.state['gameStep'] += 1
    d.state['serverSteps'] += 1

    # for each bot that is alive, copy health to so we know what it was at the start of the step.
    aliveBots = {}
    for src, bot in d.bots.items():
        if bot['health'] != 0:
            aliveBots[src] = bot['health']

    # for all bots that are alive
    for src, bot in d.bots.items():
        if src in aliveBots:
            # change speed if needed
            if bot['currentSpeed'] > bot['requestedSpeed']:
                bot['currentSpeed'] -= d.getClassValue('botAccRate', bot['class'])
                if bot['currentSpeed'] < bot['requestedSpeed']:
                    bot['currentSpeed'] = bot['requestedSpeed']
            elif bot['currentSpeed'] < bot['requestedSpeed']:
                bot['currentSpeed'] += d.getClassValue('botAccRate', bot['class'])
                if bot['currentSpeed'] > bot['requestedSpeed']:
                    bot['currentSpeed'] = bot['requestedSpeed']

            # change direction if needed
            if bot['currentDirection'] != bot['requestedDirection']:
                if bot['currentDirection'] != bot['requestedDirection'] and bot['currentSpeed'] == 0:
                    # turn instanly if bot is not moving
                    bot['currentDirection'] = bot['requestedDirection']
                else:
                    # how much can we turn at the speed we are going?
                    turnRate = d.getClassValue('botMinTurnRate', bot['class']) \
                        + (d.getClassValue('botMaxTurnRate', bot['class']) -
                           d.getClassValue('botMinTurnRate', bot['class'])) \
                        * (1 - bot['currentSpeed'] / 100)

                    # if turn is negative and does not pass over 0 radians
                    if bot['currentDirection'] > bot['requestedDirection'] and \
                            bot['currentDirection'] - bot['requestedDirection'] <= math.pi:
                        bot['currentDirection'] -= turnRate
                        if bot['currentDirection'] <= bot['requestedDirection']:
                            bot['currentDirection'] = bot['requestedDirection']

                    # if turn is negative and passes over 0 radians, so we may need to normalize angle
                    elif bot['requestedDirection'] > bot['currentDirection'] and \
                            bot['requestedDirection'] - bot['currentDirection'] >= math.pi:
                        bot['currentDirection'] = nbmath.normalizeAngle(bot['currentDirection'] - turnRate)
                        if bot['currentDirection'] <= bot['requestedDirection'] and bot['currentDirection'] >= bot['requestedDirection'] - math.pi:
                            bot['currentDirection'] = bot['requestedDirection']

                    # if turn is positive and does not pass over 0 radians
                    elif bot['requestedDirection'] > bot['currentDirection'] and \
                            bot['requestedDirection'] - bot['currentDirection'] <= math.pi:
                        bot['currentDirection'] += turnRate
                        if bot['requestedDirection'] <= bot['currentDirection']:
                            bot['currentDirection'] = bot['requestedDirection']

                    # if turn is positive and passes over 0 radians
                    elif bot['currentDirection'] > bot['requestedDirection'] and \
                            bot['currentDirection'] - bot['requestedDirection'] >= math.pi:
                        bot['currentDirection'] = nbmath.normalizeAngle(bot['currentDirection'] + turnRate)
                        if bot['currentDirection'] >= bot['requestedDirection'] and bot['currentDirection'] <= bot['requestedDirection'] + math.pi:
                            bot['currentDirection'] = bot['requestedDirection']
            # move bot
            if bot['currentSpeed'] != 0:
                bot['x'], bot['y'] = nbmath.project(bot['x'], bot['y'],
                                        bot['currentDirection'],
                                        bot['currentSpeed'] / 100.0 * d.getClassValue('botMaxSpeed', bot['class']))

    # set starting hitSeverity to 0 for all robots. hitSeverity == 0 means robot did not 
    # hit anything this step.
    for src, bot in d.bots.items():
        bot['hitSeverity'] = 0.0

    # do until we get one clean pass where no bot hitting wall, obstacle or other bot.
    foundOverlap = True
    while foundOverlap:
        foundOverlap = False

        # detect if bots hit walls. if they, did move them so they are just barely not touching,
        for src, bot in d.bots.items():
            hitSeverity = 0
            if bot['x'] - d.conf['botRadius'] < 0:
                # hit left side
                bot['x'] = d.conf['botRadius'] + 1
                hitSeverity = getHitSeverity(d, bot, math.pi)
            if bot['x'] + d.conf['botRadius'] > d.conf['arenaSize']:
                # hit right side
                bot['x'] = d.conf['arenaSize'] - d.conf['botRadius'] - 1
                hitSeverity = getHitSeverity(d, bot, 0)
            if bot['y'] - d.conf['botRadius'] < 0:
                # hit bottom side
                bot['y'] = d.conf['botRadius'] + 1
                hitSeverity = getHitSeverity(d, bot, math.pi * 3 / 2)
            if bot['y'] + d.conf['botRadius'] > d.conf['arenaSize']:
                # hit top side
                bot['y'] = d.conf['arenaSize'] - d.conf['botRadius'] - 1
                hitSeverity = getHitSeverity(d, bot, math.pi/2)
    
            if hitSeverity:
                foundOverlap = True
                bot['hitSeverity'] = max(bot['hitSeverity'], hitSeverity)

        # detect if bots hit obstacles, if the did move them so they are just barely not touching,
        overlap = findOverlapingBotsAndObstacles(d, d.bots)
        while overlap:
            foundOverlap = True
            b = d.bots[overlap[0]]
            o = overlap[1]
            # find angle to move bot directly away from obstacle
            a = nbmath.angle(o['x'], o['y'], b['x'], b['y'])
            # find min distance to move bot so it don't touch (plus 0.5 for safety).
            distance = d.conf['botRadius'] + o['radius'] + 0.5 - nbmath.distance(o['x'], o['y'], b['x'], b['y'])
            # move bot
            b['x'], b['y'] = nbmath.project(b['x'], b['y'], a, distance)
            # record damage
            hitSeverity = getHitSeverity(d, b, a + math.pi)
            b['hitSeverity'] = max(b['hitSeverity'], hitSeverity)
            # check for more bots overlapping
            overlap = findOverlapingBotsAndObstacles(d, d.bots)
                    
        # detect if bots hit other bots, if the did move them so they are just barely not touching,
        overlap = findOverlapingBots(d, d.bots)
        while overlap:
            foundOverlap = True
            b1 = d.bots[overlap[0]]
            b2 = d.bots[overlap[1]]
            # find angle to move bot directly away from each other
            a = nbmath.angle(b1['x'], b1['y'], b2['x'], b2['y'])
            # find min distance to move each bot so they don't touch (plus 0.5 for saftly).
            between = nbmath.distance(b1['x'], b1['y'], b2['x'], b2['y'])
            distance = between / 2 - (between - d.conf['botRadius']) + 0.5
            # move bots
            b1['x'], b1['y'] = nbmath.project(b1['x'], b1['y'], a + math.pi, distance)
            b2['x'], b2['y'] = nbmath.project(b2['x'], b2['y'], a, distance)
            # record damage
            hitSeverity = getHitSeverity(d, b1, a, b2)
            b1['hitSeverity'] = max(b1['hitSeverity'], hitSeverity)
            b2['hitSeverity'] = max(b2['hitSeverity'], hitSeverity)
            # check for more bots overlapping
            overlap = findOverlapingBots(d, d.bots)

    # give damage (only once this step) to bots that hit things. Also stop them.
    for src, bot in d.bots.items():
        if bot['hitSeverity']:
            if d.conf['simpleCollisions']:
                bot['hitSeverity'] = 1
            bot['health'] = max(0, bot['health'] - bot['hitSeverity'] * d.conf['hitDamage'] * d.getClassValue('botArmor', bot['class']))
            bot['currentSpeed'] = 0
            bot['requestedSpeed'] = 0
        del bot['hitSeverity']

    # for all shells
    for src in list(d.shells.keys()):
        shell = d.shells[src]

        # remember shells start point before moving
        oldx = shell['x']
        oldy = shell['y']

        # move shell
        distance = min(d.getClassValue('shellSpeed', d.bots[src]['class']), shell['distanceRemaining'])
        shell['x'], shell['y'] = nbmath.project(shell['x'], shell['y'], shell['direction'], distance)
        shell['distanceRemaining'] -= distance

        # did shell hit an obstacle?
        shellHitObstacle = False
        for o in d.conf['obstacles']:
            if nbmath.intersectLineCircle(oldx, oldy, shell['x'], shell['y'], o['x'], o['y'], o['radius']):
                shellHitObstacle = True

        # if did not hit an obstacle and shell's explosion would touch inside of arena
        if not shellHitObstacle and \
           (shell['x'] > d.getClassValue('explRadius', d.bots[src]['class']) * -1 and shell['x'] < d.conf['arenaSize'] + d.getClassValue('explRadius', d.bots[src]['class']) and
                shell['y'] > d.getClassValue('explRadius', d.bots[src]['class']) * -1 and shell['y'] < d.conf['arenaSize'] + d.getClassValue('explRadius', d.bots[src]['class'])):

            # if shell has reached it destination then explode.
            if shell['distanceRemaining'] <= 0:
                # apply damage to bots.
                for k, bot in d.bots.items():
                    if bot['health'] > 0:
                        distance = nbmath.distance(bot['x'], bot['y'], shell['x'], shell['y'])
                        if distance < d.getClassValue('explRadius', d.bots[src]['class']):
                            damage = d.getClassValue('explDamage', d.bots[src]['class']) * (1 - distance / d.getClassValue('explRadius', d.bots[src]['class']))
                            bot['health'] = max(0, bot['health'] - (damage * d.getClassValue('botArmor', bot['class'])))
                            # allow recording of inflicting damage that is greater than health of hit robot.
                            # also record damage to oneself.
                            d.bots[src]['shellDamage'] += damage

                # store the explosion so viewers can display it. we can't use src as index because it is possible for two explosions
                # from same bot to exist (but not likly).
                d.explosions[d.state['explIndex']] = {
                    'x': shell['x'],
                    'y': shell['y'],
                    'stepsAgo': 0,
                    'src': src  # this is needed by viewer to color this explosion based on the bot who fired it.
                    }
                d.state['explIndex'] += 1
                if d.state['explIndex'] > 65000:
                    d.state['explIndex'] = 0

                # this shell exploed so remove it
                del d.shells[src]
        else:
            # shell hit obstacle or left arena so remove it without exploding
            del d.shells[src]

    # Remove old explosions and add 1 to other explosions stepsAgo.
    # Note, We only keep these around so the viewer can do a nice animation
    # over a number of steps before they are removed.
    for key in list(d.explosions.keys()):
        expl = d.explosions[key]
        if expl['stepsAgo'] == d.conf['keepExplosionSteps']:
            del d.explosions[key]
        else:
            expl['stepsAgo'] += 1

    # find how many points bots that died this step will get. (Based on how many bots have died previouly)
    if len(aliveBots) == d.conf['botsInGame']:
        points = 0  # first to die
    elif len(aliveBots) > d.conf['botsInGame'] / 2:
        points = 2  # died in first half
    else:
        points = 5  # died in second half

    # Kill all bots if we have reached the max steps and there is still more than one bot alive.
    if d.state['gameStep'] == d.conf['stepMax'] and len(aliveBots) != 1:
        log("Game reached stepMax with more than one bot alive. Killing all bots.")
        for src in aliveBots:
            d.bots[src]['health'] = 0

    # Assign points to bots that died this turn
    for src in list(aliveBots.keys()):
        if d.bots[src]['health'] == 0:
            d.bots[src]['points'] += points
            del aliveBots[src]

    # If only one bot is left then end game.
    if len(aliveBots) == 1:
        src = list(aliveBots.keys())[0]
        d.bots[src]['winHealth'] += d.bots[src]['health']
        d.bots[src]['winCount'] += 1
        d.bots[src]['health'] = 0
        d.bots[src]['points'] += 10  # last robot (winner)
        del aliveBots[src]

    d.state['stepTime'] += time.perf_counter() - startTime
Пример #2
0
def play(botSocket, srvConf):
    gameNumber = 0  # The last game number bot got from the server (0 == no game has been started)

    while True:
        try:
            # Get information to determine if bot is alive (health > 0) and if a new game has started.
            getInfoReply = botSocket.sendRecvMessage(
                {'type': 'getInfoRequest'})
        except nbipc.NetBotSocketException as e:
            # We are always allowed to make getInfoRequests, even if our health == 0. Something serious has gone wrong.
            log(str(e), "FAILURE")
            log("Is netbot server still running?")
            quit()

        if getInfoReply['health'] == 0:
            # we are dead, there is nothing we can do until we are alive again.
            continue

        if getInfoReply['gameNumber'] != gameNumber:
            # A new game has started. Record new gameNumber and reset any variables back to their initial state
            gameNumber = getInfoReply['gameNumber']
            log("Game " + str(gameNumber) + " has started. Points so far = " +
                str(getInfoReply['points']))

            maxSpeed = 70
            reversing = False
            scanCounter = 0
            defensiveScan = False
            counter = 0
            direction = 0
            speed = 50
            startingDirection = True
            wall = ""
            currentMode = "scan"
            scanSlices = 32
            nextScanSlice = 0
            scanSliceWidth = math.pi * 2 / scanSlices
            maxScanSlice = 0
            minScanSlice = 0

            getLocationReply = botSocket.sendRecvMessage(
                {'type': 'getLocationRequest'})
            x = getLocationReply['x']
            y = getLocationReply['y']

            # run to nearest wall from starting location
            if x < 500 and y < 500:
                if x >= y:
                    direction = math.pi * 3 / 2
                    wall = "down"
                else:
                    direction = math.pi
                    wall = "left"
            elif x < 500 and y >= 500:
                if x >= 1000 - y:
                    direction = math.pi / 2
                    wall = "up"
                else:
                    direction = math.pi
                    wall = "left"
            elif x >= 500 and y < 500:
                if 1000 - x <= y:
                    direction = 0
                    wall = "right"
                else:
                    direction = math.pi * 3 / 2
                    wall = "down"
            elif x >= 500 and y >= 500:
                if x >= y:
                    direction = 0
                    wall = "right"
                else:
                    direction = math.pi / 2
                    wall = "up"

        try:

            getLocationReply = botSocket.sendRecvMessage(
                {'type': 'getLocationRequest'})
            x = getLocationReply['x']
            y = getLocationReply['y']
            getSpeedReply = botSocket.sendRecvMessage(
                {'type': 'getSpeedRequest'})

            if getSpeedReply['currentSpeed'] == 0:

                if not (startingDirection):
                    direction = reverseDirection(direction, wall)
                if counter >= 1:
                    startingDirection = False

                # Turn in a new direction
                botSocket.sendRecvMessage({
                    'type': 'setDirectionRequest',
                    'requestedDirection': direction
                })

                speed = maxSpeed

                # log some useful information.
                log(
                    "Requested to go " + str(direction / math.pi) +
                    " pi radians at speed: " + str(speed), "INFO")
                botSocket.sendRecvMessage({
                    'type': 'setSpeedRequest',
                    'requestedSpeed': speed
                })
                reversing = False

            elif not (reversing):

                if startingDirection:
                    if (x <= 100 and direction
                            == math.pi) or (x >= 900 and direction == 0) or (
                                y <= 100 and direction == math.pi * 3 / 2) or (
                                    y >= 900 and direction == math.pi / 2):
                        speed = 10
                else:
                    if (x <= 200 and direction
                            == math.pi) or (x >= 800 and direction == 0) or (
                                y <= 200 and direction == math.pi * 3 / 2) or (
                                    y >= 800 and direction == math.pi / 2):
                        speed = 0
                        reversing = True
                    else:
                        speed = maxSpeed

                botSocket.sendRecvMessage({
                    'type': 'setSpeedRequest',
                    'requestedSpeed': speed
                })

            if not (startingDirection):
                if currentMode == "wait":
                    # find out if we already have a shell in the air. We need to wait for it to explode before
                    # we fire another shell. If we don't then the first shell will never explode!
                    getCanonReply = botSocket.sendRecvMessage(
                        {'type': 'getCanonRequest'})
                    if not getCanonReply['shellInProgress']:
                        # we are ready to shoot again!
                        currentMode = "scan"

                if currentMode == "scan":

                    defensiveScan = True if scanCounter % 6 == 0 else False

                    # defensive scan
                    if defensiveScan:

                        scanSliceTemp = nextScanSlice

                        scanRadStart = direction - math.pi / 4
                        scanRadEnd = direction + math.pi / 4

                        scanRadStart = nbmath.normalizeAngle(scanRadStart)
                        scanRadEnd = nbmath.normalizeAngle(scanRadEnd)

                        if scan(scanRadStart, scanRadEnd):
                            reverseDirection(direction, wall)

                    else:

                        scanning(minScanSlice, maxScanSlice, 1)
                        getLocationReply = botSocket.sendRecvMessage(
                            {'type': 'getLocationRequest'})
                        x = getLocationReply['x']
                        y = getLocationReply['y']

                        botSocket.sendRecvMessage({
                            'type':
                            'fireCanonRequest',
                            'direction':
                            nbmath.angle(x, y, enemyX, enemyY),
                            'distance':
                            nbmath.distance(x, y, enemyX, enemyY)
                        })
                        currentMode = "wait"

                    scanCounter += 1

            # initialize starting scan slice
            else:
                if wall == "up":
                    minScanSlice = 16
                    maxScanSlice = 32
                elif wall == "left":
                    minScanSlice = 24
                    maxScanSlice = 8
                elif wall == "down":
                    minScanSlice = 0
                    maxScanSlice = 16
                elif wall == "right":
                    minScanSlice = 8
                    maxScanSlice = 24

            counter += 1

        except nbipc.NetBotSocketException as e:
            # Consider this a warning here. It may simply be that a request returned
            # an Error reply because our health == 0 since we last checked. We can
            # continue until the next game starts.
            log(str(e), "WARNING")
            continue
Пример #3
0
def play(botSocket, srvConf):
    gameNumber = 0  # The last game number bot got from the server (0 == no game has been started)

    # Each scan will be this wide in radians (note, math.pi*2 radians is the same as 360 Degrees)
    scanSliceWidth = math.pi

    while True:
        try:
            # Get information to determine if bot is alive (health > 0) and if a new game has started.
            getInfoReply = botSocket.sendRecvMessage(
                {'type': 'getInfoRequest'})
        except nbipc.NetBotSocketException as e:
            # We are always allowed to make getInfoRequests, even if our health == 0. Something serious has gone wrong.
            log(str(e), "FAILURE")
            log("Is netbot server still running?")
            quit()

        if getInfoReply['health'] == 0:
            # we are dead, there is nothing we can do until we are alive again.
            continue

        if getInfoReply['gameNumber'] != gameNumber:
            # A new game has started. Record new gameNumber and reset any variables back to their initial state
            gameNumber = getInfoReply['gameNumber']
            log("Game " + str(gameNumber) + " has started. Points so far = " +
                str(getInfoReply['points']))

            # start every new game in scan mode. No point waiting if we know we have not fired our canon yet.
            currentMode = "scan"

            # The distance to the closest bot in each quadrant is stored in this list.
            quadrant = [0, 0, 0, 0]

        try:
            if currentMode == "wait":
                # find out if we already have a shell in the air. We need to wait for it to explode before
                # we fire another shell. If we don't then the first shell will never explode!
                getCanonReply = botSocket.sendRecvMessage(
                    {'type': 'getCanonRequest'})
                if not getCanonReply['shellInProgress']:
                    # we are ready to shoot again!
                    currentMode = "scan"

            if currentMode == "scan":
                scanRadStart = 0
                scanRadEnd = math.pi

                while scanRadStart <= scanRadEnd:
                    if scanRadEnd > 2 * math.pi:
                        scanRadEnd = 2 * math.pi
                    scanReply = botSocket.sendRecvMessage({
                        'type':
                        'scanRequest',
                        'startRadians':
                        scanRadStart,
                        'endRadians':
                        scanRadEnd
                    })
                    necWidth = math.pi / 32 if scanReply[
                        'distance'] >= 500 else math.pi / 16
                    #log('distance: %s' % scanReply['distance'], 'INFO')
                    if scanReply[
                            'distance'] != 0 and scanSliceWidth <= necWidth:
                        fireDirection = scanRadStart + scanSliceWidth / 2
                        fireDirection = nbmath.normalizeAngle(fireDirection)
                        botSocket.sendRecvMessage({
                            'type':
                            'fireCanonRequest',
                            'direction':
                            fireDirection,
                            'distance':
                            scanReply['distance']
                        })
                        currentMode = "wait"
                    elif scanReply[
                            'distance'] != 0 and scanSliceWidth >= necWidth:
                        scanSliceWidth /= 2
                        scanRadEnd = (scanRadStart + scanRadEnd) / 2
                    else:
                        scanRadStart = scanRadEnd
                        scanRadEnd = scanRadStart + scanSliceWidth
                    if scanReply[
                            'distance'] == 0 and scanSliceWidth <= necWidth:
                        scanSliceWidth *= 2
                    elif currentMode == "wait":
                        break
                scanSliceWidth = math.pi

        except nbipc.NetBotSocketException as e:
            # Consider this a warning here. It may simply be that a request returned
            # an Error reply because our health == 0 since we last checked. We can
            # continue until the next game starts.
            log(str(e), "WARNING")
            continue
            '''
                pi/2
            pi        0
               3pi/2            
            '''
        try:

            # turns around before hitting the edge, hopefully
            getLocationReply = botSocket.sendRecvMessage(
                {'type': 'getLocationRequest'})
            xMin = math.pi / 2 + random.random() * math.pi - math.pi
            xR = xMin if xMin > 0 else 3 * math.pi / 2 + random.random(
            ) * math.pi / 2
            x = getLocationReply['x']
            y = getLocationReply['y']
            if abs(x - 1000) < 300 or abs(y - 1000) < 300 or abs(
                    x - 1000) > 700 or abs(y - 1000) > 300:
                botSocket.sendRecvMessage({
                    'type': 'setSpeedRequest',
                    'requestedSpeed': 0
                })
            #lower x boundary
            if round(getLocationReply['x']) <= srvConf['botRadius'] + 500:
                botSocket.sendRecvMessage({
                    'type': 'setDirectionRequest',
                    'requestedDirection': xR
                })
                botSocket.sendMessage({
                    'type': 'setSpeedRequest',
                    'requestedSpeed': 35
                })
            #upper x boundary
            elif round(getLocationReply['x']
                       ) >= srvConf['arenaSize'] - srvConf['botRadius'] - 500:
                botSocket.sendRecvMessage({
                    'type':
                    'setDirectionRequest',
                    'requestedDirection':
                    math.pi / 2 + random.random() * math.pi
                })
                botSocket.sendMessage({
                    'type': 'setSpeedRequest',
                    'requestedSpeed': 35
                })
            #lower y boundary
            elif round(getLocationReply['y']) <= srvConf['botRadius'] + 500:
                botSocket.sendRecvMessage({
                    'type':
                    'setDirectionRequest',
                    'requestedDirection':
                    random.random() * math.pi
                })
                botSocket.sendMessage({
                    'type': 'setSpeedRequest',
                    'requestedSpeed': 35
                })
            #upper y boundary
            elif round(getLocationReply['y']
                       ) >= srvConf['arenaSize'] - srvConf['botRadius'] - 500:
                botSocket.sendRecvMessage({
                    'type':
                    'setDirectionRequest',
                    'requestedDirection':
                    math.pi + random.random() * math.pi
                })
                botSocket.sendMessage({
                    'type': 'setSpeedRequest',
                    'requestedSpeed': 35
                })
            else:
                # variables that are iterated in the while loop
                x = 0
                i = 0

                # ScaredyCat scans all four quadrants and looks for the closest target
                while x < 2.0:

                    # ScaredyCat scans the quadrant starting from x pi to 1/2 more than x. This is a quarter of a circle.
                    # Then , it adds the server's response to the list
                    scanReply = botSocket.sendRecvMessage({
                        'type':
                        'scanRequest',
                        'startRadians':
                        math.pi * x,
                        'endRadians':
                        math.pi * (x + 1.0 / 2.0)
                    })
                    quadrant[i] = scanReply['distance']
                    x += 1.0 / 2.0
                    i += 1

                # finds how far the closest enemy is from us (can't be zero)
                minDistance = min(i for i in quadrant if i > 0)

                # finds which quadrant that enemy is in
                moveDirection = quadrant.index(minDistance)

                # move perpendicular to the enemy.
                # ie. if closest enemy is in quadrant 0, it will move in the direction 3pi/4 or 7pi/4
                '''
                      pi/2
                    1   |   0
                 pi ----|----  0
                    2   |   3
                      3pi/2
                '''
                move1 = 5 * math.pi / 4 + random.random() * math.pi
                move2 = 7 * math.pi / 4 + random.random() * math.pi
                move3 = move1 if move1 < 2 * math.pi else random.random(
                ) * math.pi / 4
                move4 = move2 if move2 < 2 * math.pi else random.random(
                ) * 3 * math.pi / 4
                if moveDirection == 0:
                    moveDirection = math.pi * (3.0 /
                                               4.0) + random.random() * math.pi
                elif moveDirection == 1:
                    moveDirection = move3
                elif moveDirection == 2:
                    moveDirection = move4
                elif moveDirection == 3:
                    moveDirection = math.pi * (1.0 /
                                               4.0) + random.random() * math.pi

                # Turn in a new direction
                botSocket.sendMessage({
                    'type': 'setDirectionRequest',
                    'requestedDirection': moveDirection
                })

                # Request we start accelerating to max speed
                botSocket.sendMessage({
                    'type': 'setSpeedRequest',
                    'requestedSpeed': 20
                })

        except nbipc.NetBotSocketException as e:
            # Consider this a warning here. It may simply be that a request returned
            # an Error reply because our health == 0 since we last checked. We can
            # continue until the next game starts.
            log(str(e), "WARNING")
            continue
            '''
Пример #4
0
def play(botSocket, srvConf, q):
    arenaSize = srvConf["arenaSize"]
    gameNumber = 0  # The last game number bot got from the server (0 == no game has been started)
    getLocationReply = {"x": 0, "y": 0}
    mouseDown = False
    mousePos = {"x": 0, "y": 0}
    waiting = True  # whether to wait for shell to explode
    firing_distance = 0
    shell_time = 0
    global keysDown
    global steering

    def shoot():
        nonlocal mousePos

        angle = nbmath.angle(getLocationReply["x"], getLocationReply["y"],
                             mousePos["x"], mousePos["y"])
        dist = nbmath.distance(getLocationReply["x"], getLocationReply["y"],
                               mousePos["x"], mousePos["y"])
        botSocket.sendMessage({
            "type": "fireCanonRequest",
            "direction": angle,
            "distance": dist
        })

        shell_time = time.perf_counter()
        firing_distance = dist

    # log the keys being used
    log("The up key is " + str(upKey), "INFO")
    log("The down key is " + str(downKey), "INFO")
    log("The left key is " + str(leftKey), "INFO")
    log("The right key is " + str(rightKey), "INFO")

    # log the current movement mode
    if (steering):
        log(
            "Steering. Use left and right keys to steer, and up and down to " +
            "control speed.", "INFO")
    else:
        log("Directional movement. Bot will go in direction of keys pressed.",
            "INFO")

    while True:
        try:
            #Get information to determine if bot is alive (health > 0) and if a new game has started.
            getInfoReply = botSocket.sendRecvMessage(
                {'type': 'getInfoRequest'})
        except nbipc.NetBotSocketException as e:
            #We are always allowed to make getInfoRequests, even if our health == 0. Something serious has gone wrong.
            log(str(e), "FAILURE")
            log("Is netbot server still running?")
            quit()

        if getInfoReply['health'] == 0:
            #we are dead, there is nothing we can do until we are alive again.
            continue

        if getInfoReply['gameNumber'] != gameNumber:
            #A new game has started. Record new gameNumber and reset any variables back to their initial state
            gameNumber = getInfoReply['gameNumber']
            log("Game " + str(gameNumber) + " has started. Points so far = " +
                str(getInfoReply['points']))

            # Reset variables
            keysDown["Up"] = False
            keysDown["Down"] = False
            keysDown["Left"] = False
            keysDown["Right"] = False
            mouseDown = False
            waiting = True

        try:
            getLocationReply = botSocket.sendRecvMessage(
                {"type": "getLocationRequest"})
            getSpeedReply = botSocket.sendRecvMessage(
                {"type": "getSpeedRequest"})
            radians = 0
            requestedSpeed = getSpeedReply["currentSpeed"]  # will add to later

            # check for shots using a queue (good asynchronous/threading practice)
            # hey wait why is this a queue but key-presses aren't?? MARTIN!
            while not q.empty():
                nextData = q.get()
                if ("mousePos" in nextData):
                    mousePos = nextData["mousePos"]
                elif ("mouseDown" in nextData):
                    mouseDown = nextData["mouseDown"]

                    # force a shot on click to emulate old behaviour for
                    # those who thoroughly enjoyed clicking to shoot
                    if (mouseDown == True):
                        shoot()
                        waiting = True
                    else:
                        waiting = False
                else:
                    # no I don't feel like ending the program today
                    log("Unexpected index name in q: " + str(q), "WARNING")
                q.task_done()

            # bot steers left and right, and up and down control speed
            if (steering):
                currAngle = botSocket.sendRecvMessage(
                    {"type": "getDirectionRequest"})

                radians = currAngle["currentDirection"]  # will add to later

                # steer
                if (keysDown["Left"]):
                    radians += 1  # ~pi/3 radians or ~60
                    radians = nbmath.normalizeAngle(radians)
                elif (keysDown["Right"]):
                    radians -= 1
                    radians = nbmath.normalizeAngle(radians)

                # speed up
                if (keysDown["Up"]):
                    requestedSpeed = 100

                # slow down
                elif (keysDown["Down"]):
                    requestedSpeed = 0

            # bot moves in direction of arrow keys
            else:
                xDir = 0
                yDir = 0

                if (keysDown["Left"]):
                    xDir = -1
                elif (keysDown["Right"]):
                    xDir = 1
                else:
                    xDir = 0

                if (keysDown["Up"]):
                    yDir = 1
                elif (keysDown["Down"]):
                    yDir = -1
                else:
                    yDir = 0

                if (xDir == 0 and yDir == 0):
                    requestedSpeed = 0
                else:
                    radians = nbmath.normalizeAngle(math.atan2(yDir, xDir))
                    requestedSpeed = 50

            botSocket.sendMessage({
                "type": "setDirectionRequest",
                "requestedDirection": radians
            })
            botSocket.sendMessage({
                "type": "setSpeedRequest",
                "requestedSpeed": requestedSpeed
            })

            # wait until shell explodes before shooting again, or if player clicks again
            if (mouseDown):
                if (waiting):
                    if firing_distance - (
                            time.perf_counter() - shell_time
                    ) / srvConf['stepSec'] * srvConf['shellSpeed'] <= 0:
                        waiting = False

                if (not waiting):
                    waiting = True
                    shoot()
        except nbipc.NetBotSocketException as e:
            #Consider this a warning here. It may simply be that a request returned
            #an Error reply because our health == 0 since we last checked. We can
            #continue until the next game starts.
            log(str(e), "WARNING")
            continue