You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
3.0 KiB

  1. # coding: utf-8
  2. import os, sys
  3. from z3 import *
  4. import string
  5. # get the playground information
  6. directory = os.path.dirname(os.path.realpath(__file__))
  7. fname = directory + "/" + "test0.txt"
  8. if len(sys.argv) == 2:
  9. fname = sys.argv[1]
  10. with open(fname) as f:
  11. playground = f.read()
  12. playground = [[c for c in row] for row in playground.strip().split("\n")]
  13. # get the playground size
  14. size_y = len(playground)
  15. assert(size_y != 0)
  16. size_x = len(playground[0])
  17. assert(size_x != 0)
  18. for row in playground:
  19. assert(len(row) == size_x)
  20. bells = {}
  21. for i in range(size_y):
  22. for j in range(size_x):
  23. c = playground[i][j]
  24. if ord(c) in range(ord("1"), ord("9") + 1):
  25. assert(int(c) not in bells.keys())
  26. bells[int(c)] = (j, i)
  27. ################################### Maestria ###################################
  28. print(f"Playground size : {size_x} x {size_y}")
  29. print("Playground:")
  30. print("\n".join(["".join(i) for i in playground]))
  31. print("Bell positions:")
  32. print(bells)
  33. print("\n")
  34. # create the solver
  35. solver = Solver()
  36. fudge_x, fudge_y = Ints("fudge_x fudge_y")
  37. # position must be in the board
  38. solver.add(fudge_x >= 0, fudge_x < size_x, fudge_y >= 0, fudge_y < size_y)
  39. # position must be on walkable cell
  40. for i in range(size_y):
  41. for j in range(size_x):
  42. if playground[i][j] != "_":
  43. solver.add(Not(And(fudge_y == i, fudge_x == j)))
  44. # encode distances in formula
  45. distances = {bell: None for bell in bells.keys()}
  46. for bell, (x,y) in bells.items():
  47. distances[bell] = (fudge_x - x) * (fudge_x - x) + (fudge_y - y) * (fudge_y - y)
  48. #
  49. # enforce ordering of distances
  50. distances_sorted = [distances[b] for b in sorted(bells.keys())]
  51. for i in range(len(distances_sorted) - 1):
  52. near = distances_sorted[i]
  53. far = distances_sorted[i+1]
  54. solver.add(near < far)
  55. # call the solver and check satisfiability
  56. while solver.check() == sat:
  57. #result = solver.check()
  58. #if result == sat:
  59. m = solver.model()
  60. if fudge_x is not None and fudge_y is not None:
  61. pos_x = m[fudge_x].as_long()
  62. pos_y = m[fudge_y].as_long()
  63. playground[pos_y][pos_x] = "F"
  64. solver.add(Or(fudge_x != pos_x, fudge_y != pos_y))
  65. ################################################################################
  66. from colorama import Fore, Back, Style
  67. cols = [Fore.BLUE, Fore.GREEN, Fore.RED, Fore.YELLOW, Fore.MAGENTA, Fore.CYAN]
  68. tones = [Style.BRIGHT, Style.DIM]
  69. cols = sum([[c + t for c in cols] for t in tones], [])
  70. if sys.stdout.isatty():
  71. for bell in sorted(list(bells.keys())):
  72. x, y = bells[bell]
  73. playground[y][x] = Back.BLACK + cols[bell - 1] + playground[y][x] + Style.RESET_ALL
  74. for y in range(size_y):
  75. for x in range(size_x):
  76. c = playground[y][x]
  77. if c == "_": playground[y][x] = Fore.BLACK + Back.WHITE + c + Style.RESET_ALL
  78. if c == "X": playground[y][x] = Fore.WHITE + Back.BLACK + c + Style.RESET_ALL
  79. if c == "F": playground[y][x] = Fore.BLACK + Back.WHITE + c + Style.RESET_ALL
  80. text = "\n".join(["".join([c for c in row]) for row in playground])
  81. print(text)