def get_n_policies(self, n=5): # for now just get n random policies policies = list(self.get_policies()) if not policies: return [] random.shuffle(policies) return policies[:n]
def shuffle(self): if not hasattr(self, "shuffle_attributes"): return for attributes in sorted(self.shuffle_attributes): if len(attributes) == 1: attribute = attributes[0] value = sorted(getattr(self, attribute)) random.shuffle(value) setattr(self, attribute, value) continue values = [getattr(self, attribute) for attribute in attributes] random.shuffle(values) for attribute, value in zip(attributes, values): setattr(self, attribute, value)
def force_role(self, role_to_force: Role): # Make sure a role is to be played, force it otherwise # Warning: This can replace previously forced role if role_to_force in self.available_roles: return else: idx = 0 # Let's replace the first role in self.available_roles if role_to_force in self.extra_roles: # Get it by swapping with self.extra_roles's swap_idx = self.extra_roles.index(role_to_force) self.available_roles[idx], self.extra_roles[swap_idx] = ( self.extra_roles[swap_idx], self.available_roles[idx], ) else: # Or just force it manually self.available_roles[idx] = role_to_force return random.shuffle(self.available_roles), random.shuffle(self.extra_roles)
def groupshuffle(cls): if (not hasattr(cls, "groupshuffle_enabled") or not cls.groupshuffle_enabled): return shuffled = range(cls.numgroups) random.shuffle(shuffled) swapdict = {} for a, b in zip(range(cls.numgroups), shuffled): a = cls.getgroup(a) b = cls.getgroup(b) for a1, b1 in zip(a, b): swapdict[a1] = (b1.groupindex, b1.index, b1.pointer) for o in cls.every: groupindex, index, pointer = swapdict[o] o.groupindex = groupindex o.index = index o.pointer = pointer
def intershuffle(cls): if not hasattr(cls, "intershuffle_attributes"): return hard_shuffle = False if (len(set([o.rank for o in cls.every])) == 1 or all([o.rank == o.index for o in cls.every])): hard_shuffle = True for attributes in cls.intershuffle_attributes: candidates = [o for o in cls.every if o.rank >= 0 and o.intershuffle_valid] if hard_shuffle: shuffled = list(candidates) random.shuffle(shuffled) else: candidates = sorted(candidates, key=lambda c: c.rank) shuffled = list(candidates) max_index = len(candidates)-1 done = set([]) for i, o in enumerate(candidates): new_index = i if shuffled[i] in done: continue while random.choice([True, False]): new_index += min(1, (max_index / 10.0)) new_index = int(round(new_index)) new_index = min(new_index, max_index) a, b = shuffled[i], shuffled[new_index] done.add(a) shuffled[i] = b shuffled[new_index] = a if isinstance(attributes, str) or isinstance(attributes, unicode): attributes = [attributes] for attribute in attributes: swaps = [] for a, b in zip(candidates, shuffled): aval, bval = getattr(a, attribute), getattr(b, attribute) swaps.append(bval) for a, bval in zip(candidates, swaps): setattr(a, attribute, bval)
async def get_response(self, ctx, question): entries = [question["correct_answer"]] + question["incorrect_answers"] entries = random.shuffle(entries) answer = await self.bot.paginator.Choose( entries=entries, title=question["question"], footer=(f"Difficulty: {question['difficulty']} | Category:" f" {question['category']}"), timeout=15, ).paginate(ctx) return answer == question["correct_answer"]
async def send_cast(self): cast = copy.copy(self.players) cast = random.shuffle(cast) cast = list(chunks(cast, 2)) self.cast = cast text = _("Team") paginator = commands.Paginator(prefix="", suffix="") paginator.add_line(_("**The cast**")) for i, team in enumerate(cast, start=1): if len(team) == 2: paginator.add_line( f"{text} #{i}: {team[0].mention} {team[1].mention}") else: paginator.add_line(f"{text} #{i}: {team[0].mention}") for page in paginator.pages: await self.ctx.send(page)
def prepare_deck(self): self.deck = [] for colour in ["hearts", "diamonds", "spades", "clubs"]: for value in range(2, 15): # 11 = Jack, 12 = Queen, 13 = King, 14 = Ace if value == 11: card = "j" elif value == 12: card = "q" elif value == 13: card = "k" elif value == 14: card = "a" else: card = str(value) self.deck.append((value, colour, self.cards[f"{card}{colour}"])) self.deck = self.deck * 6 # BlackJack is played with 6 sets of cards self.deck = random.shuffle(self.deck)
def get_roles(number_of_players: int) -> List[Role]: number_of_players += 2 # Thief is in play if number_of_players > len(ROLES_FOR_PLAYERS): roles = ROLES_FOR_PLAYERS # Fill up with villagers and wolves as all special roles are taken for i in range(number_of_players - len(roles)): if i % 2 == 0: roles.append(Role.WEREWOLF) else: roles.append(Role.VILLAGER) else: roles = ROLES_FOR_PLAYERS[:number_of_players] if sum(1 for role in roles if role == Role.SISTER) == 1: for idx, role in enumerate(roles): if role == Role.SISTER: roles[idx] = Role.VILLAGER if sum(1 for role in roles if role == Role.BROTHER) < 3: for idx, role in enumerate(roles): if role == Role.BROTHER: roles[idx] = Role.VILLAGER roles = random.shuffle(roles) return roles
user=u.mention)) toremove = 2**math.floor(math.log2(len(participants))) if toremove != len(participants): await ctx.send( _("There are **{num}** entries, due to the fact we need a playable" " tournament, the last **{removed}** have been removed."). format(num=len(participants), removed=len(participants) - toremove)) participants = participants[:-(len(participants) - toremove)] else: await ctx.send( _("Tournament started with **{num}** entries.").format( num=toremove)) text = _("vs") while len(participants) > 1: participants = random.shuffle(participants) matches = list(chunks(participants, 2)) for match in matches: await ctx.send(f"{match[0].mention} {text} {match[1].mention}") await asyncio.sleep(2) async with self.bot.pool.acquire() as conn: val1 = sum(await self.bot.get_damage_armor_for( match[0], conn=conn)) + random.randint(1, 7) val2 = sum(await self.bot.get_damage_armor_for( match[1], conn=conn)) + random.randint(1, 7) if val1 > val2: winner = match[0] looser = match[1] elif val2 > val1: winner = match[1]
async def werewolf( self, ctx, mode: Optional[WerewolfMode] = "Classic", speed: str.title = "Normal", min_players: IntGreaterThan(1) = None, ): _(""" `[mode]` - The mode to play, see below for available options. (optional and defaults to Classic) `[speed]` - The game speed to play, see below available options. (optional and defaults to Normal) `[min_players]` - The minimum players needed to play. (optional and defaults depending on the game mode: Classic: 5, Imbalanced: 5, Huntergame: 8, Villagergame: 5, Valentines: 8, IdleRPG: 5) Starts a game of Werewolf. Find the werewolves, before they find you! Your goal to win is indicated on the role you have. **Game modes:** `Classic` (default), `Imbalanced`, `Huntergame`, `Villagergame`, `Valentines`, `IdleRPG`. Use `{prefix}ww modes` for detailed info. **Game speeds** (in seconds): `Normal`: 60 (default), `Extended`: 90, `Fast`: 45, `Blitz`: 30. Use `{prefix}ww speeds` for detailed info. **Aliases:** `ww` **Examples:** `{prefix}ww Blitz` for Classic mode on Blitz speed `{prefix}ww Imbalanced` for Imbalanced mode on Normal speed `{prefix}ww Valentines Extended` for Valentines mode on Extended speed `{prefix}ww Huntergame Fast` for Huntergame mode on Fast speed """) # TODO: # Bizarro: Roles are flipped. # Random: Roles are reassigned randomly every night. # Zombie (Classic-based, another team) - There's a chance that a random player will be randomly resurrected as Zombie and they can devour any villagers or werewolves with the other zombies. if self.games.get(ctx.channel.id): return await ctx.send(_("There is already a game in here!")) game_modes = [ "Classic", "Imbalanced", "Huntergame", "Villagergame", "Valentines", "Idlerpg", ] if mode not in game_modes: return await ctx.send( _("Invalid game mode. Use `{prefix}help ww` to get help on this" " command.").format(prefix=ctx.prefix)) elif mode == "Idlerpg": mode = "IdleRPG" game_speeds = ["Normal", "Extended", "Fast", "Blitz"] if speed not in game_speeds: return await ctx.send( _("Invalid game speed. Use `{prefix}help ww` to get help on this" " command.").format(prefix=ctx.prefix)) minimum_players = { "Classic": 5, "Imbalanced": 5, "Huntergame": 8, "Villagergame": 5, "Valentines": 8, "IdleRPG": 5, } if not min_players: default_min_players = ( 5 # Get default of Classic mode if unexpected value happened ) min_players = minimum_players.get(mode, default_min_players) self.games[ctx.channel.id] = "forming" additional_text = _( "Use `{prefix}help ww` to get help on werewolf commands. Use `{prefix}ww" " roles` to view descriptions of game roles and their goals to win. Use" " `{prefix}ww modes` and `{prefix}ww speeds` to see info about available" " game modes and speeds.").format(prefix=ctx.prefix) mode_emojis = {"Huntergame": "🔫", "Valentines": "💕"} mode_emoji = mode_emojis.get(mode, "") if ctx.channel.id == self.bot.config.official_tournament_channel_id: # TODO: Determine threshold players when wolves can kill 2 villagers per night in mass-games id_ = await self.bot.start_joins() url = f"https://join.idlerpg.xyz/{id_}" text = _( "**{author} started a mass-game of Werewolf!**\n**{mode}** mode on" " **{speed}** speed. Go to {url} to join in the next 10 minutes." " **Minimum of {min_players} players are required.**") try: await ctx.send(embed=discord.Embed( title=_("Werewolf Mass-game!"), description=text.format( author=ctx.author.mention, mode=mode_emoji + mode, speed=speed, url=url, min_players=min_players, ), url=url, colour=self.bot.config.primary_colour, ).set_author( name=str(ctx.author), icon_url=ctx.author.avatar_url_as(size=64)).add_field( name=_("New to Werewolf?"), value=additional_text)) except discord.errors.Forbidden: del self.games[ctx.channel.id] return await ctx.send( _("An error happened during the Werewolf. Missing Permission:" " `Embed Links` . Please check the **Edit Channel >" " Permissions** and **Server Settings > Roles** then try again!" )) await asyncio.sleep(60 * 10) players = await self.bot.get_joins(id_) else: title = _("Werewolf game!") text = _( "**{author} started a game of Werewolf!**\n**{mode}** mode on" " **{speed}** speed. React with 🐺 to join the game! **Minimum of" " {min_players} players are required. Starting in 30 seconds.\n{num}" " joined**") players = [ctx.author] try: msg = await ctx.send(embed=discord.Embed( title=title, description=text.format( author=ctx.author.mention, mode=mode_emoji + mode, speed=speed, min_players=min_players, num=len(players), ), colour=self.bot.config.primary_colour, ).set_author( name=str(ctx.author), icon_url=ctx.author.avatar_url_as(size=64)).add_field( name=_("New to Werewolf?"), value=additional_text)) await msg.add_reaction("\U0001f43a") except discord.errors.Forbidden: del self.games[ctx.channel.id] return await ctx.send( _("An error happened during the Werewolf. Missing Permission:" " `Embed Links` . Please check the **Edit Channel >" " Permissions** and **Server Settings > Roles** then try again!" )) def check(reaction, user): return (user not in players and reaction.message.id == msg.id and reaction.emoji == "\U0001f43a" and not user.bot) while True: try: reaction, user = await self.bot.wait_for("reaction_add", check=check, timeout=30) except asyncio.TimeoutError: break players.append(user) await msg.edit(embed=discord.Embed( title=title, description=text.format( author=ctx.author.mention, mode=mode_emoji + mode, speed=speed, min_players=min_players, num=len(players), ), colour=self.bot.config.primary_colour, ).set_author( name=str(ctx.author), icon_url=ctx.author.avatar_url_as(size=64)).add_field( name=_("New to Werewolf?"), value=additional_text)) # Check for not included participants try: msg = await ctx.channel.fetch_message(msg.id) for reaction in msg.reactions: if reaction.emoji == "\U0001f43a": async for user in reaction.users(): if user != ctx.me and user not in players: players.append(user) break except discord.errors.NotFound: del self.games[ctx.channel.id] await ctx.send( _("An error happened during the Werewolf. Please try again!" )) return if len(players) < min_players: del self.games[ctx.channel.id] await self.bot.reset_cooldown(ctx) return await ctx.send( _("Not enough players joined... We didn't reach the minimum" " {min_players} players. 🙁").format(min_players=min_players)) players = random.shuffle(players) try: game = Game(ctx, players, mode, speed) self.games[ctx.channel.id] = game await game.run() except Exception as e: await ctx.send( _("An error happened during the Werewolf. Please try again!")) del self.games[ctx.channel.id] raise e try: del self.games[ctx.channel.id] except KeyError: # got stuck in between pass
async def werewolf( self, ctx, mode: WerewolfMode | None = "Classic", speed: str.title = "Normal", min_players: IntGreaterThan(1) = None, ): _(""" `[mode]` - The mode to play, see below for available options. (optional and defaults to Classic) `[speed]` - The game speed to play, see below available options. (optional and defaults to Normal) `[min_players]` - The minimum players needed to play. (optional and defaults depending on the game mode: Classic: 5, Imbalanced: 5, Huntergame: 8, Villagergame: 5, Valentines: 8, IdleRPG: 5) Starts a game of Werewolf. Find the werewolves, before they find you! Your goal to win is indicated on the role you have. **Game modes:** `Classic` (default), `Imbalanced`, `Huntergame`, `Villagergame`, `Valentines`, `IdleRPG`. Use `{prefix}ww modes` for detailed info. **Game speeds** (in seconds): `Normal`: 60 (default), `Extended`: 90, `Fast`: 45, `Blitz`: 30. Use `{prefix}ww speeds` for detailed info. **Aliases:** `ww` **Examples:** `{prefix}ww Blitz` for Classic mode on Blitz speed `{prefix}ww Imbalanced` for Imbalanced mode on Normal speed `{prefix}ww Valentines Extended` for Valentines mode on Extended speed `{prefix}ww Huntergame Fast` for Huntergame mode on Fast speed """) # TODO: # Bizarro: Roles are flipped. # Random: Roles are reassigned randomly every night. # Zombie (Classic-based, another team) - There's a chance that a random player will be randomly resurrected as Zombie and they can devour any villagers or werewolves with the other zombies. if self.games.get(ctx.channel.id): return await ctx.send(_("There is already a game in here!")) game_modes = [ "Classic", "Imbalanced", "Huntergame", "Villagergame", "Valentines", "Idlerpg", ] minimum_players = { "Classic": 5, "Imbalanced": 5, "Huntergame": 8, "Villagergame": 5, "Valentines": 8, "IdleRPG": 5, } game_speeds = ["Normal", "Extended", "Fast", "Blitz"] if mode not in game_modes: return await ctx.send( _("Invalid game mode. Use `{prefix}help ww` to get help on this" " command.").format(prefix=ctx.prefix)) elif mode == "Idlerpg": mode = "IdleRPG" if speed not in game_speeds: return await ctx.send( _("Invalid game speed. Use `{prefix}help ww` to get help on this" " command.").format(prefix=ctx.prefix)) if not min_players: # Get default of Classic mode if unexpected value happened min_players = minimum_players.get(mode, 5) self.games[ctx.channel.id] = "forming" additional_text = _( "Use `{prefix}help ww` to get help on werewolf commands. Use `{prefix}ww" " roles` to view descriptions of game roles and their goals to win. Use" " `{prefix}ww modes` and `{prefix}ww speeds` to see info about available" " game modes and speeds.").format(prefix=ctx.prefix) mode_emojis = {"Huntergame": "🔫", "Valentines": "💕"} mode_emoji = mode_emojis.get(mode, "") if (self.bot.config.game.official_tournament_channel_id and ctx.channel.id == self.bot.config.game.official_tournament_channel_id): # TODO: Determine threshold players when wolves can kill 2 villagers per night in mass-games view = JoinView( Button(style=ButtonStyle.primary, label=_("Join the Werewolf game!")), message=_("You joined the Werewolf game."), timeout=60 * 10, ) text = _( "**{author} started a mass-game of Werewolf!**\n**{mode}** mode on" " **{speed}** speed. You can join in the next 10 minutes." " **Minimum of {min_players} players are required.**") await ctx.send( embed=discord.Embed( title=_("Werewolf Mass-game!"), description=text.format( author=ctx.author.mention, mode=mode_emoji + mode, speed=speed, min_players=min_players, ), colour=self.bot.config.game.primary_colour, ).set_author(name=str(ctx.author), icon_url=ctx.author.display_avatar.url).add_field( name=_("New to Werewolf?"), value=additional_text), view=view, ) await asyncio.sleep(60 * 10) view.stop() players = list(view.joined) else: view = JoinView( Button(style=ButtonStyle.primary, label=_("Join the Werewolf game!")), message=_("You joined the Werewolf game."), timeout=120, ) view.joined.add(ctx.author) title = _("Werewolf game!") text = _( "**{author} started a game of Werewolf!**\n**{mode}** mode on" " **{speed}** speed. Minimum of" " **{min_players}** players are required. Starting in 2 minutes." ) try: await ctx.send( embed=discord.Embed( title=title, description=text.format( author=ctx.author.mention, mode=mode_emoji + mode, speed=speed, min_players=min_players, ), colour=self.bot.config.game.primary_colour, ).set_author( name=str(ctx.author), icon_url=ctx.author.display_avatar.url).add_field( name=_("New to Werewolf?"), value=additional_text), view=view, ) except discord.errors.Forbidden: del self.games[ctx.channel.id] return await ctx.send( _("An error happened during the Werewolf. Missing Permission:" " `Embed Links` . Please check the **Edit Channel >" " Permissions** and **Server Settings > Roles** then try again!" )) await asyncio.sleep(60 * 2) view.stop() players = list(view.joined) if len(players) < min_players: del self.games[ctx.channel.id] await self.bot.reset_cooldown(ctx) return await ctx.send( _("Not enough players joined... We didn't reach the minimum" " {min_players} players. �").format( min_players=min_players)) players = random.shuffle(players) try: game = Game(ctx, players, mode, speed) self.games[ctx.channel.id] = game await game.run() except Exception as e: await ctx.send( _("An error happened during the Werewolf. Please try again!")) del self.games[ctx.channel.id] raise e try: del self.games[ctx.channel.id] except KeyError: # got stuck in between pass
async def draw( self, ctx, enemy: MemberWithCharacter = None, money: IntGreaterThan(-1) = 0 ): _( """`[enemy]` - A user who has a profile; defaults to None `[money]` - The bet money. A whole number that can be 0 or greater; defaults to 0 Draws a random card from the 52 French playing cards. Playing Draw with someone for money is also available if the enemy is mentioned. The player with higher value of the drawn cards will win the bet money. This command has no effect on your balance if done with no enemy mentioned. (This command has a cooldown of 15 seconds.)""" ) if not enemy: return await ctx.send( content=f"{ctx.author.mention} you drew:", file=discord.File(f"assets/cards/{random.choice(self.cards)}"), ) else: if enemy == ctx.author: return await ctx.send(_("Please choose someone else.")) if enemy == ctx.me: return await ctx.send(_("You should choose a human to play with you.")) if ctx.character_data["money"] < money: return await ctx.send(_("You are too poor.")) await self.bot.pool.execute( 'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;', money, ctx.author.id, ) async def money_back(): await self.bot.pool.execute( 'UPDATE profile SET "money"="money"+$1 WHERE "user"=$2;', money, ctx.author.id, ) return await self.bot.reset_cooldown(ctx) try: if not await ctx.confirm( _( "{author} challenges {enemy} to a game of Draw for" " **${money}**. Do you accept?" ).format( author=ctx.author.mention, enemy=enemy.mention, money=money, ), user=enemy, timeout=15, ): await money_back() return await ctx.send( _( "They declined. They don't want to play a game of Draw with" " you {author}." ).format(author=ctx.author.mention) ) except self.bot.paginator.NoChoice: await money_back() return await ctx.send( _( "They didn't choose anything. It seems they're not interested" " to play a game of Draw with you {author}." ).format(author=ctx.author.mention) ) if not await has_money(self.bot, enemy.id, money): await money_back() return await ctx.send( _("{enemy} You don't have enough money to play.").format( enemy=enemy.mention ) ) await self.bot.pool.execute( 'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2;', money, enemy.id, ) cards = self.cards.copy() cards = random.shuffle(cards) rank_values = { "jack": 11, "queen": 12, "king": 13, "ace": 14, } while True: try: author_card = cards.pop() enemy_card = cards.pop() except IndexError: return await ctx.send( _( "Cards ran out. This is a very rare issue that could mean" " image files for cards have become insufficient. Please" " report this issue to the bot developers." ) ) rank1 = author_card[: author_card.find("_")] rank2 = enemy_card[: enemy_card.find("_")] drawn_values = [ int(rank_values.get(rank1, rank1)), int(rank_values.get(rank2, rank2)), ] async with self.bot.pool.acquire() as conn: if drawn_values[0] == drawn_values[1]: await conn.execute( 'UPDATE profile SET "money"="money"+$1 WHERE "user"=$2 OR' ' "user"=$3;', money, ctx.author.id, enemy.id, ) text = _("Nobody won. {author} and {enemy} tied.").format( author=ctx.author.mention, enemy=enemy.mention, ) else: players = [ctx.author, enemy] winner = players[drawn_values.index(max(drawn_values))] loser = players[players.index(winner) - 1] await conn.execute( 'UPDATE profile SET "money"="money"+$1 WHERE "user"=$2;', money * 2, winner.id, ) await self.bot.log_transaction( ctx, from_=loser.id, to=winner.id, subject="gambling", data={"Amount": money}, conn=conn, ) text = _( "{winner} won the Draw vs {loser}! Congratulations!" ).format(winner=winner.mention, loser=loser.mention) await ctx.send( content=( _("{author}, while playing against {enemy}, you drew:").format( author=ctx.author.mention, enemy=enemy.mention ) ), file=discord.File(f"assets/cards/{author_card}"), ) await ctx.send( content=( _("{enemy}, while playing against {author}, you drew:").format( enemy=enemy.mention, author=ctx.author.mention ) ), file=discord.File(f"assets/cards/{enemy_card}"), ) await ctx.send(text) if drawn_values[0] != drawn_values[1]: break else: msg = await ctx.send( content=f"{ctx.author.mention}, {enemy.mention}", embed=discord.Embed( title=_("Break the tie?"), description=_( "{author}, {enemy} You tied. Do you want to break the" " tie by playing again for **${money}**?" ).format( author=ctx.author.mention, enemy=enemy.mention, money=money, ), colour=discord.Colour.blurple(), ), ) emoji_no = "\U0000274e" emoji_yes = "\U00002705" emojis = (emoji_no, emoji_yes) for emoji in emojis: await msg.add_reaction(emoji) def check(r, u): return ( str(r.emoji) in emojis and r.message.id == msg.id and u in [ctx.author, enemy] and not u.bot ) async def cleanup() -> None: with suppress(discord.HTTPException): await msg.delete() accept_redraws = {} while len(accept_redraws) < 2: try: reaction, user = await self.bot.wait_for( "reaction_add", timeout=15, check=check ) except asyncio.TimeoutError: await cleanup() return await ctx.send( _("One of you or both didn't react on time.") ) else: if not (accept := bool(emojis.index(str(reaction.emoji)))): await cleanup() return await ctx.send( _("{user} declined to break the tie.").format( user=user.mention ) ) if user.id not in accept_redraws: accept_redraws[user.id] = accept await cleanup() if not await has_money(self.bot, ctx.author.id, money): return await ctx.send( _("{author} You don't have enough money to play.").format( author=ctx.author.mention ) ) if not await has_money(self.bot, enemy.id, money): return await ctx.send( _("{enemy} You don't have enough money to play.").format( enemy=enemy.mention ) ) await self.bot.pool.execute( 'UPDATE profile SET "money"="money"-$1 WHERE "user"=$2 OR' ' "user"=$3;', money, ctx.author.id, enemy.id, )
def generate(self, pos, good_enough=None, tries_limit=None, subgroup=None, basis=None): """Generate the parameters by finding good polynomials and building the parameters according to Proposition 8 & Remark 5 of [GW15]. @pos - the reconstruction pos @good_enough - amount of subfield elements sent which is good enough for us. if unset - the information theoretic best is taken (which might be impossible) @tries_limit - amount of polynomial sets to try. If unset - number of tries is unlimited @subgroup - amount of points to randomly checks before calculating the bandwidth of the scheme @basis - optional specific basis of gf over subfield to use """ pts = [p for p in self._pts] if pos not in pts: pts.append(pos) n = len(pts) t = self._t ext = self._gf.get_extension() # Set good enough to the lower bound of information needed - at least t parties, at least one element (in the big field) if good_enough is None: good_enough = -1 good_enough = max(good_enough, t, ext) if tries_limit is None: tries_limit = -1 # Set subgroup size for testing bandwidth # Only if bandwidth on subgroup seems to be better than current bandwidth we continue if subgroup is None: subgroup_fraction, subgroup_min = Config.GW_PARAMS_SUBGROUP_SIZE subgroup = int(ceil(n / subgroup_fraction)) subgroup = max(subgroup, subgroup_min) subgroup = min(n - 1, subgroup) subgroup_factor = float(subgroup) / n # Choose our polynomials so their evaluation in @pos will be some predefined base # We don't care about this degree of freedom - as it only changes our polynomial by a multiplicative scalar factor if basis is not None: assert len(basis) == ext, "Invalid size of basis supplied" assert self._linear_independant(basis), "Invalid basis supplied" else: # Choose the monomial basis as default subf = self._gf.get_subfield() gf_x = self._gf([subf.zero(), subf.one()]) basis = [x for x in powers(gf_x, ext)] pol_deg = n - t - 2 best_bandwidth = (n * ext) + 1 # <- More than the worst case bandwidth best_subgroup_bandwidth = int(ceil(subgroup_factor * best_bandwidth)) shuffled_pts = [p for p in pts] best_pols = None done = False try_i = 0 try: while not done and try_i != tries_limit: try_i += 1 # Choose a random polynomials with a sample of the points as roots, # while still making sure the evaluation in `pos` will yield the `basis` pols = [] for b in basis: roots = random.sample( pts, pol_deg + 1) # Over sample by 1 in case @pos gets in try: roots.remove(pos) except ValueError: roots.pop(-1) # Remove someone else (arbitrary) pol = LinearFactors(self._gf, roots, constraint=(pos, b)) pols.append(pol) # Sum the degree of the vector spaces spanned by {p(pt) | p in pols} for each pt (except pos) # First start with `subgroup` random points and see if random.shuffle(shuffled_pts) pts_iter = iter(shuffled_pts) bandwidth = 0 for i in xrange(subgroup): pt = pts_iter.next() if pt == pos: pt = pts_iter.next() bandwidth += self._degree(pol(pt) for pol in pols) if bandwidth > best_subgroup_bandwidth: continue #else: bandwidth += sum( self._degree(pol(pt) for pol in pols) for pt in pts_iter if pt != pos) if bandwidth < best_bandwidth: best_pols = pols best_bandwidth = bandwidth best_subgroup_bandwidth = int( ceil(subgroup_factor * best_bandwidth)) log.info("Found scheme with %d bandwidth (%d%%)", best_bandwidth, int(ceil((100.0 * best_bandwidth) / (ext * n)))) if bandwidth <= good_enough: done = True except KeyboardInterrupt: if best_pols is None: raise # Else - continue normally basis_elements = map( lambda pol: -pol(pos), best_pols ) #Notice: Negation added for correct result (mistake in [GW15] ?) dual = self._dual_basis(basis_elements) mus, mus_basis = self._calc_mus(pos, pts, best_pols) return dual, mus, mus_basis, best_bandwidth