So, there is this king-of-the-hill challenge going on at PPCG SE to which I submitted my participation. I won't change it further in terms of behaviour, so I wanted to know what you think of the code.The challengeIt is very well described in the original post, I'll just summarize the key ideas here.SetupA pile of \$C\$ unflipped coins at the center of the table;\$N\$ players around the table with, each, \$F_i\$ flipped coins and \$U_i\$ unflipped coins (\$i \in [0;N[\$)Input of the programSingle argument formated following:$$R;I;C;P_i\_S_i\_F_i\_U_i;P_i\_S_i\_F_i\_U_i;\ldots$$Where \$R\$ is the current round, \$I\$ is the id of our player, \$P_i\$ is the id of the player being described by the \$P\_S\_F\_U\$ data and \$S_i\$ is its score.Expected outputA 3-character string, nothing else, representing the actions of our player for this turn. The actions can be:N: Do Nothing1: Take 1 coin from the central pile [Effects: +1 local unflipped / -1 point / -1 global unflipped]2: Take 2 coins from the central pile [Effects: +2 local unflipped / -2 points / -2 global unflipped]3: Take 3 coins from the central pile [Effects: +3 local unflipped / -3 points / -3 global unflipped]A: Put back 1 coin from your pile [Effects: -1 local unflipped / +1 point / +1 global unflipped]B: Put back 2 coins from your pile [Effects: -2 local unflipped / +2 points / +2 global unflipped]C: Put back 3 coins from your pile [Effects: -3 local unflipped / +3 points / +3 global unflipped]X: Remove 1 coin from your pile [Effects: -1 local unflipped / 0 point]Y: Remove 2 coins from your pile [Effects: -2 local unflipped / 0 point]Z: Remove 3 coins from your pile [Effects: -3 local unflipped / 0 point]R: Rotate coins to previous player [Effects: -1 point per unflipped received, +2 points per flipped received / applies to all players]T: Rotate coins to next player [Effects: -1 point per unflipped received, +2 points per flipped received / applies to all players]F: Flip 1 coin [Effects: -1 local unflipped / +1 local flipped / +2 point]U: Unflip 1 coin [Effects: +1 local unflipped / -1 local flipped / -2 point] The codeThe submission tries every one of the 2744 possible move and output the (first) one with the maximum amount of points gained.import sysimport itertoolsfrom copy import deepcopyMOVES_REQUIRED = 3FLIPPED = 0UNFLIPPED = 1def filter_neighbors(neighbors, me, size):    limit = size - MOVES_REQUIRED    for data in neighbors:        i, _, flipped, unflipped = map(int, data.split('_'))        if MOVES_REQUIRED < (me - i) % size < limit:            continue  # Skip neighbors that are too far away        yield i, [flipped, unflipped]class Player:    def __init__(self, raw_data):        _, me, coins, *data = raw_data.split(';')        self.num_players = len(data)        self._me = int(me)        self._coins = int(coins)        self._state = dict(filter_neighbors(data, self._me, self.num_players))    def reset(self):        self.me = self._me        self.coins = self._coins        self.state = deepcopy(self._state)        self.my_state = self.state[self.me]    def invalid_move(self, move):        if move in 'NRT':            return False        if move in '123'[:self.coins]:            return False        flipped, unflipped = self.my_state        if flipped and move == 'U':            return False        if unflipped and move == 'F':            return False        if move in 'AXBYCZ'[:2 * unflipped]:            return False        return True    def N(self):        return 0    def one(self):        self.coins -= 1        self.my_state[UNFLIPPED] += 1        return -1    def two(self):        self.coins -= 2        self.my_state[UNFLIPPED] += 2        return -2    def three(self):        self.coins -= 3        self.my_state[UNFLIPPED] += 3        return -3    def A(self):        self.coins += 1        self.my_state[UNFLIPPED] -= 1        return 1    def B(self):        self.coins += 2        self.my_state[UNFLIPPED] -= 2        return 2    def C(self):        self.coins += 3        self.my_state[UNFLIPPED] -= 3        return 3    def X(self):        self.my_state[UNFLIPPED] -= 1        return 0    def Y(self):        self.my_state[UNFLIPPED] -= 2        return 0    def Z(self):        self.my_state[UNFLIPPED] -= 3        return 0    def R(self):        self.me = (self.me + 1) % self.num_players        flipped, unflipped = self.my_state = self.state[self.me]        return 2 * flipped - unflipped    def T(self):        self.me = (self.me - 1) % self.num_players        flipped, unflipped = self.my_state = self.state[self.me]        return 2 * flipped - unflipped    def F(self):        self.my_state[FLIPPED] += 1        self.my_state[UNFLIPPED] -= 1        return 2    def U(self):        self.my_state[FLIPPED] -= 1        self.my_state[UNFLIPPED] += 1        return -2setattr(Player, '1', Player.one)setattr(Player, '2', Player.two)setattr(Player, '3', Player.three)def scenarii(player):    for tries in itertools.product('N123ABCXYZRTFU', repeat=MOVES_REQUIRED):        player.reset()        points = 0        for try_ in tries:            if player.invalid_move(try_):                break            points += getattr(player, try_)()        else:            yield points, ''.join(tries)if __name__ == '__main__':    player = Player(sys.argv[1])    print(max(scenarii(player))[1])What do you think?
Maximize points won by flipping coins
python;python 3.x