Last active
September 9, 2017 19:48
-
-
Save emlun/d375b3b843499fb7d3b2ae41d9e8442a to your computer and use it in GitHub Desktop.
Shenzhen I/O: Frobnicator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- The function get_name() should return a single string that is the name of the puzzle. | |
-- | |
function get_name() | |
return "Frobnicator" | |
end | |
-- The function get_description() should return an array of strings, where each string is | |
-- a line of description for the puzzle. Surrounding text with asterisks will cause it to | |
-- be rendered in bold, something we use when mentioning a signal by name. | |
-- | |
-- By using the syntax that we use in our puzzle descriptions, you can also create tables: | |
-- | |
-- "| This is a table. | This is a second column. | This is a column with " | |
-- "| | | multiple line of text." | |
-- "----------------------------------------------------------------------" | |
-- "| This is a second | | More text here! " | |
-- "| table row. | | " | |
-- | |
-- Puzzle descriptions are not automatically paginated, so you can use the string "<PAGE>" | |
-- to start a new page of text. If you don't it will overflow and make Zach sad. | |
-- | |
function get_description() | |
return { | |
"*prog* is a simple input connected to a push button.", | |
"*keypad* is a non-blocking XBus input connected to a numeric keypad.", | |
"*data-in* is a non-blocking XBus input connected to an electronic device generating nonnegative numbers.", | |
"*data-out* is an XBus output connected to an electronic device.", | |
"<PAGE>", | |
"When data arrives on *data-in*, frobnicate it as described below and write the result to *data-out*.", | |
"While *prog* is pressed, read decimal digits from *keypad* until *prog* is released. Create a number _k_ from the up to 3 last digits, with the last digit to arrive as the least significant digit. If _k <_ 500, set the frobnication key _K_ to _k_. If _k >=_ 500, do not change _K_. _K_ is initially zero.", | |
"A key _K_ frobnicates a number _n_ to _f(n, K)_, where:\nIf _n = K_, then _f(n, K) = n_. If _n < K_, then _f(n, K) = K + (K - n)_. If _n > K_ then _f(n, K) = K - (n - K)_.", | |
} | |
end | |
-- The function get_board() allows you to specify an 18x7 "ASCII art" grid to customize | |
-- the layout of the board and the placement of the input and output terminals. Generally | |
-- speaking, inputs are placed on the left of boards, while outputs are placed on the right. | |
-- | |
-- For empty space, use the '.' character. | |
-- For buildable board space, use the '#' character. | |
-- For an input or output terminal, use characters '0' through '9' no more than once each. | |
-- For the bottom-left corner of the radio, use the 'R' character. | |
-- For the bottom-left corners of dials, use characters 'A', 'B', and 'C'. | |
-- | |
function get_board() | |
return [[ | |
.0###############. | |
.################. | |
.################. | |
.1##############3. | |
.################. | |
.################. | |
.2###############. | |
]] | |
end | |
-- The function get_data() is called both to establish information about the puzzle (such as what | |
-- the inputs and outputs are) and to generate the random test cases. Signal levels and XBus data | |
-- should change from call to call, but information like the names and types of terminals should | |
-- not change at all. | |
-- | |
-- To create a standard input or output terminal, call create_terminal(). Valid terminal types are | |
-- TYPE_SIMPLE, TYPE_XBUS, and TYPE_XBUS_NONBLOCKING. Valid terminal directions are DIR_INPUT and | |
-- DIR_OUTPUT. Valid data for a simple I/O signal is an array of integers, 0 - 100 inclusive. Valid | |
-- data for an XBus signal is an array of integer arrays, each with values -999 to 999 inclusive. | |
-- | |
-- create_terminal(name, board_character, type, direction, data) | |
-- | |
-- To create a radio (C2S-RF901), call create_radio(). You may only create one radio in each puzzle. | |
-- Since radios are XBus-only, the only valid data for data_rx and data_tx are arrays of integer arrays, | |
-- each with values -999 to 999 inclusive. You cannot customize the signal names for a radio. | |
-- | |
-- By default the radio will be placed in the bottom-left corner of the screen. However, if you use an | |
-- 'R' character in your board layout, the bottom-left corner of the radio will be placed there instead. | |
-- | |
-- create_radio(data_rx, data_tx) | |
-- | |
-- To create a dial (N4DL-1000), call create_dial(). You may create up to three dials in each puzzle. | |
-- The names of dials should be kept short, as there is not much room to display them visually. A valid | |
-- value is an integer between 0 and 99, inclusive. | |
-- | |
-- By default dials will be placed in the bottom-left corner of the screen. However, if you use an | |
-- 'A', 'B', or 'C' character in your board layout, the bottom-left corners of the first, second, and | |
-- third dials will be placed there, respectively. | |
-- | |
-- create_dial(name, value) | |
-- | |
-- NOTE: To generate random values you should use math.random(). However, you SHOULD NOT seed | |
-- the random number generator with a new seed value, as that is how the game ensures that | |
-- the first test run is consistent for all users, and thus something that allows for the | |
-- comparison of cycle scores. | |
-- | |
-- NOTE: Fun fact! Arrays in Lua are implemented as tables (dictionaries) with integer keys that | |
-- start at 1 by convention. Contrast this with nearly every other programming language, in | |
-- which arrays start with an index of 0. Because of this, the 60 "time slices" that make | |
-- up a test case are indexed from 1 to 60 inclusive. | |
-- | |
function frob(n, k) | |
if n == k then | |
return n | |
elseif n < k then | |
return (k + (k - n)) | |
else | |
return (k - (n - k)) | |
end | |
end | |
function get_data() | |
keypad = {} | |
prog = {} | |
data_in = {} | |
data_out = {} | |
T = 60 | |
frobkey = {} | |
for t = 1, T do | |
frobkey[t] = 0 | |
end | |
time = 1 | |
while time <= T do | |
time = time + math.random(5,10) | |
progtime = math.random(3, math.min(8, T - 5 - time)) | |
for j = 0, progtime - 1 do | |
prog[time + j] = 100 | |
end | |
key_input = {} | |
key_idx = 1 | |
keytime = -2 | |
keytime = keytime + math.random(1, 4) | |
while keytime <= progtime + 2 do | |
input = math.random(1, 9) | |
keypad[time + keytime] = { input } | |
if keytime >= 0 and keytime < progtime then | |
key_input[key_idx] = input | |
key_idx = key_idx + 1 | |
end | |
keytime = keytime + math.random(1, 4) | |
end | |
key = 0 | |
if key_idx > 3 then | |
key = key + 100 * key_input[key_idx - 3] | |
end | |
if key_idx > 2 then | |
key = key + 10 * key_input[key_idx - 2] | |
end | |
if key_idx > 1 then | |
key = key + key_input[key_idx - 1] | |
end | |
if key < 500 and progtime >= 1 then | |
for t = time + progtime, T do | |
frobkey[t] = key | |
end | |
end | |
time = time + progtime + 1 | |
end | |
time = 1 | |
while time <= T do | |
if math.random(1, 3) == 1 then | |
num_packets = math.random(1, math.min(5, 59 - time)) | |
data_in[time] = {} | |
data_out[time] = {} | |
for i = 1, num_packets do | |
data_in[time][i] = math.random(0, 999) | |
data_out[time][i] = frob(data_in[time][i], frobkey[time]) | |
end | |
time = time + num_packets | |
else | |
time = time + 1 | |
end | |
end | |
create_terminal("keypad", "0", TYPE_XBUS_NONBLOCKING, DIR_INPUT, keypad) | |
create_terminal("prog", "1", TYPE_SIMPLE, DIR_INPUT, prog) | |
create_terminal("data-in", "2", TYPE_XBUS_NONBLOCKING, DIR_INPUT, data_in) | |
create_terminal("data-out", "3", TYPE_XBUS, DIR_OUTPUT, data_out) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment