1
1
# Submitted by Marius Becker
2
+ # Updated by Amaras
3
+ # Updated again by Jonathan Dönszelmann
2
4
3
- import sys
4
5
from random import shuffle
5
6
from copy import copy
6
- from string import ascii_uppercase
7
+ from string import ascii_uppercase , ascii_lowercase
7
8
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
14
9
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
19
13
20
14
# 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 ] ]
23
17
24
18
# Set everyone's preferences
25
19
for man in men :
@@ -31,101 +25,58 @@ def main():
31
25
shuffle (woman .preference )
32
26
33
27
# Run the algorithm
34
- resolve (men , women )
28
+ stable_marriage (men , women )
35
29
36
30
# Print preferences and the result
31
+ print ('Preferences of the men:' )
37
32
for man in men :
38
- print ('{}: {}' .format (man .name , ', ' .join ([ p .name for p in man .preference ])))
33
+ print (man )
34
+
35
+ print ()
39
36
37
+ print ('Preferences of the women:' )
40
38
for woman in women :
41
- print ('{}: {}' . format ( woman . name , ', ' . join ([ p . name for p in woman . preference ])) )
39
+ print (woman )
42
40
43
- print ('' )
41
+ print ('\n ' )
44
42
43
+ print ('The algorithm gave this solution:' )
45
44
for man in men :
46
- print ('{ } + {}' . format ( man .name , man . partner .name ) )
45
+ print (f' { man . name } + { man .partner .name } ' )
47
46
48
- def resolve (men , women ):
47
+
48
+ def stable_marriage (men , women ):
49
49
"""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
67
50
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
74
65
66
+ person .partner = partner
67
+ partner .partner = person
68
+
69
+
70
+ class Person :
75
71
def __init__ (self , name ):
76
72
self .name = name
77
73
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
+
129
80
130
81
if __name__ == '__main__' :
131
82
main ()
0 commit comments