Advertisement
scorleo

Countdown Numbers Game

Mar 28th, 2018
290
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.65 KB | None | 0 0
  1. import itertools as it
  2. import operator
  3. import random
  4.  
  5. from more_itertools import distinct_permutations
  6.  
  7.  
  8. class FalseOperation(ValueError):
  9.     pass
  10.  
  11.  
  12. def is_valid(sequence):
  13.     count_nums = 0
  14.     for token in sequence:
  15.         if not token:
  16.             count_nums -= 1
  17.             if count_nums < 1:
  18.                 return False
  19.         else:
  20.             count_nums += 1
  21.     return True
  22.  
  23.  
  24. def valid_sequences(num_count):
  25.     base = (True,) * num_count + (False,) * (num_count - 1)
  26.     #     print(base)
  27.     perms = distinct_permutations(base)
  28.     #     perms = list(perms)
  29.     #     print(f'possible permutations: {len(perms)}')
  30.     for sequence in perms:
  31.         #         print(sequence)
  32.         if is_valid(sequence):
  33.             yield sequence
  34.  
  35.  
  36. def distinct_ordered_combinations(iterable, r):
  37.     seen = set()
  38.     for combination in it.combinations_with_replacement(iterable, r):
  39.         for permutation in it.permutations(combination):
  40.             if permutation not in seen:
  41.                 yield permutation
  42.                 seen.add(permutation)
  43.  
  44.  
  45. def generate_sequences(numbers, operators):
  46.     l = len(numbers)
  47.     for sequence in valid_sequences(l):
  48.         for nums, ops in it.product(
  49.                 distinct_permutations(numbers),
  50.                 distinct_ordered_combinations(operators, l - 1),
  51.         ):
  52.             nums = iter(nums)
  53.             ops = iter(ops)
  54.             yield tuple(next(nums) if token else next(ops) for token in sequence)
  55.  
  56.  
  57. def calculate_sequence(sequence, operators):
  58.     # Implement postfix algorithm
  59.     stack = list(sequence[:2])
  60.     for idx, token in enumerate(sequence[2:], start=3):
  61.         if token not in operators:
  62.             stack.append(token)
  63.             continue
  64.         operand1 = stack.pop()
  65.         operand2 = stack.pop()
  66.         try:
  67.             result = operators[token](operand1, operand2)
  68.         except ZeroDivisionError:
  69.             raise FalseOperation('Division by zero')
  70.         if int(result) != result:
  71.             raise FalseOperation('non-int value')
  72.         if result < 0:
  73.             raise FalseOperation('negative value')
  74.         yield result, sequence[:idx]
  75.         stack.append(result)
  76.  
  77.  
  78. def test_sequences(target, numbers, operators):
  79.     for sequence in generate_sequences(numbers, operators):
  80.         try:
  81.             for result, seq in calculate_sequence(sequence, operators):
  82.                 if result == target:
  83.                     yield result, seq
  84.         except FalseOperation:
  85.             pass
  86.  
  87.  
  88. def main():
  89.     # Generate the set of possible numbers allowed by Countdown rules
  90.     large_numbers = [25, 50, 75, 100]
  91.     small_numbers = list(range(1, 11)) * 2
  92.  
  93.     # Generate six number tiles according to user input for large numbers
  94.     while True:
  95.         try:
  96.             usr_large_num = int(input("How many LARGE numbers do you want (0-4)? "))
  97.         except ValueError:
  98.             pass
  99.         else:
  100.             if 0 <= usr_large_num <= 4:
  101.                 break
  102.     six_tiles = random.sample(large_numbers, usr_large_num) + \
  103.                 random.sample(small_numbers, 6 - usr_large_num)
  104.  
  105.     # Generate random target output: any three-digit number
  106.     target = random.randint(100, 999)
  107.  
  108.     print(six_tiles)
  109.     print(f"Target: {target}")
  110.  
  111.     ops_tiles = {"+": operator.add,
  112.                  "-": operator.sub,
  113.                  "*": operator.mul,
  114.                  "/": operator.truediv}
  115.  
  116.     for operators in it.combinations_with_replacement(ops_tiles, 4):
  117.         generate_sequences(six_tiles, operators)
  118.         test_sequences(target, six_tiles, operators)
  119.         print('hi')
  120.  
  121.  
  122. if __name__ == '__main__':
  123.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement