[Tutor] Creating lists with 3 (later4) items occuring only once
Martin A. Brown
martin at linux-ip.net
Tue Sep 22 03:10:04 CEST 2015
Marcus,
I have more questions for you, as well as a possible solution
(though it's a bit more verbose than I would have liked to offer).
Question:
Problem A: Are you looking to identify the complete set of
possible options for constructing the triples of pairs?
Problem B: Are you looking only to construct one set that
satisfies the problem? [see my lousy solution]
You may observe that the question I ask is quite similar to the
question asked by Francesco [0].
If you are asking about the complete set of possible options
(Problem A), then I submit to you that you are asking a mathematical
question, not a Python question. If that's the case, perhaps you
should look further into the Steiner system and/or ask again on the
list.
If you are asking about finding an individual solution satisfying
the constraints, I submit to you that either my approach or
Francesco's approach could work for you. If that's the case, then
using random.sample may offer you some help. See my sample,
below--it should work on Python 2.x or Python 3.x.
Comments:
* There are rules in your system about when a player can play
again. The rules were not fully clear to me, so I allowed
players to be selecteda second time, if there were no more
players who had not already been chosen.
* This program produces only one possible scenario for 7
rounds of 3 distinct, simultaneously played 2-player games.
No player can play twice in the same round. (Simple arithmetic
determines the minimum number of players.)
If your question is Problem A, then I wonder if you know anybody who
knows combinatorics? I do not.
-Martin
[0] https://mail.python.org/pipermail/tutor/2015-September/106820.html
#! /usr/bin/python
from __future__ import print_function
import sys
import string
import random
import logging
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
logger = logging.getLogger()
class NotEnoughPlayers(Exception):
pass
def choose_game_participants(players, pcount=2):
'''returns a tuple of players for a single game
'''
if len(players) < pcount:
raise NotEnoughPlayers("not enough players, need %d, have only %d: %r" %
(pcount, len(players), players))
game = tuple(sorted(random.sample(players, pcount)))
return game
def choose_match_games(players, pcount=2, gcount=3):
'''returns a list of games where no player is duplicated
'''
mcount = pcount * gcount
if len(players) < mcount:
raise NotEnoughPlayers("not enough players, need %d, have only %d: %r" %
(mcount, len(players), players))
eligible_players = random.sample(players, mcount)
match = list()
while eligible_players:
m = choose_game_participants(eligible_players, pcount)
for x in m:
eligible_players.remove(x)
match.append(m)
match.sort() # optional
return match
def generate_rounds(players, pcount, gcount, rcount):
games = set()
matches = list()
mcount = pcount * gcount
eligible_players = list(players)
if mcount > len(eligible_players):
raise NotEnoughPlayers("not enough players (%d) to guarantee %d %d-player games per match" %
(len(eligible_players), gcount, pcount))
r = 1
while r <= rcount:
try:
proposed_match = choose_match_games(eligible_players, pcount, gcount)
except NotEnoughPlayers:
logger.info("adding %d additional players in round %d to meet minimum pool requirements",
mcount, r)
how_many = mcount - len(eligible_players)
eligible_players.extend(random.sample(players, how_many))
continue
already_played = games.intersection(set(proposed_match))
if already_played:
logger.info("discarding %d %r because %r have already played",
r, proposed_match, list(already_played))
continue
else:
games.update(proposed_match)
matches.append(proposed_match)
logger.info('Proposed match %r', proposed_match)
for game in proposed_match:
for player in game:
eligible_players.remove(player)
r = r + 1
return matches
def log_match_info(matches, detail=False):
for mnum, match in enumerate(matches, 1):
logger.info("match summary %d: %r", mnum, match)
for gnum, game in enumerate(match, 1):
if not detail:
continue
logger.info("match detail %d, game %d: players %r",
mnum, gnum, game)
def log_match_summary(matches):
log_match_info(matches, detail=False)
def log_match_detail(matches):
log_match_info(matches, detail=True)
if __name__ == '__main__':
players = list(string.ascii_uppercase)
random.shuffle(players)
# players = set('ABCDEFGHIJ')
pcount = 2 # players per game
gcount = 3 # games per match
rcount = 7 # rounds (of matches)
matches = generate_rounds(players, pcount, gcount, rcount)
log_match_detail(matches)
# -- end of file
--
Martin A. Brown
http://linux-ip.net/
More information about the Tutor
mailing list