CodeFights: Frisbees
builtin

you can use some parts of the standard library:


math.hypot for the distance function
collections.defaultdict for the frisbees_held
itertools.combinations for generating the combinations in the distance matrix


imports:

from itertools import combinations, islice
from collections import namedtuple, defaultdict
from math import hypot


players

you can use a class, or even a namedtuple to represent a player, to simplify the building of the distance matrix

Player = namedtuple('Player', 'name x y range')
players = [[152, 213, 276], [274, 259, 151], [40, 57, 130], [203, 87, 189], [43, 182, 163]]
players = [Player(i, x, y, range_) for i, (x, y, range_) in enumerate(players)]



[Player(name=0, x=152, y=213, range=276),
 Player(name=1, x=274, y=259, range=151),
 Player(name=2, x=40, y=57, range=130),
 Player(name=3, x=203, y=87, range=189),
 Player(name=4, x=43, y=182, range=163)]



distance matrix

you calculate the distance between the players a few times, you can reduce that by doing something like this:

def distance_generator(players):
    for p1, p2 in combinations(players, 2):
        dist = hypot((p1.x - p2.x), (p1.y - p2.y))
        if dist &lt; p1.range:
            yield p1, p2, dist
        if dist &lt; p2.range:
            yield p2, p1, dist


here a dict of dicts might be a more appropriate data structure than a list of lists

def build_distance_matrix(players): 
    distance_matrix = defaultdict(dict)
    for p1, p2, dist in distance_generator(players):
        distance_matrix[p1.name][p2.name] = dist
    return dict(distance_matrix)



{
    0: 
    {
        1: 130.38404810405297,
        2: 192.04166214652486,
        3: 135.9301291105103,
        4: 113.3225485064645,
    },
    1: {0: 130.38404810405297},
    3: {
        0: 135.9301291105103,
        1: 186.07794065928394,
        2: 165.73774464496614,
        4: 186.07794065928394,
    },
     4: {0: 113.3225485064645, 2: 125.03599481749245},
     2: {4: 125.03599481749245},
}



throwing

you can model a game as an endless series of people throwing the frisbee to eachother. The min(...) you use is the correct way to do this, but can be formatted clearer

def game(distance_matrix, start_player):
    frisbees_held = defaultdict(int)
    target = start_player
    while True:
        frisbees_held[target] += 1
        targets = distance_matrix[target]
        yield target
        target = min(
            targets,
            key=lambda x: (
                frisbees_held[x], # number times held
                -targets[x], # furthest
                x # lowest index
            ) 
        )


final selection

then you can use the nth itertools recipe

def nth(iterable, n, default=None):
    "Returns the nth item or a default value"
    return next(islice(iterable, n, None), default)

def frisbees(friends, numberOfPasses, startingPlayer):
    players = [Player(i, x, y, range_) for i, (x, y, range_) in enumerate(friends)]
    distance_matrix = build_distance_matrix(players)
    g = game(distance_matrix, startingPlayer)
    return nth(g, numberOfPasses)