Advertisement
jordancurve

"A Self-Descriptive Crossword": Clingo solution

Feb 22nd, 2018
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.20 KB | None | 0 0
  1. % Stan Wagon Problem of the Week #1258. A Self-Descriptive Crossword
  2. %
  3. % Each of the entries in this crossword grid describes the number of times that the letter named appears in the completed grid. For example, if the grid had a single Z, then one of the entries would be "ONE Z", with a space after "ONE". Plurals are indicated by S, as in THIRTEEN ES. Spaces are counted here, so if there were nineteen spaces, then one entry would be "NINETEEN S" with TWO spaces after the word. These conditions uniquely determine all entries. Fill in the grid so that it describes itself.
  4. %
  5. % Source. Lee Sallows, Nijmegen, The Netherlands
  6. %
  7. % Text users: Art at <http://stanwagon.com/public/POWARCHIVE/1258SallowsCrosswordArt.jpg>
  8. %
  9. % Issue: Just left of center top is a down-sequence of two squares. That cannot and does not count as an answer. Lee has come up with a version that eliminates this blemish, but that version will appear in the Amer. Math. Monthly, so I will not show it here. The blemish makes no difference to the solving experience.
  10. %
  11. %
  12. % 1
  13. % 2 3 4 5 6 7 8 9 10 11
  14. % 12 13 14 15 16
  15. % 17 18 19
  16. % 20 21 22 23 24 25 26
  17. % 27 28 29 30 31 32 33 34 35
  18. % 36 37 38 39
  19. % 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
  20. % 56 57 58
  21. % 59 60
  22. % 61 62 63 64 65 66 67 68 69 70 71 72
  23. % 73 74 75
  24. % 76 77
  25. % 78
  26. % 79 80 81 82 83 84 85 86 87 88
  27. % 89
  28. % 90
  29. %
  30. % To solve the problem with Clingo, enter: clingo < crossword.lp
  31. %
  32. % There are two solutions. One looks like this:
  33. %
  34. % S
  35. % F I F T E E N S S
  36. % O N E X
  37. % O T
  38. % N T W O W S
  39. % S E V E N F S O
  40. % O F
  41. % T H R E E U S S E V E N O S
  42. % R S U
  43. % R
  44. % F O U R T E E N S
  45. % S I I
  46. % N S
  47. % E
  48. % F I F T E E N E S
  49. % N
  50. % S
  51. %
  52. % The other is the same, except with the letter E & S interchanged
  53. % in the two FIFTEEN rows.
  54.  
  55. % entry(E, C) :- Cell C is in entry E.
  56. entry(1, (1;3;16;18;21;34)).
  57. entry(2, (2;3;4;5;6;7;8;9;10;11)).
  58. entry(12, (12;13;14;15;16)).
  59. entry(17, (17;20;28;36;41)).
  60. entry(19, (19;25;35;38;50;57)).
  61. entry(21, (21;22;23;24;25;26)).
  62. entry(27, (27;28;29;30;31;32;33;34)).
  63. entry(33, (33;37;46;56;59;64;73)).
  64. entry(39, (39;54;58;60;72;75;77)).
  65. entry(40, (40;41;42;43;44;45;46;47)).
  66. entry(48, (48;49;50;51;52;53;54;55)).
  67. entry(61, (61;62;63;64;65;66;67;68;69;70;71)).
  68. entry(68, (68;74;76;78;86;89;90)).
  69. entry(79, (79;80;81;82;83;84;85;86;87;88)).
  70.  
  71. % entry(E) :- E is an entry (a sequene of cells to be filled in).
  72. entry(X) :-entry(X, _).
  73.  
  74. % entrylen(E, N) :- entry E has N cells.
  75. entrylen(E, N) :- N = #count { C : entry(E, C) }, entry(E).
  76.  
  77. % entry(E, N, C) :- cell C is the Nth cell in entry E.
  78. entry(E, N+1, C) :- N = #count { D : entry(E, D), D < C }, entry(E, C).
  79.  
  80. % Define the letters used in the spelling of each number word.
  81. #script (python)
  82. def word(n, s):
  83. terms = []
  84. for i, c in enumerate(s.string):
  85. terms.append((n.number, i+1, c))
  86. return terms
  87. #end.
  88. number(@word(1, "ONE")).
  89. number(@word(2, "TWO")).
  90. number(@word(3, "THREE")).
  91. number(@word(4, "FOUR")).
  92. number(@word(5, "FIVE")).
  93. number(@word(6, "SIX")).
  94. number(@word(7, "SEVEN")).
  95. number(@word(8, "EIGHT")).
  96. number(@word(9, "NINE")).
  97. number(@word(10, "TEN")).
  98. number(@word(10, "TEN")).
  99. number(@word(11, "ELEVEN")).
  100. number(@word(12, "TWELVE")).
  101. number(@word(13, "THIRTEEN")).
  102. number(@word(14, "FOURTEEN")).
  103. number(@word(15, "FIFTEEN")).
  104. number(@word(16, "SIXTEEN")).
  105. number(@word(17, "SEVENTEEN")).
  106. number(@word(18, "EIGHTEEN")).
  107. number(@word(19, "NINETEEN")).
  108. number(@word(20, "TWENTY")).
  109.  
  110. % num(N, I, L) :- letter L is the Ith letter in the word for number N.
  111. % Example: num(2, 1, "T"), because "T" is the 1st letter of "TWO", the word for number 2.
  112. num(N, I, L) :- number((N, I, L)).
  113.  
  114.  
  115. % num(N): N is a number of times some letter can occur in the crossword.
  116. num(N) :- num(N, _, _).
  117.  
  118. % numlen(N, M) :- the word for number N has M letters.
  119. numlen(N, M) :- M = #count { I : num(N,I,_) }, num(N).
  120.  
  121. % letter(L) :- L is a letter used in the crossword.
  122. letter(L) :- num(_, _, L).
  123. letter(" ").
  124.  
  125. % fill(E, N, L) :- Entry E consists of the word for number N followed by a
  126. % space followed by letter L followed by the letter "S".
  127.  
  128. % Fill each entry with an arbitrary number and letter (e.g. "TWO ES").
  129. 1 { fill(E, N, L) : num(N), letter(L) } 1 :- entry(E).
  130.  
  131. % Each entry must be exactly the right length for its contents.
  132. :- N > 1, fill(E, N, L), entrylen(E, M), numlen(N, K), M != K + 3.
  133. :- N = 1, fill(E, N, L), entrylen(E, M), numlen(N, K), M != K + 2.
  134.  
  135. % cell(C, L) :- cell C contains letter L.
  136. cell(C, M) :- fill(E, N, _), entry(E, X, C), num(N, X, M).
  137.  
  138. % Fill in the space after the count.
  139. cell(C, " ") :- fill(E, N, _), numlen(N, M), entry(E, M+1, C).
  140.  
  141. % Fill in the letter after the space.
  142. cell(C, L) :- fill(E, N, L), numlen(N, M), entry(E, M+2, C).
  143.  
  144. % Fill in the trailing "S" if the number is plural.
  145. cell(C, "S") :- fill(E, N, _), numlen(N, M), entry(E, M+3, C), N > 1.
  146.  
  147. % Don't write two different letters into the same cell.
  148. :- cell(C, L1), cell(C, L2), L1 < L2.
  149.  
  150. % occur(L, N) :- letter L occurs N times in the grid (N > 0).
  151. occur(L, N) :- N = #count { C : cell(C, L) }, letter(L), N > 0.
  152.  
  153. % If a letter occurs in the grid, and there is an entry reflecting its count, those two counts must be equal.
  154. :- occur(L, N), fill(_, M, L), M != N.
  155.  
  156. % Show the contents of each cell.
  157. #show cell/2.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement