Advertisement
Guest User

Untitled

a guest
Dec 16th, 2017
60
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.55 KB | None | 0 0
  1. #! /usr/bin/env perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. my %in;
  7. (m/^Generator ([AB]) starts with (\d+)$/ and $in{$1} = $2) for <>;
  8.  
  9. printf "Part 1: %d\n", solve($in{A}, $in{B}, 40_000_000, qr//, qr//);
  10. printf "Part 2: %d\n", solve($in{A}, $in{B}, 5_000_000, qr/xyz$/, qr/wxyz$/);
  11.  
  12. sub solve {
  13. # Numbers are represented as binary strings which
  14. # look like: "...qrstuuvwwxyyz". The doubled letters
  15. # are 1-bits, and single letters are 0-bits. In the
  16. # example, qrstuuvwwxyyz is 0000101010, or 42 in decimal.
  17. my $a = decimal_to_binary(shift);
  18. my $b = decimal_to_binary(shift);
  19.  
  20. my ($count, $filter_a, $filter_b) = @_;
  21.  
  22. # The $_ variable keeps track of how many matches have been
  23. # found so far. Each match is a "." character, so the string
  24. # "......." would mean 7 matches.
  25. local $_ = "";
  26. for my $i (1..$count) {
  27. do { $a = generator_a($a) } until $a =~ m/$filter_a/;
  28. do { $b = generator_b($b) } until $b =~ m/$filter_b/;
  29.  
  30. # Append $a and $b to $_. If the bottom 16 bits match,
  31. # substitute them with a ".". Clean up all non-"."
  32. # garbage before continuing.
  33. s/$/ $a $b/;
  34. s/(j[k-z]+) .*\1$/./;
  35. s/[^.]//g;
  36. }
  37.  
  38. return length_to_decimal($_);
  39. }
  40.  
  41. sub generator_a {
  42. local $_ = shift;
  43.  
  44. # Multiply by 16807 == 24 * 25 * 28 + 7
  45.  
  46. # Multiply by the remainder (7), and save for later
  47. my $r = s/(.)(?=\1)/$1$1$1$1$1$1$1/gr;
  48.  
  49. # Multiply by 24
  50. s/(.)(?=\1)/$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1/g;
  51. $_ = carry_binary($_);
  52.  
  53. # Multiply by 25
  54. s/(.)(?=\1)/$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1/g;
  55. $_ = carry_binary($_);
  56.  
  57. # Multiply by 28
  58. s/(.)(?=\1)/$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1/g;
  59.  
  60. # Add the remainder (7)
  61. s/$/ $r/;
  62. $_ = add_binary($_);
  63.  
  64. return mod_2147483647($_);
  65. }
  66.  
  67. sub generator_b {
  68. local $_ = shift;
  69.  
  70. # Multiply by 48271 == 33 * 34 * 43 + 25
  71.  
  72. # Multiply by the remainder (25), and save for later
  73. my $r = s/(.)(?=\1)/$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1/gr;
  74.  
  75. # Multiply by 33
  76. s/(.)(?=\1)/$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1/g;
  77. $_ = carry_binary($_);
  78.  
  79. # Multiply by 34
  80. s/(.)(?=\1)/$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1/g;
  81. $_ = carry_binary($_);
  82.  
  83. # Multiply by 43
  84. s/(.)(?=\1)/$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1/g;
  85.  
  86. # Add the remainder (25)
  87. s/$/ $r/;
  88. $_ = add_binary($_);
  89.  
  90. return mod_2147483647($_);
  91. }
  92.  
  93. sub mod_2147483647 {
  94. local $_ = shift;
  95.  
  96. # Take the remainder modulo 2147483647 (2^31 - 1), using a property
  97. # of Mersenne primes which allows a handy bitwise shortcut.
  98. #
  99. # remainder = (product >> 31) + (product & 0x7fffffff)
  100. # if (remainder & 0x80000000) {
  101. # remainder -= 0x7fffffff;
  102. # }
  103.  
  104. # Split the product into high and low bits, separated by a space
  105. s/(?=\\)/ /;
  106.  
  107. # Shift the high bits right by 31
  108. y/=-[/\\-z/;
  109.  
  110. # Prepend 31 0's to the high bits to bring the width back to 62
  111. s/^/=>?\@ABCDEFGHIJKLMNOPQRSTUVWXYZ[/;
  112.  
  113. # Add the numbers together
  114. $_ = add_binary($_);
  115.  
  116. # If the 0x80000000 bit is set, clear it and add 1, i.e.
  117. # remainder = remainder - 0x80000000 + 1;
  118. s/\[(\[.*)$/$1z/;
  119. return carry_binary($_);
  120. }
  121.  
  122. sub add_binary {
  123. local $_ = shift;
  124.  
  125. # Combine bits from each place value, for example:
  126. # "vwwxxyzz vwxxyyz" (01101 00110) becomes "vwwxxxyyzz" (01211)
  127. s/(.)\1*+\K(?=[^ ]* .*?\1(\1*))/$2/g;
  128.  
  129. # Remove the second number
  130. s/ .*$//g;
  131.  
  132. return carry_binary($_);
  133. }
  134.  
  135. sub decimal_to_binary {
  136. local $_ = shift;
  137.  
  138. # Convert to binary coded decimal
  139. s/0/wxyz:/g;
  140. s/1/wxyzz:/g;
  141. s/2/wxyyz:/g;
  142. s/3/wxyyzz:/g;
  143. s/4/wxxyz:/g;
  144. s/5/wxxyzz:/g;
  145. s/6/wxxyyz:/g;
  146. s/7/wxxyyzz:/g;
  147. s/8/wwxyz:/g;
  148. s/9/wwxyzz:/g;
  149. s/:$//;
  150.  
  151. # Bring the width of the first digit up to 62
  152. s/^/=>?\@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuv/;
  153.  
  154. # While there are more digits
  155. while (s/:/ /) {
  156. # Multiply by 10
  157. s/(([^ ])\2*)(?=\2[^ ]* )/$1$1$1$1$1$1$1$1$1$1/g;
  158.  
  159. # Add the next digit
  160. s/(.)\1*+\K(?=[^ ]* [^ ]*?\1(\1*))/$2/g;
  161. $_ = carry_binary($_);
  162.  
  163. # Erase the digit just added
  164. s/ [a-z]+//;
  165. }
  166.  
  167. return $_;
  168. }
  169.  
  170. sub length_to_decimal {
  171. local $_ = shift;
  172.  
  173. s/./z/g;
  174. s/^/stuvwxyz/;
  175.  
  176. s/(z){10}(?=\1)/y/g;
  177. s/(y){10}(?=\1)/x/g;
  178. s/(x){10}(?=\1)/w/g;
  179. s/(w){10}(?=\1)/v/g;
  180. s/(v){10}(?=\1)/u/g;
  181. s/(u){10}(?=\1)/t/g;
  182. s/(t){10}(?=\1)/s/g;
  183.  
  184. s/([a-z])\1{9}/9/g;
  185. s/([a-z])\1{8}/8/g;
  186. s/([a-z])\1{7}/7/g;
  187. s/([a-z])\1{6}/6/g;
  188. s/([a-z])\1{5}/5/g;
  189. s/([a-z])\1{4}/4/g;
  190. s/([a-z])\1{3}/3/g;
  191. s/([a-z])\1{2}/2/g;
  192. s/([a-z])\1{1}/1/g;
  193. s/([a-z])\1{0}/0/g;
  194. s/^0+(?!$)//;
  195.  
  196. return $_;
  197. }
  198.  
  199. sub carry_binary {
  200. local $_ = shift;
  201.  
  202. s/(z)\1(?=\1)/y/g;
  203. s/(y)\1(?=\1)/x/g;
  204. s/(x)\1(?=\1)/w/g;
  205. s/(w)\1(?=\1)/v/g;
  206. s/(v)\1(?=\1)/u/g;
  207. s/(u)\1(?=\1)/t/g;
  208. s/(t)\1(?=\1)/s/g;
  209. s/(s)\1(?=\1)/r/g;
  210. s/(r)\1(?=\1)/q/g;
  211. s/(q)\1(?=\1)/p/g;
  212. s/(p)\1(?=\1)/o/g;
  213. s/(o)\1(?=\1)/n/g;
  214. s/(n)\1(?=\1)/m/g;
  215. s/(m)\1(?=\1)/l/g;
  216. s/(l)\1(?=\1)/k/g;
  217. s/(k)\1(?=\1)/j/g;
  218. s/(j)\1(?=\1)/i/g;
  219. s/(i)\1(?=\1)/h/g;
  220. s/(h)\1(?=\1)/g/g;
  221. s/(g)\1(?=\1)/f/g;
  222. s/(f)\1(?=\1)/e/g;
  223. s/(e)\1(?=\1)/d/g;
  224. s/(d)\1(?=\1)/c/g;
  225. s/(c)\1(?=\1)/b/g;
  226. s/(b)\1(?=\1)/a/g;
  227. s/(a)\1(?=\1)/`/g;
  228. s/(`)\1(?=\1)/_/g;
  229. s/(_)\1(?=\1)/^/g;
  230. s/(\^)\1(?=\1)/]/g;
  231. s/(])\1(?=\1)/\\/g;
  232. s/(\\)\1(?=\1)/[/g;
  233. s/(\[)\1(?=\1)/Z/g;
  234. s/(Z)\1(?=\1)/Y/g;
  235. s/(Y)\1(?=\1)/X/g;
  236. s/(X)\1(?=\1)/W/g;
  237. s/(W)\1(?=\1)/V/g;
  238. s/(V)\1(?=\1)/U/g;
  239. s/(U)\1(?=\1)/T/g;
  240. s/(T)\1(?=\1)/S/g;
  241. s/(S)\1(?=\1)/R/g;
  242. s/(R)\1(?=\1)/Q/g;
  243. s/(Q)\1(?=\1)/P/g;
  244. s/(P)\1(?=\1)/O/g;
  245. s/(O)\1(?=\1)/N/g;
  246. s/(N)\1(?=\1)/M/g;
  247. s/(M)\1(?=\1)/L/g;
  248. s/(L)\1(?=\1)/K/g;
  249. s/(K)\1(?=\1)/J/g;
  250. s/(J)\1(?=\1)/I/g;
  251. s/(I)\1(?=\1)/H/g;
  252. s/(H)\1(?=\1)/G/g;
  253. s/(G)\1(?=\1)/F/g;
  254. s/(F)\1(?=\1)/E/g;
  255. s/(E)\1(?=\1)/D/g;
  256. s/(D)\1(?=\1)/C/g;
  257. s/(C)\1(?=\1)/B/g;
  258. s/(B)\1(?=\1)/A/g;
  259. s/(A)\1(?=\1)/\@/g;
  260. s/(\@)\1(?=\1)/?/g;
  261. s/(\?)\1(?=\1)/>/g;
  262. s/(>)\1(?=\1)/=/g;
  263.  
  264. return $_;
  265. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement