File size: 7,463 Bytes
8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf b9c9b71 8e80adf |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
This is an example of representing a Zebra Puzzle using a Z3-based Python code: There are 5 Producers in this puzzle. Categories and possible items: - Shirt: black, green, orange, pink, red - Name: Barbara, Isabella, Jane, Nicole, Rachel - Jam: apricot, cherry, fig, raspberry, watermelon - Size: 10 oz, 12 oz, 14 oz, 20 oz, 6 oz - Source: backyard, farmers' coop, local grocer, organic farm, wild pickings Clues: - The producer whose jam comes from Wild pickings is in the fourth position. - The producer selling Cherry jam is somewhere to the right of the one wearing a Green shirt. - Isabella is selling Cherry jam. - The producer wearing a Pink shirt is somewhere between the producer whose jam source is the Backyard and the one selling Watermelon jam, in that order. - The producer selling 14 oz jars is somewhere to the right of the one wearing a Green shirt. - The producer with 14 oz jars is next to the one selling Raspberry jam. - The Raspberry jam producer is positioned at one of the ends. - Barbara is next to the producer whose jam source is the Organic farm. - Jane is located somewhere between Nicole and Isabella, in that order. - The producer of Fig jam sources the fruit from an Organic farm. - The producer with 10 oz jars is at one of the ends. - The Raspberry jam producer is somewhere to the right of the one wearing a Green shirt. - The producer with 12 oz jars is next to the one who has 6 oz jars. - Isabella is next to the producer wearing a Black shirt. - The producer with 6 oz jars is next to the one whose source is the Local grocer. - The producer with 6 oz jars is in the second position. - Rachel's source of fruit is the Farmers' coop. - Barbara is next to Nicole. - The producer wearing an Orange shirt gets her fruit from the Backyard. - The producer with 12 oz jars is in the very first position. ```python from z3 import * import json import sys # Define all categories in a single list of tuples: # (House is implicit; each row's first column will be the house number.) categories = [ ("Shirt", ["black", "green", "orange", "pink", "red"]), ("Name", ["Barbara", "Isabella", "Jane", "Nicole", "Rachel"]), ("Jam", ["apricot", "cherry", "fig", "raspberry", "watermelon"]), ("Size", ["10 oz", "12 oz", "14 oz", "20 oz", "6 oz"]), ("Source", ["backyard", "farmers' coop", "local grocer", "organic farm", "wild pickings"]) ] # No need to change here, automatically processing NUM_POSITIONS = len(categories[0][1]) item_to_cat_and_index = {} for cat_idx, (cat_str, item_list) in enumerate(categories): for item_idx, item_str in enumerate(item_list): item_to_cat_and_index[(cat_str, item_str)] = (cat_idx, item_idx) Vars = [] for cat_idx, (cat_name, item_list) in enumerate(categories): var = IntVector(cat_name, len(item_list)) Vars.append(var) s = Solver() for cat_idx, (cat_name, item_list) in enumerate(categories): for item_idx, item_str in enumerate(item_list): s.add(Vars[cat_idx][item_idx] >= 1, Vars[cat_idx][item_idx] <= NUM_POSITIONS) s.add(Distinct(Vars[cat_idx])) def pos(cat_str, item_str): (cat_idx, item_idx) = item_to_cat_and_index[(cat_str, item_str)] return Vars[cat_idx][item_idx] # All clues here # The producer whose jam comes from Wild pickings is in the fourth position. s.add(pos("Source", "wild pickings") == 4) # The producer selling Cherry jam is somewhere to the right of the one wearing a Green shirt. s.add(pos("Jam", "cherry") > pos("Shirt", "green")) # Isabella is selling Cherry jam. s.add(pos("Name", "Isabella") == pos("Jam", "cherry")) # The producer wearing a Pink shirt is somewhere between the producer whose jam source is the Backyard and the one selling Watermelon jam, in that order. s.add(And(pos("Source", "backyard") < pos("Shirt", "pink"), pos("Shirt", "pink") < pos("Jam", "watermelon"))) # The producer selling 14 oz jars is somewhere to the right of the one wearing a Green shirt. s.add(pos("Size", "14 oz") > pos("Shirt", "green")) # The producer with 14 oz jars is next to the one selling Raspberry jam. s.add(Abs(pos("Size", "14 oz") - pos("Jam", "raspberry")) == 1) # The Raspberry jam producer is positioned at one of the ends. s.add(Or(pos("Jam", "raspberry") == 1, pos("Jam", "raspberry") == NUM_POSITIONS)) # Barbara is next to the producer whose jam source is the Organic farm. s.add(Abs(pos("Name", "Barbara") - pos("Source", "organic farm")) == 1) # Jane is located somewhere between Nicole and Isabella, in that order. s.add(And(pos("Name", "Nicole") < pos("Name", "Jane"), pos("Name", "Jane") < pos("Name", "Isabella"))) # The producer of Fig jam sources the fruit from an Organic farm. s.add(pos("Jam", "fig") == pos("Source", "organic farm")) # The producer with 10 oz jars is at one of the ends. s.add(Or(pos("Size", "10 oz") == 1, pos("Size", "10 oz") == NUM_POSITIONS)) # The Raspberry jam producer is somewhere to the right of the one wearing a Green shirt. s.add(pos("Jam", "raspberry") > pos("Shirt", "green")) # The producer with 12 oz jars is next to the one who has 6 oz jars. s.add(Abs(pos("Size", "12 oz") - pos("Size", "6 oz")) == 1) # Isabella is next to the producer wearing a Black shirt. s.add(Abs(pos("Name", "Isabella") - pos("Shirt", "black")) == 1) # The producer with 6 oz jars is next to the one whose source is the Local grocer. s.add(Abs(pos("Size", "6 oz") - pos("Source", "local grocer")) == 1) # The producer with 6 oz jars is in the second position. s.add(pos("Size", "6 oz") == 2) # Rachel's source of fruit is the Farmers' coop. s.add(pos("Name", "Rachel") == pos("Source", "farmers' coop")) # Barbara is next to Nicole. s.add(Abs(pos("Name", "Barbara") - pos("Name", "Nicole")) == 1) # The producer wearing an Orange shirt gets her fruit from the Backyard. s.add(pos("Shirt", "orange") == pos("Source", "backyard")) # The producer with 12 oz jars is in the very first position. s.add(pos("Size", "12 oz") == 1) # Solve the puzzle if s.check() == sat: m = s.model() rows = [] header = ["House"] + [cat_name for cat_name, _ in categories] for position in range(1, NUM_POSITIONS + 1): row = [str(position)] for cat_idx, (cat_name, item_list) in enumerate(categories): for item_idx, item_str in enumerate(item_list): if m.evaluate(Vars[cat_idx][item_idx]).as_long() == position: row.append(item_str) break rows.append(row) result_dict = {"header": header, "rows": rows} cnt = 1 block = [] for cat_idx, (cat_name, item_list) in enumerate(categories): for i in range(NUM_POSITIONS): block.append(Vars[cat_idx][i] != m[Vars[cat_idx][i]]) s.add(Or(block)) while s.check() == sat: m = s.model() cnt += 1 block = [] for cat_idx, (cat_name, item_list) in enumerate(categories): for i in range(NUM_POSITIONS): block.append(Vars[cat_idx][i] != m[Vars[cat_idx][i]]) s.add(Or(block)) if cnt == 1: # Output the solution as a JSON string. print(json.dumps(result_dict)) else: print(json.dumps({"error": "Multiple solutions found."})) else: print(json.dumps({"error": "No solution found."})) sys.stdout.flush() # Force immediate output ``` Based on this example, write a similar Z3-based Python code by changing only categories and constraints to represent the puzzle given below. |