Advertisement
sawczakl

Christmas Dinner

Feb 11th, 2024 (edited)
858
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.97 KB | Software | 0 0
  1. # This damn thing https://www.ahapuzzles.com/logic/logic-puzzles/christmas-dinner/
  2.  
  3. from __future__ import annotations
  4. import itertools
  5.  
  6. class Thing:
  7.     id: str
  8.  
  9.     food: Thing
  10.     resto: Thing
  11.     person: Thing
  12.     cost: Thing
  13.  
  14.     def __init__(self: Thing, id: str) -> None:
  15.         self.id = id
  16.  
  17.         self.resto = None
  18.         self.food = None
  19.         self.cost = None
  20.         self.person = None
  21.  
  22.     def __hash__(self: Thing) -> int:
  23.         return hash(str(self))
  24.    
  25.     def __repr__(self: Thing) -> str:
  26.         return f'{self.id}'
  27.    
  28.     def __eq__(self: Thing, other: Thing) -> bool:
  29.         return str(self) == str(other)
  30.    
  31.     def things(self: Thing) -> set[Thing]:
  32.         return {self.person, self.cost, self.food, self.resto}
  33.    
  34.     def add_resto(self: Thing, resto: Thing) -> bool:
  35.         self.resto = resto
  36.         resto.person = self
  37.  
  38.         return True
  39.    
  40.     def add_food(self: Thing, food: Thing) -> bool:
  41.         self.food = food
  42.         food.person = self
  43.  
  44.         food.resto = self.resto
  45.         self.resto.food = self.food
  46.  
  47.         return True
  48.    
  49.     def add_cost(self: Thing, cost: Thing) -> bool:
  50.         self.cost = cost
  51.         cost.person = self
  52.  
  53.         self.food.cost = cost
  54.         cost.food = self.food
  55.  
  56.         self.resto.cost = cost
  57.         cost.resto = self.resto
  58.  
  59.         return True
  60.  
  61.     @staticmethod
  62.     def is_pair(a: Thing, b: Thing) -> bool:
  63.         return any((
  64.             any(((t is b) and (t is not None)) for t in a.things()),
  65.             any(((t is a) and (t is not None)) for t in b.things())
  66.         ))
  67.  
  68. P_Leon = Thing('Leon')
  69. P_Yvette = Thing('Yvette')
  70. P_Isac = Thing('Isac')
  71. P_Eric = Thing('Eric')
  72. PS = {P_Isac, P_Eric, P_Leon, P_Yvette}
  73.  
  74. R_Greg = Thing('Greg\'s')
  75. R_Irene = Thing('Irene\'s')
  76. R_Charlie = Thing('Charlie\'s')
  77. R_Lyon = Thing('Lyon\'s')
  78. RS = {R_Greg, R_Irene, R_Charlie, R_Lyon}
  79.  
  80. F_Ham = Thing('Ham')
  81. F_Turkey = Thing('Turkey')
  82. F_Chicken = Thing('Chicken')
  83. F_Pork = Thing('Pork')
  84. FS = {F_Chicken, F_Ham, F_Pork, F_Turkey}
  85.  
  86. C_14 = Thing('14.99')
  87. C_15 = Thing('15.99')
  88. C_16 = Thing('16.99')
  89. C_17 = Thing('17.99')
  90. CS = {C_14, C_15, C_16, C_17}
  91.  
  92. TS = PS.union(CS).union(FS).union(RS)
  93.  
  94. def validate_clue_1() -> bool:
  95.     return not any((
  96.         Thing.is_pair(P_Yvette, R_Lyon),
  97.         Thing.is_pair(P_Yvette, C_14),
  98.         # Thing.is_pair(C_14, R_Lyon) # Removing this assumption from first clue
  99.     ))
  100.  
  101. def validate_clue_2() -> bool:
  102.     return not any((
  103.         Thing.is_pair(C_16, R_Irene),
  104.         Thing.is_pair(C_16, R_Lyon)
  105.     ))
  106.  
  107. def validate_clue_3() -> bool:
  108.     if any((
  109.         Thing.is_pair(R_Lyon, C_17), Thing.is_pair(P_Leon, F_Pork)
  110.     )):
  111.         return False
  112.    
  113.     a = Thing.is_pair(P_Leon, C_17) and Thing.is_pair(F_Pork, R_Lyon)
  114.     b = Thing.is_pair(P_Leon, R_Lyon) and Thing.is_pair(F_Pork, C_17)
  115.  
  116.     return (a + b) == 1
  117.  
  118. def validate_clue_4() -> bool:
  119.     return (R_Charlie.cost, F_Chicken.cost) in (
  120.         (C_14, C_15),
  121.         (C_15, C_16),
  122.         (C_16, C_17)
  123.     )
  124.  
  125. def validate_clue_5() -> bool:
  126.     if Thing.is_pair(P_Yvette, R_Irene):
  127.         return False
  128.    
  129.     return any((
  130.         Thing.is_pair(F_Pork, P_Yvette),
  131.         Thing.is_pair(F_Pork, R_Irene)
  132.     ))
  133.  
  134. def validate_clue_6() -> bool:
  135.     return Thing.is_pair(P_Isac, F_Chicken)
  136.  
  137. def validate_all_clues() -> bool:
  138.     for clue in (
  139.         validate_clue_1,
  140.         validate_clue_2,
  141.         validate_clue_3,
  142.         validate_clue_4,
  143.         validate_clue_5,
  144.         validate_clue_6,
  145.     ):
  146.         if not clue():
  147.             # print(clue.__name__)
  148.             return False
  149.    
  150.     return True
  151.  
  152. def get_expanded_worlds(worlds: list[list[Thing]], items: set[Thing]):
  153.     for world in worlds:
  154.         for perm in itertools.permutations(items):        
  155.             expanded = []  
  156.             for (base, add) in zip(world, perm):
  157.                 item = base[:] + [add]
  158.                 expanded.append(item)
  159.             yield expanded
  160.  
  161. def get_all_worlds() -> list[list[Thing]]:
  162.     worlds = [[[p] for p in PS]]
  163.     worlds = list(w for w in get_expanded_worlds(worlds, RS))
  164.     worlds = list(w for w in get_expanded_worlds(worlds, FS))
  165.     worlds = list(w for w in get_expanded_worlds(worlds, CS))
  166.     return worlds                            
  167.  
  168. def realize_world(world: list[list[Thing]]) -> None:
  169.     for group in world:
  170.         p, r, f, c = group
  171.         p.add_resto(r)
  172.         p.add_food(f)
  173.         p.add_cost(c)
  174.  
  175. def reset_world() -> None:
  176.     for t in TS:
  177.         t.resto = None
  178.         t.food = None
  179.         t.cost = None
  180.         t.person = None
  181.  
  182. def test_all() -> int:
  183.     reset_world()
  184.  
  185.     good = 0
  186.     for world in get_all_worlds():
  187.         realize_world(world)
  188.  
  189.         if validate_all_clues():
  190.             good += 1
  191.        
  192.         reset_world()
  193.        
  194.     return good
  195.                    
  196. if __name__ == '__main__':
  197.     n = test_all()
  198.     print(f'Found {n} solution(s). Debug to investigate')
  199.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement