Last active
April 28, 2022 00:26
-
-
Save iconmaster5326/b77d9878dcd91549ba053ba32ae81cbf to your computer and use it in GitHub Desktop.
Revisions
-
iconmaster5326 revised this gist
Apr 28, 2022 . 1 changed file with 13 additions and 13 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,20 +1,20 @@ Here is a solution for breeding a gold quintar with an initially empty stable: obtain RIVER WOKE from world obtain BLUE TRUSTY from world breed RIVER WOKE with BLUE TRUSTY (making BLUE FANCY) obtain RED WOKE from world breed BLUE FANCY with RED WOKE (making HIGHLAND BRUTISH) breed BLUE FANCY with HIGHLAND BRUTISH (making HIGHLAND FANCY) breed RIVER WOKE with HIGHLAND FANCY (making AQUA BRUTISH) breed RIVER WOKE with AQUA BRUTISH (making AQUA WOKE) release BLUE TRUSTY obtain DESERT BRUTISH from world release BLUE FANCY breed DESERT BRUTISH with HIGHLAND FANCY (making DESERT FANCY) release DESERT BRUTISH breed RIVER WOKE with DESERT FANCY (making BLACK BRUTISH) release RIVER WOKE breed BLACK BRUTISH with DESERT FANCY (making BLACK FANCY) release BLACK BRUTISH breed BLACK FANCY with AQUA WOKE (making GOLD BRUTISH) -
iconmaster5326 revised this gist
Apr 27, 2022 . 1 changed file with 9 additions and 7 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -13,18 +13,17 @@ pip install intbitset """ import enum import multiprocessing import typing import intbitset class QuintarType(enum.Enum): RED = 1 BLUE = 2 DESERT = 3 HIGHLAND = 4 RIVER = 5 BLACK = 6 @@ -151,9 +150,12 @@ def breed(q1: Quintar, q2: Quintar) -> Quintar: # default case: the least valuable type among the two else: if ( q1.nature.value > q2.nature.value ): # TODO: is this right? not mentioned by any duck new_type = q1.type else: new_type = q2.type return Quintar( new_type, combine_natures(q1.nature, q2.nature), -
iconmaster5326 revised this gist
Apr 27, 2022 . 1 changed file with 14 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,17 @@ """ This script finds the minimal number of steps required to breed a golden quintar, given an initial stable state. Note that, due to its multi-threaded nature, there is a very small but finite probability it does not return a minimal solution, but it will be at most one step away from a minimal one. Also note that this script considers things like releasing quintar or obtaining them from the game world steps; finding the minimal number of breeding steps or the minimal number of quintar races required would take considerably higher computing power. To run this script, you need some Python packages to be installed: pip install intbitset """ import enum import multiprocessing -
iconmaster5326 revised this gist
Apr 27, 2022 . 1 changed file with 17 additions and 6 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,10 @@ # To run this script, you need some Python packages to be installed: # pip install intbitset import enum import multiprocessing import typing import intbitset class QuintarType(enum.Enum): @@ -233,13 +236,17 @@ def possible_next_steps(slots: QuintarSlots) -> typing.Iterable[Action]: yield ActionRelease(q) def intbitset_hash(value: typing.Hashable): return hash(value) % intbitset.__maxelem__ def search_process( process_no: int, initial_slots: QuintarSlots, solutions: "multiprocessing.Queue[typing.Tuple[Action, ...]]", result: "multiprocessing.Queue[typing.Tuple[Action, ...]]", ): visited: intbitset.intbitset = intbitset.intbitset() while True: steps = solutions.get(True) # print( @@ -248,18 +255,22 @@ def search_process( # cycle checking slots_after = quintar_slots_after(initial_slots, steps) slots_set_hash = intbitset_hash( frozenset(q for q in slots_after if q is not None) ) if slots_set_hash in visited: continue else: visited.add(slots_set_hash) # success if any(q is not None and q.type == QuintarType.GOLD for q in slots_after): result.put(steps) # recursion for next_step in possible_next_steps(slots_after): if ( intbitset_hash( frozenset(q for q in next_step.act(slots_after) if q is not None) ) not in visited ): solutions.put_nowait(steps + (next_step,)) -
iconmaster5326 revised this gist
Apr 27, 2022 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -262,7 +262,7 @@ def search_process( frozenset(q for q in next_step.act(slots_after) if q is not None) not in visited ): solutions.put_nowait(steps + (next_step,)) def search( -
iconmaster5326 revised this gist
Apr 27, 2022 . 1 changed file with 75 additions and 39 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,12 +1,16 @@ import enum import multiprocessing import threading import typing class QuintarType(enum.Enum): RED = ( 1 # TODO: what is relative ordering of red and blue? not mentioned by any duck ) BLUE = 2 DESERT = 3 # TODO: what is relative ordering of desert? not mentioned by any duck HIGHLAND = 4 RIVER = 5 BLACK = 6 AQUA = 7 @@ -132,7 +136,9 @@ def breed(q1: Quintar, q2: Quintar) -> Quintar: # default case: the least valuable type among the two else: new_type = min( q1.type, q2.type, key=(lambda x: x.value) ) # TODO: is this right? not mentioned by any duck return Quintar( new_type, combine_natures(q1.nature, q2.nature), @@ -150,6 +156,7 @@ def breed(q1: Quintar, q2: Quintar) -> Quintar: } MAX_QUINAR_SLOTS = 8 EMPTY_SLOTS = (None,) * MAX_QUINAR_SLOTS NUMBER_THREADS = multiprocessing.cpu_count() QuintarSlots = typing.Tuple[typing.Optional[Quintar], ...] @@ -222,50 +229,79 @@ def possible_next_steps(slots: QuintarSlots) -> typing.Iterable[Action]: yield ActionObtainInWorld(quintar) if all(v is not None for v in slots): for q in slots: if q is not None: yield ActionRelease(q) def search_process( process_no: int, initial_slots: QuintarSlots, solutions: "multiprocessing.Queue[typing.Tuple[Action, ...]]", result: "multiprocessing.Queue[typing.Tuple[Action, ...]]", ): visited: typing.Dict[typing.FrozenSet[Quintar], typing.Literal[True]] = {} while True: steps = solutions.get(True) # print( # f"[{process_no}] got {len(steps)} steps ending in: {steps[-1] if len(steps) > 0 else None}" # ) # cycle checking slots_after = quintar_slots_after(initial_slots, steps) slots_set = frozenset(q for q in slots_after if q is not None) if slots_set in visited: continue else: visited[slots_set] = True # success if any(q is not None and q.type == QuintarType.GOLD for q in slots_after): result.put(steps) # recursion for next_step in possible_next_steps(slots_after): if ( frozenset(q for q in next_step.act(slots_after) if q is not None) not in visited ): solutions.put(steps + (next_step,), True) def search( slots: QuintarSlots = EMPTY_SLOTS, ) -> typing.Tuple[Action, ...]: with multiprocessing.Manager() as manager: solutions = manager.Queue() solutions.put((), True) result = manager.Queue(1) processes = [ multiprocessing.Process( target=search_process, args=(i, slots, solutions, result) ) for i in range(NUMBER_THREADS) ] for process in processes: process.start() return result.get(True) if __name__ == "__main__": multiprocessing.freeze_support() print( "\n".join( str(step) for step in search( # if you already have some quintars, fill them in below and uncomment the following lines: # ( # Quintar(QuintarType.EXAMPLE, QuintarNature.EXAMPLE), # slot filled with Quintar # None, # slot not filled with Quintar # None, # None, # None, # None, # None, # None, # ) ) ) ) -
iconmaster5326 revised this gist
Apr 27, 2022 . 1 changed file with 7 additions and 6 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,11 +3,11 @@ class QuintarType(enum.Enum): RED = 1 # TODO: what is relative ordering of red and blue? not mentioned by any duck BLUE = 2 HIGHLAND = 3 DESERT = 4 # TODO: what is relative ordering of desert? not mentioned by any duck RIVER = 5 BLACK = 6 AQUA = 7 GOLD = 8 @@ -130,10 +130,11 @@ def breed(q1: Quintar, q2: Quintar) -> Quintar: } and QuintarNature.FANCY in {q1.nature, q2.nature}: return Quintar(QuintarType.GOLD, combine_natures(q1.nature, q2.nature)) # default case: the least valuable type among the two else: new_type = min(q1.type, q2.type, key=(lambda x: x.value)) # TODO: is this right? not mentioned by any duck return Quintar( new_type, combine_natures(q1.nature, q2.nature), ) -
iconmaster5326 revised this gist
Apr 27, 2022 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ Here is a solution for breeding a gold quintar with an initially empty stable: obtain DESERT BRUTISH from world obtain BLUE TRUSTY from world obtain RED WOKE from world breed BLUE TRUSTY with RED WOKE (making BLUE FANCY) -
iconmaster5326 created this gist
Apr 27, 2022 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,270 @@ import enum import typing class QuintarType(enum.Enum): RED = 1 BLUE = 2 DESERT = 3 RIVER = 4 HIGHLAND = 5 BLACK = 6 AQUA = 7 GOLD = 8 def __str__(self) -> str: return self.name class QuintarNature(enum.Enum): FIENDISH = 1 BRUTISH = 2 WOKE = 3 FANCY = 4 TRUSTY = 5 def __str__(self) -> str: return self.name class Quintar(typing.NamedTuple): type: QuintarType nature: QuintarNature def __str__(self) -> str: return f"{self.type} {self.nature}" def can_breed(q1: Quintar, q2: Quintar) -> bool: return q1.nature != q2.nature def combine_natures(n1: QuintarNature, n2: QuintarNature) -> QuintarNature: if n1 == n2: return n1 elif n1 == QuintarNature.FIENDISH or n1 == QuintarNature.BRUTISH: if n2 == QuintarNature.TRUSTY: return n1 else: return n2 elif n2 == QuintarNature.FIENDISH or n2 == QuintarNature.BRUTISH: if n1 == QuintarNature.TRUSTY: return n2 else: return n1 elif {n1, n2} == {QuintarNature.FANCY, QuintarNature.WOKE}: return QuintarNature.BRUTISH elif {n1, n2} == {QuintarNature.FANCY, QuintarNature.TRUSTY}: return QuintarNature.WOKE elif {n1, n2} == {QuintarNature.WOKE, QuintarNature.TRUSTY}: return QuintarNature.FANCY else: raise Exception(f"Unknown nature combination: {n1} and {n2}") def breed(q1: Quintar, q2: Quintar) -> Quintar: # brutish takes own type and other's nature UNLESS they're Trusty # brutish takes priority over fiendish if q1.nature == QuintarNature.BRUTISH: if q2.nature == QuintarNature.TRUSTY: return Quintar(q1.type, q1.nature) else: return Quintar(q1.type, q2.nature) elif q2.nature == QuintarNature.BRUTISH: if q1.nature == QuintarNature.TRUSTY: return Quintar(q2.type, q2.nature) else: return Quintar(q2.type, q1.nature) # fiendish always clones the other parent UNLESS they're Trusty elif q1.nature == QuintarNature.FIENDISH: if q1.nature == QuintarNature.TRUSTY: return Quintar(q2.type, q1.nature) else: return Quintar(q2.type, q2.nature) elif q2.nature == QuintarNature.FIENDISH: if q1.nature == QuintarNature.TRUSTY: return Quintar(q1.type, q2.nature) else: return Quintar(q1.type, q1.nature) # red + blue = highland (if one parent is fancy) elif {q1.type, q2.type} == { QuintarType.RED, QuintarType.BLUE, } and QuintarNature.FANCY in {q1.nature, q2.nature}: return Quintar(QuintarType.HIGHLAND, combine_natures(q1.nature, q2.nature)) # desert fancy + river X = black Y elif ( q1.nature == QuintarNature.FANCY and q1.type == QuintarType.DESERT and q2.type == QuintarType.RIVER ): return Quintar(QuintarType.BLACK, combine_natures(q1.nature, q2.nature)) elif ( q2.nature == QuintarNature.FANCY and q2.type == QuintarType.DESERT and q1.type == QuintarType.RIVER ): return Quintar(QuintarType.BLACK, combine_natures(q1.nature, q2.nature)) # highland fancy + river X = aqua Y elif ( q1.nature == QuintarNature.FANCY and q1.type == QuintarType.HIGHLAND and q2.type == QuintarType.RIVER ): return Quintar(QuintarType.AQUA, combine_natures(q1.nature, q2.nature)) elif ( q2.nature == QuintarNature.FANCY and q2.type == QuintarType.HIGHLAND and q1.type == QuintarType.RIVER ): return Quintar(QuintarType.AQUA, combine_natures(q1.nature, q2.nature)) # black + aqua = gold (if one parent is fancy) elif {q1.type, q2.type} == { QuintarType.BLACK, QuintarType.AQUA, } and QuintarNature.FANCY in {q1.nature, q2.nature}: return Quintar(QuintarType.GOLD, combine_natures(q1.nature, q2.nature)) # default case: the most valuable type among the two else: return Quintar( max(q1.type, q2.type, key=(lambda x: x.value)), combine_natures(q1.nature, q2.nature), ) OBTAINABLE_IN_WORLD = { Quintar(QuintarType.BLUE, QuintarNature.FIENDISH), Quintar(QuintarType.RED, QuintarNature.TRUSTY), Quintar(QuintarType.RIVER, QuintarNature.WOKE), Quintar(QuintarType.BLUE, QuintarNature.TRUSTY), Quintar(QuintarType.RED, QuintarNature.WOKE), Quintar(QuintarType.DESERT, QuintarNature.BRUTISH), Quintar(QuintarType.DESERT, QuintarNature.FIENDISH), } MAX_QUINAR_SLOTS = 8 EMPTY_SLOTS = (None,) * MAX_QUINAR_SLOTS QuintarSlots = typing.Tuple[typing.Optional[Quintar], ...] class ActionObtainInWorld(typing.NamedTuple): quintar: Quintar def act(self, slots: QuintarSlots) -> QuintarSlots: free_index = slots.index(None) assert free_index >= 0 return tuple( (self.quintar if i == free_index else v) for i, v in enumerate(slots) ) def __str__(self) -> str: return f"obtain {self.quintar} from world" class ActionRelease(typing.NamedTuple): quintar: Quintar def act(self, slots: QuintarSlots) -> QuintarSlots: full_index = slots.index(self.quintar) assert full_index >= 0 return tuple((None if i == full_index else v) for i, v in enumerate(slots)) def __str__(self) -> str: return f"release {self.quintar}" class ActionBreed(typing.NamedTuple): quintar1: Quintar quintar2: Quintar def act(self, slots: QuintarSlots) -> QuintarSlots: free_index = slots.index(None) assert free_index >= 0 return tuple( (breed(self.quintar1, self.quintar2) if i == free_index else v) for i, v in enumerate(slots) ) def __str__(self) -> str: return f"breed {self.quintar1} with {self.quintar2} (making {breed(self.quintar1, self.quintar2)})" Action = typing.Union[ActionObtainInWorld, ActionRelease, ActionBreed] def quintar_slots_after( slots: QuintarSlots, actions: typing.Iterable[Action] ) -> QuintarSlots: for action in actions: slots = action.act(slots) return slots def possible_next_steps(slots: QuintarSlots) -> typing.Iterable[Action]: if any(v is None for v in slots): for q1 in slots: for q2 in slots: if ( q1 is not None and q2 is not None and can_breed(q1, q2) and breed(q1, q2) not in slots ): yield ActionBreed(q1, q2) for quintar in OBTAINABLE_IN_WORLD: if quintar not in slots: yield ActionObtainInWorld(quintar) if all(v is not None for v in slots): for q in slots: yield ActionRelease(q) def search( slots: QuintarSlots = EMPTY_SLOTS, ) -> typing.Optional[typing.Tuple[Action, ...]]: solutions: typing.List[typing.Tuple[Action, ...]] = [()] visited: typing.Set[typing.FrozenSet[Quintar]] = set() while len(solutions) > 0: # cycle checking steps = solutions.pop(0) slots_after = quintar_slots_after(slots, steps) slots_set = frozenset(q for q in slots_after if q is not None) if slots_set in visited: continue else: visited.add(slots_set) # success if any(q is not None and q.type == QuintarType.GOLD for q in slots_after): return steps # recursion for next_step in possible_next_steps(slots_after): # print(f"[{len(steps)}] {next_step}") solutions.append(steps + (next_step,)) # failure return None print( ", ".join( str(step) for step in search( # if you already have some quintars, fill them in below and uncomment the following lines: # ( # Quintar(QuintarType.EXAMPLE, QuintarNature.EXAMPLE), # slot filled with Quintar # None, # slot not filled with Quintar # None, # None, # None, # None, # None, # None, # ) ) or ("no solution found",) ) ) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,20 @@ obtain DESERT BRUTISH from world Here is a solution for breeding a gold quintar with an initially empty stable: obtain BLUE TRUSTY from world obtain RED WOKE from world breed BLUE TRUSTY with RED WOKE (making BLUE FANCY) breed DESERT BRUTISH with BLUE FANCY (making DESERT FANCY) breed RED WOKE with BLUE FANCY (making HIGHLAND BRUTISH) breed BLUE FANCY with HIGHLAND BRUTISH (making HIGHLAND FANCY) obtain RIVER WOKE from world release DESERT BRUTISH breed DESERT FANCY with RIVER WOKE (making BLACK BRUTISH) release BLUE TRUSTY breed BLACK BRUTISH with RED WOKE (making BLACK WOKE) release BLACK BRUTISH breed HIGHLAND FANCY with RIVER WOKE (making AQUA BRUTISH) release RED WOKE breed AQUA BRUTISH with BLUE FANCY (making AQUA FANCY) release AQUA BRUTISH breed BLACK WOKE with AQUA FANCY (making GOLD BRUTISH)