Skip to content

Instantly share code, notes, and snippets.

@GreenLightning
Created June 21, 2015 20:01
Show Gist options
  • Save GreenLightning/35e5872b53c9eac92533 to your computer and use it in GitHub Desktop.
Save GreenLightning/35e5872b53c9eac92533 to your computer and use it in GitHub Desktop.
TIS-100 SCATTER PLOT VIEWER SPECIFICATION
-- For anyone who liked the SCATTER PLOT VIEWER puzzle included in some of the early
-- access builds of TIS-100...
-- INSTALLATION: Copy everything in this file. Open TIS-100. Go to the SPECIFICATION
-- EDITOR. Click on IMPORT SPECIFICATION FROM CLIPBOARD. Done!
-- The function get_name() should return a single string that is the name of the puzzle.
--
function get_name()
return "SCATTER PLOT VIEWER"
end
-- The function get_description() should return an array of strings, where each string is
-- a line of description for the puzzle. The text you return from get_description() will
-- be automatically formatted and wrapped to fit inside the puzzle information box.
--
function get_description()
return {
"READ AN X VALUE FROM IN",
"READ A Y VALUE FROM IN",
"READ A SPRITE VALUE FROM IN",
"IF SPRITE = 1, DRAW A WHITE PLUS",
"IF SPRITE = 2, DRAW A RED X"
}
end
-- The function get_streams() should return an array of streams. Each stream is described
-- by an array with exactly four values: a STREAM_* value, a name, a position, and an array
-- of integer values between -999 and 999 inclusive.
--
-- STREAM_INPUT: An input stream containing up to 39 numerical values.
-- STREAM_OUTPUT: An output stream containing up to 39 numerical values.
-- STREAM_IMAGE: An image output stream, containing exactly 30*18 numerical values between 0
-- and 4, representing the full set of "pixels" for the target image.
--
-- NOTE: Arrays in Lua are implemented as tables (dictionaries) with integer keys that start
-- at 1 by convention. The sample code below creates an input array of 39 random values
-- and an output array that doubles all of the input values.
--
-- 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 TIS-100 ensures that
-- the first test run is consistent for all users, and thus something that allows for the
-- comparison of cycle scores.
--
-- NOTE: Position values for streams should be between 0 and 3, which correspond to the far
-- left and far right of the TIS-100 segment grid. Input streams will be automatically
-- placed on the top, while output and image streams will be placed on the bottom.
--
function get_streams()
local image = create_blank_image()
local generate_x = create_horizontal_generator()
local generate_y = create_vertical_generator()
local input = {}
for i = 1,39,3 do -- 39 values allow us to provide 13 inputs consisting of 3 values
local x = generate_x()
local y = generate_y()
local sprite = math.random(2);
input[i + 0] = x
input[i + 1] = y
input[i + 2] = sprite
if sprite == 1 then
-- white plus
set_pixel(image, x, y-1, 3)
set_pixel(image, x-1, y, 3)
set_pixel(image, x, y, 3)
set_pixel(image, x+1, y, 3)
set_pixel(image, x, y+1, 3)
elseif sprite == 2 then
-- red x
set_pixel(image, x-1, y-1, 4)
set_pixel(image, x+1, y-1, 4)
set_pixel(image, x, y, 4)
set_pixel(image, x-1, y+1, 4)
set_pixel(image, x+1, y+1, 4)
end
end
return {
{ STREAM_INPUT, "IN", 1, input },
{ STREAM_IMAGE, "IMAGE", 2, image },
}
end
-- Returns a properly sized image array (30 * 18 pixel) containing all zeros (black).
--
function create_blank_image()
local image = {}
for i = 1,30*18 do
image[i] = 0
end
return image
end
-- Sets the pixel at x and y to the specified color value
--
function set_pixel(image, x, y, color)
-- add 1 because array indices start with 1 in lua
image[1 + 30*y + x] = color
end
-- The function get_layout() should return an array of exactly 12 TILE_* values, which
-- describe the layout and type of tiles found in the puzzle.
--
-- TILE_COMPUTE: A basic execution node (node type T21).
-- TILE_MEMORY: A stack memory node (node type T30).
-- TILE_DAMAGED: A damaged execution node, which acts as an obstacle.
--
function get_layout()
return {
TILE_COMPUTE, TILE_COMPUTE, TILE_COMPUTE, TILE_DAMAGED,
TILE_COMPUTE, TILE_COMPUTE, TILE_COMPUTE, TILE_COMPUTE,
TILE_COMPUTE, TILE_COMPUTE, TILE_COMPUTE, TILE_COMPUTE,
}
end
-- These functions create simple pseudo-random number generators
-- for the x and y values.
-- They are linear congruential generators and their parameters
-- are carefully chosen so that they have a full period, i. e.
-- they generate all possible numbers in a pseudo-random order
-- before starting over.
-- The resulting plots look a lot nicer than those created with
-- the lua random number generator because they are not
-- clustered as much.
--
-- The generators work by applying the following formula
-- repeatedly to the current seed (start) value:
--
-- s_1 = (a * s_0 + c) mod m
--
-- The ordering generated by these generators is hard-coded
-- in form of the three parameters a, c and m, however the
-- seed value is generated using math.random() which
-- results in enough variety.
-- The modulus value m determines the maximum number the
-- generator can output and also the maximum length of the
-- period.
-- The parameters a and c need to be adjusted to m to ensure
-- that the generator has a full period for all possible
-- seed values.
--
-- The generators generate values between 0 (inclusive) and
-- m (exclusive), however the generator functions add 1
-- to the result before returning it so that the horizontal
-- generator generates values between 1 and 28 and the
-- vertical generator generates values between 1 and 16.
-- The first and last indices (0 and 29 and 0 and 17 for
-- the 30x18 pixel large display) are not generated so
-- that all pixels of the resulting plot fall inside the
-- bounds of the display.
--
-- See also: https://en.wikipedia.org/wiki/Linear_congruential_generator
function create_horizontal_generator()
local m = 28
local c = 23
local a = 29
local s = math.random(m) - 1
return function ()
s = next(s, a, c, m)
return s + 1
end
end
function create_vertical_generator()
local m = 16
local c = 11
local a = 9
local s = math.random(m) - 1
return function ()
s = next(s, a, c, m)
return s + 1
end
end
function next(value, multiplier, increment, modulus)
return (multiplier * value + increment) % modulus
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment