csaboka

Weekly Challenge #22: Credit Card Validator

Aug 30th, 2017
614
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.40 KB | None | 0 0
  1. -- The function get_name() should return a single string that is the name of the puzzle.
  2. --
  3. function get_name()
  4.     return "CREDIT CARD VERIFIER"
  5. end
  6.  
  7. -- The function get_description() should return an array of strings, where each string is
  8. -- a line of description for the puzzle. Surrounding text with asterisks will cause it to
  9. -- be rendered in bold, something we use when mentioning a signal by name.
  10. --
  11. -- By using the syntax that we use in our puzzle descriptions, you can also create tables:
  12. --
  13. --       "| This is a table. | This is a second column. | This is a column with "
  14. --       "|                  |                          | multiple line of text."
  15. --       "----------------------------------------------------------------------"
  16. --       "| This is a second |                          | More text here!       "
  17. --       "| table row.       |                          |                       "
  18. --
  19. -- Puzzle descriptions are not automatically paginated, so you can use the string "<PAGE>"
  20. -- to start a new page of text. If you don't it will overflow and make Zach sad.
  21. --
  22. function get_description()
  23.     return {
  24.         "*card#* are XBus inputs connected to numeric keypads.",
  25.         "*error* is a simple output connected to a LED next to the keypad.",
  26.         "15-digit credit card numbers are entered on the keypads connected to *card#*.",
  27.         "Verfiy whether the card number was entered correctly, using the *Luhn algorithm*.",
  28.         "Send 100 to *error* to make the LED turn on when the card number is incorrect.",
  29.         "There will never be two card numbers entered during the same time unit.",
  30.         "<PAGE>",
  31.         "*The Luhn algorithm* works like this:",
  32.         "Counting from the right, double every second digit of the number",
  33.         "Take the sum of all digits. If you ended up with a value above 9 in the previous step, use the sum of the digits of that number",
  34.         "If the sum is divisible by 10, the number passes the Luhn algorithm",
  35.         "See the next page for an example.",
  36.         "<PAGE>",
  37.         "Take a number:",
  38.         "|2|8|8|5|7|1|6|6|1|9|1|8|1|1|3",
  39.         "Double every second digit, counting from the right:",
  40.         "|2|*16*|8|*10*|7|*2*|6|*12*|1|*18*|1|*16*|1|*2*|3",
  41.         "Add the digits together: 2+1+6+8+1+0+7+2+6+1+2+1+1+8+1+1+6+1+2+3=60",
  42.         "The number passes because 60 is divisible by 10"
  43.     }
  44. end
  45.  
  46. -- The function get_board() allows you to specify an 18x7 "ASCII art" grid to customize
  47. -- the layout of the board and the placement of the input and output terminals. Generally
  48. -- speaking, inputs are placed on the left of boards, while outputs are placed on the right.
  49. --
  50. -- For empty space, use the '.' character.
  51. -- For buildable board space, use the '#' character.
  52. -- For an input or output terminal, use characters '0' through '9' no more than once each.
  53. -- For the bottom-left corner of the radio, use the 'R' character.
  54. -- For the bottom-left corners of dials, use characters 'A', 'B', and 'C'.
  55. --
  56. function get_board()
  57.     return [[
  58.         .0123##########...
  59.         .....##########...
  60.         .###############..
  61.         .################4
  62.         .###############..
  63.         .##############...
  64.         .##############...
  65.     ]]
  66. end
  67.  
  68. -- The function get_data() is called both to establish information about the puzzle (such as what
  69. -- the inputs and outputs are) and to generate the random test cases. Signal levels and XBus data
  70. -- should change from call to call, but information like the names and types of terminals should
  71. -- not change at all.
  72. --
  73. -- To create a standard input or output terminal, call create_terminal(). Valid terminal types are
  74. -- TYPE_SIMPLE, TYPE_XBUS, and TYPE_XBUS_NONBLOCKING. Valid terminal directions are DIR_INPUT and
  75. -- DIR_OUTPUT. Valid data for a simple I/O signal is an array of integers, 0 - 100 inclusive. Valid
  76. -- data for an XBus signal is an array of integer arrays, each with values -999 to 999 inclusive.
  77. --
  78. --       create_terminal(name, board_character, type, direction, data)
  79. --
  80. -- To create a radio (C2S-RF901), call create_radio(). You may only create one radio in each puzzle.
  81. -- Since radios are XBus-only, the only valid data for data_rx and data_tx are arrays of integer arrays,
  82. -- each with values -999 to 999 inclusive. You cannot customize the signal names for a radio.
  83. --
  84. -- By default the radio will be placed in the bottom-left corner of the screen. However, if you use an
  85. -- 'R' character in your board layout, the bottom-left corner of the radio will be placed there instead.
  86. --
  87. --       create_radio(data_rx, data_tx)
  88. --
  89. -- To create a dial (N4DL-1000), call create_dial(). You may create up to three dials in each puzzle.
  90. -- The names of dials should be kept short, as there is not much room to display them visually. A valid
  91. -- value is an integer between 0 and 99, inclusive.
  92. --
  93. -- By default dials will be placed in the bottom-left corner of the screen. However, if you use an
  94. -- 'A', 'B', or 'C' character in your board layout, the bottom-left corners of the first, second, and
  95. -- third dials will be placed there, respectively.
  96. --
  97. --       create_dial(name, value)
  98. --
  99. -- NOTE: To generate random values you should use math.random(). However, you SHOULD NOT seed
  100. --       the random number generator with a new seed value, as that is how the game ensures that
  101. --       the first test run is consistent for all users, and thus something that allows for the
  102. --       comparison of cycle scores.
  103. --
  104. -- NOTE: Fun fact! Arrays in Lua are implemented as tables (dictionaries) with integer keys that
  105. --       start at 1 by convention. Contrast this with nearly every other programming language, in
  106. --       which arrays start with an index of 0. Because of this, the 60 "time slices" that make
  107. --       up a test case are indexed from 1 to 60 inclusive.
  108. --
  109. function random_sequence(length)
  110.     local result = {}
  111.     for i = 1, length do
  112.         result[i] = math.random(0, 9)
  113.     end
  114.     return result
  115. end
  116.  
  117. function get_luhn_digit(seq)
  118.     local checksum = 0
  119.     for i = 1, #seq do
  120.         local digit = seq[#seq - i + 1]
  121.         if i % 2 == 1 then
  122.             digit = digit * 2
  123.         end
  124.         if digit < 10 then
  125.             checksum = checksum + digit
  126.         else
  127.             checksum = checksum + 1 + (digit - 10)
  128.         end
  129.     end
  130.     return (10 - checksum % 10) % 10
  131. end
  132.  
  133. function get_data()
  134.     local inputs = {{}, {}, {}, {}}
  135.     local output = {}
  136.     local current_lane = 1
  137.     local time = 1
  138.  
  139.     while time <= 60 do
  140.         local seq = random_sequence(14)
  141.         local correct_luhn = get_luhn_digit(seq)
  142.         local last_digit
  143.         if math.random(1, 5) == 1 then
  144.             last_digit = math.random(0, 9)
  145.         else
  146.             last_digit = correct_luhn
  147.         end
  148.         seq[15] = last_digit
  149.         inputs[current_lane][time] = seq
  150.         if last_digit != correct_luhn then
  151.             output[time] = 100
  152.         end
  153.         if current_lane < 4 then
  154.             current_lane = current_lane + 1
  155.         else
  156.             current_lane = 1
  157.         end
  158.         time = time + 4
  159.     end
  160.  
  161.     create_terminal("card#", "0", TYPE_XBUS, DIR_INPUT, inputs[1])
  162.     create_terminal("card#", "1", TYPE_XBUS, DIR_INPUT, inputs[2])
  163.     create_terminal("card#", "2", TYPE_XBUS, DIR_INPUT, inputs[3])
  164.     create_terminal("card#", "3", TYPE_XBUS, DIR_INPUT, inputs[4])
  165.     create_terminal("error", "4", TYPE_SIMPLE, DIR_OUTPUT, output)
  166. end
Advertisement
Add Comment
Please, Sign In to add comment