Beispiel #1
0
def arithmetic(puzzle="SEND+MORE=MONEY", base=10) -> None:

    problem = re.split(r"[\s+=]", puzzle)

    # remove spaces
    problem = list(filter(lambda w: len(w) > 0, problem))

    letters = {
        letter: facile.variable(range(base))
        for letter in set("".join(problem))
    }

    # expressions
    expr_pb = [[letters[a] for a in word] for word in problem]

    def horner(a: Expression, b: Expression):
        return 10 * a + b

    words = [reduce(horner, word) for word in expr_pb]

    # constraints
    facile.constraint(facile.alldifferent(letters.values()))
    facile.constraint(facile.sum(words[:-1]) == words[-1])

    for word in expr_pb:
        facile.constraint(word[0] > 0)

    assert facile.solve(letters.values())

    # print solutions
    for word, numbers in zip(problem, expr_pb):
        strings = [str(n.value()) for n in numbers]
        print(f"{word} = {''.join(strings)}")
Beispiel #2
0
def print_current(sol):
    print("Solution after {} backtracks:".format(sol.backtrack))
    for i, x in enumerate(sol.solution):
        if x == 0:
            continue
        print("  {} × {:<20} : {:>5}".format(x, products[i], x * price[i]))
    total = sum(x * price[i] for i, x in enumerate(sol.solution))
    print("  Total                    : {:>5}".format(total))
Beispiel #3
0
def test_magical() -> None:
    array = [facile.variable(range(10)) for i in range(10)]

    for i in range(10):
        sum_ = facile.sum(x == i for x in array)
        facile.constraint(sum_ == array[i])

    solution = facile.solve(array)

    assert solution.solved
    assert solution.solution == [6, 2, 1, 0, 0, 0, 1, 0, 0, 0]
Beispiel #4
0
def coins(values, maxval) -> Optional[Solution]:
    """
    Which coins do you need to give back change for any amount between 0 and
    maxval, using coins from values?
    """

    # How many coin types
    n = len(values)
    nb_min_coins = [variable(range(maxval // values[i])) for i in range(n)]

    for val in range(maxval):
        # How many coins per type
        nb_coins = [variable(range(maxval // values[i])) for i in range(n)]
        mysum = sum([x[0] * x[1] for x in zip(values, nb_coins)])
        constraint(mysum == val)
        for j in range(len(nb_coins)):
            constraint(nb_coins[j] <= nb_min_coins[j])

    total = variable(sum(nb_min_coins))

    return minimize(nb_min_coins, total)
Beispiel #5
0
import facile

# Magical sequence!
# The value inside array[i] is equal to the number of i in array

array = [facile.variable(range(10)) for i in range(10)]

for i in range(10):
    facile.constraint(facile.sum(x == i for x in array) == array[i])

if facile.solve(array):
    print([v.value() for v in array])
Beispiel #6
0
# Agatha hates everybody except the butler.
constraint(hates[agatha, charles] == 1)
constraint(hates[agatha, agatha] == 1)
constraint(hates[agatha, butler] == 0)

# The butler hates everyone not richer than Aunt Agatha.
#   (richer[i, agatha] = 0) => (hates[butler, i] = 1),
for i in range(n):
    constraint((richer[i, agatha] == 0) <= (hates[butler, i] == 1))

# The butler hates everyone whom Agatha hates.
#   (hates[agatha, i] = 1) => (hates[butler, i] = 1),
for i in range(n):
    constraint((hates[agatha, i] == 1) <= (hates[butler, i] == 1))

# No one hates everyone.
#   (sum j: hates[i, j]) <= 2,
for i in range(n):
    constraint(sum([hates[i, j] for j in range(n)]) <= 2)

# Who killed Agatha?
constraint(victim == agatha)

assert solve(list(hates) + list(richer) + [victim, killer])
killer_value = killer.value()
assert killer_value is not None

msg = "{} killed Agatha."
print(msg.format(["Agatha", "The butler", "Charles"][killer_value]))
Beispiel #7
0
buckets = [
    [variable(range(capacity[b] + 1)) for b in range(nb)] for i in range(steps)
]

constraint(buckets[0][0] == 8)
constraint(buckets[0][1] == 0)
constraint(buckets[0][2] == 0)

constraint(buckets[steps - 1][0] == 4)
constraint(buckets[steps - 1][1] == 4)
constraint(buckets[steps - 1][2] == 0)

for i in range(steps - 1):
    # we change the contents of two buckets at a time
    sum_buckets = sum([buckets[i][b] != buckets[i + 1][b] for b in range(nb)])
    constraint(sum_buckets == 2)
    # we play with a constant amount of water
    sum_water = sum([buckets[i][b] for b in range(nb)])
    constraint(sum_water == 8)
    for b1 in range(nb):
        for b2 in range(b1):
            constraint(
                # either the content of the bucket does not change
                (buckets[i][b1] == buckets[i + 1][b1])
                | (buckets[i][b2] == buckets[i + 1][b2])
                |
                # or the bucket ends up empty or full
                (buckets[i + 1][b1] == 0)
                | (buckets[i + 1][b1] == capacity[b1])
                | (buckets[i + 1][b2] == 0)
Beispiel #8
0
for i in range(nb_weeks):

    # [1] Use a Sorting Constraint (redundant with [2])
    s = groups[i, :].sort()
    for j in range(nb_golfers):
        facile.constraint(s[j] == j // size_group)

    # [2] Use a Global Cardinality Constraint (redundant with [1])
    gcc = groups[i, :].gcc([(size_group, i) for i in range(nb_groups)])
    facile.constraint(gcc)

# Two golfers do not play in the same group more than once
for g1 in range(nb_golfers):
    for g2 in range(g1 + 1, nb_golfers):
        g1_with_g2 = [groups[w, g1] == groups[w, g2] for w in range(nb_weeks)]
        facile.constraint(facile.sum(g1_with_g2) <= 1)

# Breaking the symmetries
#  - 0 always in the first group, 1 in a group less than 1, ...
#  - First week (0) a priori chosen

for w in range(nb_weeks):
    for g in range(nb_groups):
        facile.constraint(groups[w, g] <= g)

for g in range(nb_golfers):
    facile.constraint(groups[0, g] == g // size_group)

if not facile.solve(list(groups)):
    print("No solution found")
else:
Beispiel #9
0
price = [215, 275, 335, 355, 420, 580]
total = 1505

products = [
    "mixed fruit",
    "french fries",
    "side salad",
    "host wings",
    "mozzarella sticks",
    "samples place",
]

# how many items of each dish
quantity = [variable(range(10)) for p in price]

constraint(sum(q * p for q, p in zip(quantity, price)) == total)


def print_current(sol):
    print("Solution after {} backtracks:".format(sol.backtrack))
    for i, x in enumerate(sol.solution):
        if x == 0:
            continue
        print("  {} × {:<20} : {:>5}".format(x, products[i], x * price[i]))
    total = sum(x * price[i] for i, x in enumerate(sol.solution))
    print("  Total                    : {:>5}".format(total))


res = solve_all(quantity, backtrack=True, on_solution=print_current)

print("Total of {} backtracks".format(res[-1].backtrack))
Beispiel #10
0
  information.

"""

from facile import Variable, constraint, sum

row_sums = [0, 0, 8, 2, 6, 4, 5, 3, 7, 0, 0]
col_sums = [0, 0, 7, 1, 6, 3, 4, 5, 2, 7, 0, 0]

rows = len(row_sums)
cols = len(col_sums)

x = [[Variable.binary() for j in col_sums] for i in row_sums]

for i in range(rows):
    constraint(sum(x[i][j] for j in range(cols)) == row_sums[i])
for j in range(cols):
    constraint(sum(x[i][j] for i in range(rows)) == col_sums[j])


def print_solution():
    print(" ", end=" ")
    for j in range(cols):
        print(col_sums[j], end=" ")
    print()
    for i in range(rows):
        print(row_sums[i], end=" ")
        for j in range(cols):
            if x[i][j].value() == 1:
                print("#", end=" ")
            else: