Skip to content

Commit b977f2e

Browse files
committed
Iproved stable mariage further
1 parent 3204369 commit b977f2e

File tree

1 file changed

+45
-94
lines changed

1 file changed

+45
-94
lines changed
Lines changed: 45 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,19 @@
11
# Submitted by Marius Becker
2+
# Updated by Amaras
3+
# Updated again by Jonathan Dönszelmann
24

3-
import sys
45
from random import shuffle
56
from copy import copy
6-
from string import ascii_uppercase
7+
from string import ascii_uppercase, ascii_lowercase
78

8-
def main():
9-
# Set this to however many men and women you want
10-
if len(sys.argv) > 1:
11-
num_pairs = int(sys.argv[1])
12-
else:
13-
num_pairs = 5
149

15-
# There are only 26 possible names
16-
if num_pairs > 13:
17-
print('You can\' have more than 13 pairs.')
18-
return
10+
def main():
11+
# Set this to however many men and women you want, up to 26
12+
num_pairs = 5
1913

2014
# Create all Person objects
21-
men = [ Person(name) for name in ascii_uppercase[0:num_pairs] ]
22-
women = [ Person(name) for name in ascii_uppercase[num_pairs:num_pairs*2] ]
15+
men = [Person(name) for name in ascii_uppercase[:num_pairs]]
16+
women = [Person(name) for name in ascii_lowercase[:num_pairs]]
2317

2418
# Set everyone's preferences
2519
for man in men:
@@ -31,101 +25,58 @@ def main():
3125
shuffle(woman.preference)
3226

3327
# Run the algorithm
34-
resolve(men, women)
28+
stable_marriage(men, women)
3529

3630
# Print preferences and the result
31+
print('Preferences of the men:')
3732
for man in men:
38-
print('{}: {}'.format(man.name, ', '.join([ p.name for p in man.preference ])))
33+
print(man)
34+
35+
print()
3936

37+
print('Preferences of the women:')
4038
for woman in women:
41-
print('{}: {}'.format(woman.name, ', '.join([ p.name for p in woman.preference ])))
39+
print(woman)
4240

43-
print('')
41+
print('\n')
4442

43+
print('The algorithm gave this solution:')
4544
for man in men:
46-
print('{} + {}'.format(man.name, man.partner.name))
45+
print(f'{man.name} + {man.partner.name}')
4746

48-
def resolve(men, women):
47+
48+
def stable_marriage(men, women):
4949
"""Finds pairs with stable marriages"""
50-
cont = True
51-
while cont:
52-
# Let every man without a partner propose to a woman
53-
for man in men:
54-
if not man.has_partner():
55-
man.propose_to_next()
56-
57-
# Let the women pick their favorites
58-
for woman in women:
59-
woman.pick_preferred()
60-
61-
# Continue only when someone is still left without a partner
62-
cont = False
63-
for man in men:
64-
if not man.has_partner():
65-
cont = True
66-
break
6750

68-
class Person:
69-
name = None
70-
preference = None
71-
pref_index = 0
72-
candidates = None
73-
partner = None
51+
people = [*men, *women]
52+
53+
for person in people:
54+
if person.partner is None:
55+
# find someone in this person's preferences who
56+
# doesn't already have a partner.
57+
for possible_partner in person.preference:
58+
if possible_partner.partner is None:
59+
partner = possible_partner
60+
break
61+
else:
62+
raise Exception(f"Couldn't find a partner for {person}")
63+
else:
64+
partner = person.partner
7465

66+
person.partner = partner
67+
partner.partner = person
68+
69+
70+
class Person:
7571
def __init__(self, name):
7672
self.name = name
7773
self.preference = []
78-
self.candidates = []
79-
80-
def get_next_choice(self):
81-
"""Return the next person in the own preference list"""
82-
if self.pref_index >= len(self.preference):
83-
return None
84-
85-
return self.preference[self.pref_index]
86-
87-
def propose_to_next(self):
88-
"""Propose to the next person in the own preference list"""
89-
person = self.get_next_choice()
90-
person.candidates.append(self)
91-
self.pref_index += 1
92-
93-
def pick_preferred(self):
94-
"""Pick a new partner or stay with the old one if they are preferred"""
95-
# Iterate own preferences in order
96-
for person in self.preference:
97-
# Pick the first person that's either a new candidate or the
98-
# current partner
99-
if person == self.partner:
100-
break
101-
elif person in self.candidates:
102-
self.set_partner(person)
103-
break
104-
105-
# Rejected candidates don't get a second chance. :(
106-
self.candidates.clear()
107-
108-
def get_partner(self):
109-
"""Return the current partner"""
110-
return self.partner
111-
112-
def set_partner(self, person):
113-
"""Set a person as the new partner and run set_partner() on that person
114-
as well"""
115-
# Do nothing if nothing would change
116-
if person != self.partner:
117-
# Remove self from current partner
118-
if self.partner is not None:
119-
self.partner.partner = None
120-
121-
# Set own and the other person's partner
122-
self.partner = person
123-
if self.partner is not None:
124-
self.partner.partner = self
125-
126-
def has_partner(self):
127-
"""Determine whether this person currently has a partner or not"""
128-
return self.partner != None
74+
self.partner = None
75+
76+
# This allows the preferences to be printed more elegantly
77+
def __str__(self):
78+
return f'{self.name}: {", ".join(p.name for p in self.preference)}'
79+
12980

13081
if __name__ == '__main__':
13182
main()

0 commit comments

Comments
 (0)