Runge-Kutta method

Given the example Differential equation:
:y'(t) = t \times \sqrt {y(t)}
With initial condition:
:t_0 = 0 and y_0 = y(t_0) = y(0) = 1
This equation has an exact solution:
:y(t) = \tfrac{1}{16}(t^2 +4)^2

;Task
Demonstrate the commonly used explicit   fourth-order Runge-Kutta method   to solve the above differential equation.
* Solve the given differential equation over the range t = 0 \ldots 10 with a step value of \delta t=0.1 (101 total points, the first being given)
* Print the calculated values of y at whole numbered t's (0.0, 1.0, \ldots 10.0) along with error as compared to the exact solution.

;Method summary
Starting with a given y_n and t_n calculate:
:\delta y_1 = \delta t\times y'(t_n, y_n)\quad
:\delta y_2 = \delta t\times y'(t_n + \tfrac{1}{2}\delta t , y_n + \tfrac{1}{2}\delta y_1)
:\delta y_3 = \delta t\times y'(t_n + \tfrac{1}{2}\delta t , y_n + \tfrac{1}{2}\delta y_2)
:\delta y_4 = \delta t\times y'(t_n + \delta t , y_n + \delta y_3)\quad
then:
:y_{n+1} = y_n + \tfrac{1}{6} (\delta y_1 + 2\delta y_2 + 2\delta y_3 + \delta y_4)
:t_{n+1} = t_n + \delta t\quad

Solution:
local df = function (t, y)
-- derivative of function by value y at time t
	return t*y^0.5
end

local dt = 0.1
local y = 1

print ("t", "realY"..'     ', "y", '		'.."error")
print ("---", "-------"..'     ', "---------------", '	'.."--------------------")

for i = 0, 100 do
	local t = i*dt
	if t%1 == 0 then
		local realY = (t*t+4)^2/16
		print (t, realY..'     ', y, '	'..realY-y)
	end
	local dy1 = df(t, y)
	local dy2 = df(t+dt/2, y+dt/2*dy1)
	local dy3 = df(t+dt/2, y+dt/2*dy2)
	local dy4 = df(t+dt, y+dt*dy3)
	y = y + dt*(dy1+2*dy2+2*dy3+dy4)/6
end


Runtime evaluation

Demonstrate a language's ability for programs to execute code written in the language provided at runtime.

Show what kind of program fragments are permitted (e.g. expressions vs. statements), and how to get values in and out (e.g. environments, arguments, return values), if applicable what lexical/static environment the program is evaluated in, and what facilities for restricting (e.g. sandboxes, resource limits) or customizing (e.g. debugging facilities) the execution.

You may not invoke a separate evaluator program, or invoke a compiler and then its output, unless the interface of that program, and the syntax and means of executing it, are considered part of your language/library/platform.

For a more constrained task giving a specific program fragment to evaluate, see [[Eval in environment]].

Solution:
f = loadstring(s) -- load a string as a function. Returns a function.

one = loadstring"return 1" -- one() returns 1

two = loadstring"return ..." -- two() returns the arguments passed to it


Runtime evaluation

Solution:
> f = load("return 42")
> f()
42
> n = load("return 42")()
> n
42


Runtime evaluation/In an environment

Given a program in the language (as a string or AST) with a free variable named x (or another name if that is not valid syntax), evaluate it with x bound to a provided value, then evaluate it again with x bound to another provided value, then subtract the result of the first from the second and return or print it.

Do so in a way which:
* does not involve string manipulation of the input source code
* is plausibly extensible to a runtime-chosen set of bindings rather than just x
* does not make x a ''global'' variable

or note that these are impossible.

;See also:
* For more general examples and language-specific details, see [[Eval]].
* [[Dynamic variable names]] is a similar task.

Solution:
code = loadstring"return x^2" --this doesn't really need to be input, does it?
val1 = setfenv(code, {x = io.read() + 0})()
val2 = setfenv(code, {x = io.read() + 0})()
print(val2 - val1)


Runtime evaluation/In an environment

Solution:
env = {}
f = load("return x", nil, nil, env)
env.x = tonumber(io.read()) -- user enters 2
a = f()
env.x = tonumber(io.read()) -- user enters 3
b = f()
print(a + b) --> outputs 5


Sailors, coconuts and a monkey problem

Five sailors are shipwrecked on an island and collect a large pile of coconuts during the day.

That night the first sailor wakes up and decides to take his first share early  so tries to divide the pile of coconuts equally into five piles but finds that there is one coconut left over, so he tosses it to a monkey and then hides "his" one of the five equally sized piles of coconuts and pushes the other four piles together to form a single visible pile of coconuts again and goes to bed.

To cut a long story short, each of the sailors in turn gets up once during the night and performs the same actions of dividing the coconut pile into five, finding that one coconut is left over and giving that single remainder coconut to the monkey.

In the morning (after the surreptitious and separate action of each of the five sailors during the night), the remaining coconuts are divided into five equal piles for each of the sailors, whereupon it is found that the pile of coconuts divides equally amongst the sailors with no remainder. (Nothing for the monkey in the morning.)

;The task:
# Calculate the minimum possible size of the initial pile of coconuts collected during the first day.
# Use a method that assumes an answer is possible, and then applies the constraints of the tale to see if it is correct. (I.e. no applying some formula that generates the correct answer without integer divisions and remainders and tests on remainders; but constraint solvers ''are'' allowed.)
# Calculate the size of the initial pile of coconuts if six sailors were marooned and went through a similar process (but split into six piles instead of five of course).
# Show your answers here.

;Extra credit (optional):
* Give some indication of the number of coconuts each sailor hides during the night.

;Note:
* Of course the tale is told in a world where the collection of any amount of coconuts in a day and multiple divisions of the pile, etc can occur in time fitting the story line, so as not to affect the mathematics.
* The tale is also told in a version where the monkey also gets a coconut in the morning. This is ''not'' that tale!

;C.f:
* Monkeys and Coconuts - Numberphile (Video) Analytical solution.
* A002021: Pile of coconuts problem The On-Line Encyclopedia of Integer Sequences. (Although some of its references may use the alternate form of the tale).

Solution:
function valid(n,nuts)
    local k = n
    local i = 0
    while k ~= 0 do
        if (nuts % n) ~= 1 then
            return false
        end
        k = k - 1
        nuts = nuts - 1 - math.floor(nuts / n)
    end
    return nuts ~= 0 and (nuts % n == 0)
end

for n=2, 9 do
    local x = 0
    while not valid(n, x) do
        x = x + 1
    end
    print(n..": "..x)
end


Same fringe

Write a routine that will compare the leaves ("fringe") of two binary trees to determine whether they are the same list of leaves when visited left-to-right.  The structure or balance of the trees does not matter; only the number, order, and value of the leaves is important.

Any solution is allowed here, but many computer scientists will consider it inelegant to collect either fringe in its entirety before starting to collect the other one.  In fact, this problem is usually proposed in various forums as a way to show off various forms of concurrency (tree-rotation algorithms have also been used to get around the need to collect one tree first).  Thinking of it a slightly different way, an elegant solution is one that can perform the minimum amount of work to falsify the equivalence of the fringes when they differ somewhere in the middle, short-circuiting the unnecessary additional traversals and comparisons.

Any representation of a binary tree is allowed, as long as the nodes are orderable, and only downward links are used (for example, you may not use parent or sibling pointers to avoid recursion).

Solution:
local type, insert, remove = type, table.insert, table.remove

None = {} -- a unique object for a truncated branch (i.e. empty subtree)
function isbranch(node) return type(node) == 'table' and #node == 2 end
function left(node) return node[1] end
function right(node) return node[2] end

function fringeiter(tree)
    local agenda = {tree}
    local function push(item) insert(agenda, item) end
    local function pop() return remove(agenda) end
    return function()
        while #agenda > 0 do
            node = pop()
            if isbranch(node) then
                push(right(node))
                push(left(node))
            elseif node == None then
                -- continue
            else
                return node
            end
        end
    end
end

function same_fringe(atree, btree)
    local anext = fringeiter(atree or None)
    local bnext = fringeiter(btree or None)
    local pos = 0
    repeat
        local aitem, bitem = anext(), bnext()
        pos = pos + 1
        if aitem ~= bitem then
            return false, string.format("at position %d, %s ~= %s", pos, aitem, bitem)
        end
    until not aitem
    return true
end

t1 = {1, {2, {3, {4, {5, None}}}}}
t2 = {{1,2}, {{3, 4}, 5}}
t3 = {{{1,2}, 3}, 4}

function compare_fringe(label, ta, tb)
    local equal, nonmatch = same_fringe(ta, tb)
    io.write(label .. ": ")
    if equal then
        print("same fringe")
    else
        print(nonmatch)
    end
end

compare_fringe("(t1, t2)", t1, t2)
compare_fringe("(t1, t3)", t1, t3)


Self-describing numbers

{{task}}There are several so-called "self-describing" or "self-descriptive" integers.

An integer is said to be "self-describing" if it has the property that, when digit positions are labeled 0 to N-1, the digit in each position is equal to the number of times that that digit appears in the number.

For example,   '''2020'''   is a four-digit self describing number:

*   position   0   has value   2   and there are two 0s in the number;
*   position   1   has value   0   and there are no 1s in the number;
*   position   2   has value   2   and there are two 2s;
*   position   3   has value   0   and there are zero 3s.

Self-describing numbers < 100.000.000  are:     1210,   2020,   21200,   3211000,   42101000.

;Task Description
# Write a function/routine/method/... that will check whether a given positive integer is self-describing.
# As an optional stretch goal - generate and display the set of self-describing numbers.

;Related tasks:
*   [[Fours is the number of letters in the ...]]
*   [[Look-and-say sequence]]
*   [[Number names]]
*   [[Self-referential sequence]]
*   [[Spelling of ordinal numbers]]

Solution:
function Is_self_describing( n )
    local s = tostring( n )

    local t = {}
    for i = 0, 9 do t[i] = 0 end

    for i = 1, s:len() do
	local idx = tonumber( s:sub(i,i) )
        t[idx] = t[idx] + 1
    end

    for i = 1, s:len() do
        if t[i-1] ~= tonumber( s:sub(i,i) ) then return false end
    end

    return true
end

for i = 1, 999999999 do
    print( Is_self_describing( i ) )
end


Semordnilap

A semordnilap is a word (or phrase) that spells a different word (or phrase) backward. "Semordnilap" is a word that itself is a semordnilap.

Example: ''lager'' and ''regal''

;Task
This task does not consider semordnilap phrases, only single words.
Using only words from this list, report the total number of unique semordnilap pairs, and print 5 examples.
Two matching semordnilaps, such as ''lager'' and ''regal'', should be counted as one unique pair.
(Note that the word "semordnilap" is not in the above dictionary.)

Solution:
#!/usr/bin/env lua
-- allow dictionary file and sample size to be specified on command line
local dictfile = arg[1] or "unixdict.txt"
local sample_size = arg[2] or 5;

-- read dictionary
local f = assert(io.open(dictfile, "r"))
local dict = {}
for line in f:lines() do
  dict[line] = line:reverse()
end
f:close()

-- find the semordnilaps
local semordnilaps = {}
for fwd, rev in pairs(dict) do
  if dict[rev] and fwd < rev then
    table.insert(semordnilaps, {fwd,rev})
  end
end

-- print the report
print("There are " .. #semordnilaps .. " semordnilaps in " .. dictfile .. ".  Here are " .. sample_size .. ":")

math.randomseed( os.time() )
for i = 1, sample_size do
  local j
  repeat
    j = math.random(1,#semordnilaps)
  until semordnilaps[j]
  local f, r = unpack(semordnilaps[j])
  semordnilaps[j] = nil
  print(f .. " -> " .. r)
end


Set consolidation

Given two sets of items then if any item is common to any set then the result of applying ''consolidation'' to those sets is a set of sets whose contents is:
*  The two input sets if no common item exists between the two input sets of items.
*  The single set that is the union of the two input sets if they share a common item.

Given N sets of items where N>2 then the result is the same as repeatedly replacing all combinations of two sets by their consolidation until no further consolidation between set pairs is possible.
If N<2 then consolidation has no strict meaning and the input can be returned.

;'''Example 1:'''
:Given the two sets {A,B} and {C,D} then there is no common element between the sets and the result is the same as the input.
;'''Example 2:'''
:Given the two sets {A,B} and {B,D} then there is a common element B between the sets and the result is the single set {B,D,A}.  (Note that order of items in a set is immaterial: {A,B,D} is the same as {B,D,A} and {D,A,B}, etc).
;'''Example 3:'''
:Given the three sets {A,B} and {C,D} and {D,B} then there is no common element between the sets {A,B} and {C,D} but the sets {A,B} and {D,B} do share a common element that consolidates to produce the result {B,D,A}. On examining this result with the remaining set, {C,D}, they share a common element and so consolidate to the final output of the single set {A,B,C,D}
;'''Example 4:'''
:The consolidation of the five sets:
::{H,I,K}, {A,B}, {C,D}, {D,B}, and {F,G,H}
:Is the two sets:
::{A, C, B, D}, and {G, F, I, H, K}

'''See also'''
* Connected component (graph theory)
* [[Range consolidation]]

Solution:
-- SUPPORT:
function T(t) return setmetatable(t, {__index=table}) end
function S(t) local s=T{} for k,v in ipairs(t) do s[v]=v end return s end
table.each = function(t,f,...) for _,v in pairs(t) do f(v,...) end end
table.copy = function(t) local s=T{} for k,v in pairs(t) do s[k]=v end return s end
table.keys = function(t) local s=T{} for k,_ in pairs(t) do s[#s+1]=k end return s end
table.intersects = function(t1,t2) for k,_ in pairs(t1) do if t2[k] then return true end end return false end
table.union = function(t1,t2) local s=t1:copy() for k,_ in pairs(t2) do s[k]=k end return s end
table.dump = function(t) print('{ '..table.concat(t, ', ')..' }') end

-- TASK:
table.consolidate = function(t)
  for a = #t, 1, -1 do
    local seta = t[a]
    for b = #t, a+1, -1 do
      local setb = t[b]
      if setb and seta:intersects(setb) then
        t[a], t[b] = seta:union(setb), nil
      end
    end
  end
  return t
end

-- TESTING:
examples = {
  T{ S{"A","B"}, S{"C","D"} },
  T{ S{"A","B"}, S{"B","D"} },
  T{ S{"A","B"}, S{"C","D"}, S{"D","B"} },
  T{ S{"H","I","K"}, S{"A","B"}, S{"C","D"}, S{"D","B"}, S{"F","G","H"} },
}
for i,example in ipairs(examples) do
  print("Given input sets:")
  example:each(function(set) set:keys():dump() end)
  print("Consolidated output sets:")
  example:consolidate():each(function(set) set:keys():dump() end)
  print("")
end


Set of real numbers

All real numbers form the uncountable set R.  Among its subsets, relatively simple are the convex sets, each expressed as a range between two real numbers ''a'' and ''b'' where ''a'' <= ''b''.  There are actually four cases for the meaning of "between", depending on open or closed boundary:
* [''a'', ''b'']: {''x'' | ''a'' <= ''x'' and ''x'' <= ''b'' }
* (''a'', ''b''): {''x'' | ''a'' < ''x'' and ''x'' < ''b'' }
* [''a'', ''b''): {''x'' | ''a'' <= ''x'' and ''x'' < ''b'' }
* (''a'', ''b'']: {''x'' | ''a'' < ''x'' and ''x'' <= ''b'' }
Note that if ''a'' = ''b'', of the four only [''a'', ''a''] would be non-empty.

'''Task'''
* Devise a way to represent any set of real numbers, for the definition of 'any' in the implementation notes below.
* Provide methods for these common set operations (''x'' is a real number; ''A'' and ''B'' are sets):
:* ''x''  ''A'': determine if ''x'' is an element of ''A''
:: example: 1 is in [1, 2), while 2, 3, ... are not.
:* ''A''  ''B'': union of ''A'' and ''B'', i.e. {''x'' | ''x''  ''A'' or ''x''  ''B''}
:: example: [0, 2)  (1, 3) = [0, 3); [0, 1)  (2, 3] = well, [0, 1)  (2, 3]
:* ''A''  ''B'': intersection of ''A'' and ''B'', i.e. {''x'' | ''x''  ''A'' and ''x''  ''B''}
:: example: [0, 2)  (1, 3) = (1, 2); [0, 1)  (2, 3] = empty set
:* ''A'' - ''B'': difference between ''A'' and ''B'', also written as ''A'' \ ''B'', i.e. {''x'' | ''x''  ''A'' and ''x''  ''B''}
:: example: [0, 2) - (1, 3) = [0, 1]
* Test your implementation by checking if numbers 0, 1, and 2 are in any of the following sets:
:* (0, 1]  [0, 2)
:* [0, 2)  (1, 2]
:* [0, 3) - (0, 1)
:* [0, 3) - [0, 1]

'''Implementation notes'''
* 'Any' real set means 'sets that can be expressed as the union of a finite number of convex real sets'.  Cantor's set needs not apply.
* Infinities should be handled gracefully; indeterminate numbers (NaN) can be ignored.
* You can use your machine's native real number representation, which is probably IEEE floating point, and assume it's good enough (it usually is).

'''Optional work'''
* Create a function to determine if a given set is empty (contains no element).
* Define ''A'' = {''x'' | 0 < ''x'' < 10 and |sin(p ''x''2)| > 1/2 }, ''B'' = {''x'' | 0 < ''x'' < 10 and |sin(p ''x'')| > 1/2}, calculate the length of the real axis covered by the set ''A'' - ''B''.  Note that
|sin(p ''x'')| > 1/2 is the same as ''n'' + 1/6 < ''x'' < ''n'' + 5/6 for all integers ''n''; your program does not need to derive this by itself.

Solution:
function createSet(low,high,rt)
    local l,h = tonumber(low), tonumber(high)
    if l and h then
        local t = {low=l, high=h}

        if type(rt) == "string" then
            if rt == "open" then
                t.contains = function(d) return low< d and d< high end
            elseif rt == "closed" then
                t.contains = function(d) return low<=d and d<=high end
            elseif rt == "left" then
                t.contains = function(d) return low< d and d<=high end
            elseif rt == "right" then
                t.contains = function(d) return low<=d and d< high end
            else
                error("Unknown range type: "..rt)
            end
        elseif type(rt) == "function" then
            t.contains = rt
        else
            error("Unable to find a range type or predicate")
        end

        t.union = function(o)
            local l2 = math.min(l, o.low)
            local h2 = math.min(h, o.high)
            local p = function(d) return t.contains(d) or o.contains(d) end
            return createSet(l2, h2, p)
        end

        t.intersect = function(o)
            local l2 = math.min(l, o.low)
            local h2 = math.min(h, o.high)
            local p = function(d) return t.contains(d) and o.contains(d) end
            return createSet(l2, h2, p)
        end

        t.subtract = function(o)
            local l2 = math.min(l, o.low)
            local h2 = math.min(h, o.high)
            local p = function(d) return t.contains(d) and not o.contains(d) end
            return createSet(l2, h2, p)
        end

        t.length = function()
            if h <= l then return 0.0 end
            local p = l
            local count = 0
            local interval = 0.00001
            repeat
                if t.contains(p) then count = count + 1 end
                p = p + interval
            until p>=high
            return count * interval
        end

        t.empty = function()
            if l == h then
                return not t.contains(low)
            end
            return t.length() == 0.0
        end

        return t
    else
        error("Either '"..low.."' or '"..high.."' is not a number")
    end
end

local a = createSet(0.0, 1.0, "left")
local b = createSet(0.0, 2.0, "right")
local c = createSet(1.0, 2.0, "left")
local d = createSet(0.0, 3.0, "right")
local e = createSet(0.0, 1.0, "open")
local f = createSet(0.0, 1.0, "closed")
local g = createSet(0.0, 0.0, "closed")

for i=0,2 do
    print("(0, 1]   union   [0, 2) contains "..i.." is "..tostring(a.union(b).contains(i)))
    print("[0, 2) intersect (1, 2] contains "..i.." is "..tostring(b.intersect(c).contains(i)))
    print("[0, 3)     -     (0, 1) contains "..i.." is "..tostring(d.subtract(e).contains(i)))
    print("[0, 3)     -     [0, 1] contains "..i.." is "..tostring(d.subtract(f).contains(i)))
    print()
end

print("[0, 0] is empty is "..tostring(g.empty()))
print()

local aa = createSet(
    0.0, 10.0,
    function(x) return (0.0<x and x<10.0) and math.abs(math.sin(math.pi * x * x)) > 0.5 end
)
local bb = createSet(
    0.0, 10.0,
    function(x) return (0.0<x and x<10.0) and math.abs(math.sin(math.pi * x)) > 0.5 end
)
local cc = aa.subtract(bb)
print("Approx length of A - B is "..cc.length())


Shoelace formula for polygonal area

Given the n + 1 vertices x[0], y[0] .. x[N], y[N] of a simple polygon described in a clockwise direction, then the polygon's area can be calculated by:

abs( (sum(x[0]*y[1] + ... x[n-1]*y[n]) + x[N]*y[0]) -
     (sum(x[1]*y[0] + ... x[n]*y[n-1]) + x[0]*y[N])
   ) / 2
(Where abs returns the absolute value)

;Task:
Write a function/method/routine to use the the Shoelace formula to calculate the area of the polygon described by the ordered points:
      (3,4), (5,11), (12,8), (9,5), and (5,6)

Show the answer here, on this page.

Solution:
function shoeArea(ps)
  local function ssum(acc, p1, p2, ...)
    if not p2 or not p1 then
      return math.abs(0.5 * acc)
    else
      return ssum(acc + p1[1]*p2[2]-p1[2]*p2[1], p2, ...)
    end
  end
  return ssum(0, ps[#ps], table.unpack(ps))
end

local p = {{3,4}, {5,11}, {12,8}, {9,5}, {5,6}}
print(shoeArea(p))-- 30


Show ASCII table

Show  the ASCII character set  from values   '''32'''   to   '''127'''   (decimal)   in a table format.

Solution:
-- map of character values to desired representation
local chars = setmetatable({[32] = "Spc", [127] = "Del"}, {__index = function(_, k) return string.char(k) end})

-- row iterator
local function iter(s,a)
  a = (a or s) + 16
  if a <= 127 then return a, chars[a] end
end

-- print loop
for i = 0, 15 do
   for j, repr in iter, i+16 do
      io.write(("%3d : %3s    "):format(j, repr))
   end
   io.write"\n"
end


Sierpinski pentagon

Produce a graphical or ASCII-art representation of a Sierpinski pentagon (aka a Pentaflake) of order 5. Your code should also be able to correctly generate representations of lower orders: 1 to 4.

;See also
* Sierpinski pentagon

Solution:
Bitmap.chaosgame = function(self, n, r, niters)
  local w, h, vertices = self.width, self.height, {}
  for i = 1, n do
    vertices[i] = {
      x = w/2 + w/2 * math.cos(math.pi/2+(i-1)*math.pi*2/n),
      y = h/2 - h/2 * math.sin(math.pi/2+(i-1)*math.pi*2/n)
    }
  end
  local x, y = w/2, h/2
  for i = 1, niters do
    local v = math.random(n)
    x = x + r * (vertices[v].x - x)
    y = y + r * (vertices[v].y - y)
    self:set(x,y,0xFFFFFFFF)
  end
end

local bitmap = Bitmap(128, 128)
bitmap:chaosgame(5, 1/((1+math.sqrt(5))/2), 1e6)
bitmap:render({[0x000000]='..', [0xFFFFFFFF]='██'})


Smith numbers

sum of the decimal digits of the integers that make up that number is the same as the sum of the decimal digits of its prime factors excluding 1.

By definition, all primes are ''excluded'' as they (naturally) satisfy this condition!

Smith numbers are also known as   ''joke''   numbers.

;Example
Using the number '''166'''
Find the prime factors of '''166''' which are: '''2''' x '''83'''
Then, take those two prime factors and sum all their decimal digits: '''2 + 8 + 3''' which is '''13'''
Then, take the decimal digits of '''166''' and add their decimal digits: '''1 + 6 + 6''' which is '''13'''
Therefore, the number '''166''' is a Smith number.

;Task
Write a program to find all Smith numbers ''below'' 10000.

;See also
* from Wikipedia:   [Smith number].
* from MathWorld:   [Smith number].
* from OEIS A6753:   [OEIS sequence A6753].
* from OEIS A104170:   [Number of Smith numbers below 10^n].
* from The Prime pages:   [Smith numbers].

Solution:
-- Returns a boolean indicating whether n is prime
function isPrime (n)
    if n < 2 then return false end
    if n < 4 then return true end
    if n % 2 == 0 then return false end
    for d = 3, math.sqrt(n), 2 do
        if n % d == 0 then return false end
    end
    return true
end

-- Returns a table of the prime factors of n
function primeFactors (n)
    local pfacs, divisor = {}, 1
    if n < 1 then return pfacs end
    while not isPrime(n) do
        while not isPrime(divisor) do divisor = divisor + 1 end
        while n % divisor == 0 do
            n = n / divisor
            table.insert(pfacs, divisor)
        end
        divisor = divisor + 1
        if n == 1 then return pfacs end
    end
    table.insert(pfacs, n)
    return pfacs
end

-- Returns the sum of the digits of n
function sumDigits (n)
    local sum, nStr = 0, tostring(n)
    for digit = 1, nStr:len() do
        sum = sum + tonumber(nStr:sub(digit, digit))
    end
    return sum
end

-- Returns a boolean indicating whether n is a Smith number
function isSmith (n)
    if isPrime(n) then return false end
    local sumFacs = 0
    for _, v in ipairs(primeFactors(n)) do
        sumFacs = sumFacs + sumDigits(v)
    end
    return sumFacs == sumDigits(n)
end

-- Main procedure
for n = 1, 10000 do
    if isSmith(n) then io.write(n .. "\t") end
end


Solve a Holy Knight's tour

Chess coaches have been known to inflict a kind of torture on beginners by taking a chess board, placing pennies on some squares and requiring that a Knight's tour be constructed that avoids the squares with pennies.

This kind of knight's tour puzzle is similar to   Hidato.

The present task is to produce a solution to such problems. At least demonstrate your program by solving the following:

;Example:

  0 0 0
  0   0 0
  0 0 0 0 0 0 0
0 0 0     0   0
0   0     0 0 0
1 0 0 0 0 0 0
    0 0   0
      0 0 0

Note that the zeros represent the available squares, not the pennies.

Extra credit is available for other interesting examples.

;Related tasks:
* [[A* search algorithm]]
* [[Knight's tour]]
* [[N-queens problem]]
* [[Solve a Hidato puzzle]]
* [[Solve a Hopido puzzle]]
* [[Solve a Numbrix puzzle]]
* [[Solve the no connection puzzle]]

Solution:
local p1, p1W = ".xxx.....x.xx....xxxxxxxxxx..x.xx.x..xxxsxxxxxx...xx.x.....xxx..", 8
local p2, p2W = ".....s.x..........x.x.........xxxxx.........xxx.......x..x.x..x..xxxxx...xxxxx..xx.....xx..xxxxx...xxxxx..x..x.x..x.......xxx.........xxxxx.........x.x..........x.x.....", 13
local puzzle, movesCnt, wid = {}, 0, 0
local moves = { { -1, -2 }, {  1, -2 }, { -1,  2 }, {  1,  2 },
                { -2, -1 }, { -2,  1 }, {  2, -1 }, {  2,  1 } }

function isValid( x, y )
    return( x > 0 and x <= wid and y > 0 and y <= wid and puzzle[x + y * wid - wid] == 0 )
end
function solve( x, y, s )
    if s > movesCnt then return true end
    local test, a, b
    for i = 1, #moves do
        test = false
        a = x + moves[i][1]; b = y + moves[i][2]
        if isValid( a, b ) then
            puzzle[a + b * wid - wid] = s
            if solve( a, b, s + 1 ) then return true end
            puzzle[a + b * wid - wid] = 0
        end
    end
    return false
end
function printSolution()
    local lp
    for j = 1, wid do
        for i = 1, wid do
            lp = puzzle[i + j * wid - wid]
            if lp == -1 then io.write( "   " )
            else io.write( string.format( " %.2d", lp ) )
            end
        end
        print()
    end
    print( "\n" )
end
local sx, sy
function fill( pz, w )
    puzzle = {}; wid = w; movesCnt = #pz
    local lp
    for i = 1, #pz do
        lp = pz:sub( i, i )
        if lp == "x" then
            table.insert( puzzle, 0 )
        elseif lp == "." then
            table.insert( puzzle, -1 ); movesCnt = movesCnt - 1
        else
            table.insert( puzzle, 1 )
            sx = 1 + ( i - 1 ) % wid; sy = math.floor( ( i + wid - 1 ) / wid )
        end
    end
end
-- [[ entry point ]] --
print( "\n\n" ); fill( p1, p1W );
if solve( sx, sy, 2 ) then printSolution() end
print( "\n\n" ); fill( p2, p2W );
if solve( sx, sy, 2 ) then printSolution() end


Split a character string based on change of character

Split a (character) string into comma (plus a blank) delimited
strings based on a change of character   (left to right).

Show the output here   (use the 1st example below).

Blanks should be treated as any other character   (except
they are problematic to display clearly).   The same applies
to commas.

For instance, the string:
  gHHH5YY++///\
should be split and show:
  g, HHH, 5, YY, ++, ///, \

Solution:
function charSplit (inStr)
    local outStr, nextChar = inStr:sub(1, 1)
    for pos = 2, #inStr do
        nextChar = inStr:sub(pos, pos)
        if nextChar ~= outStr:sub(#outStr, #outStr) then
            outStr = outStr .. ", "
        end
        outStr = outStr .. nextChar
    end
    return outStr
end

print(charSplit("gHHH5YY++///\\"))


Square-free integers

Write a function to test if a number is   ''square-free''.

A   ''square-free''   is an integer which is divisible by no perfect square other
than   '''1'''   (unity).

For this task, only positive square-free numbers will be used.

Show here (on this page) all square-free integers (in a horizontal format) that are between:
::*   '''1'''            --->   '''145'''                        (inclusive)
::*   '''1''' trillion   --->   '''1''' trillion + '''145'''     (inclusive)

(One trillion = 1,000,000,000,000)

Show here (on this page) the count of square-free integers from:
::*   '''1'''            --->   one hundred                      (inclusive)
::*   '''1'''            --->   one thousand                     (inclusive)
::*   '''1'''            --->   ten thousand                     (inclusive)
::*   '''1'''            --->   one hundred thousand             (inclusive)
::*   '''1'''            --->   one million                      (inclusive)

;See also:
:*   the Wikipedia entry:   square-free integer

Solution:
function squareFree (n)
  for root = 2, math.sqrt(n) do
    if n % (root * root) == 0 then return false end
  end
  return true
end

function run (lo, hi, showValues)
  io.write("From " .. lo .. " to " .. hi)
  io.write(showValues and ":\n" or " = ")
  local count = 0
  for i = lo, hi do
    if squareFree(i) then
      if showValues then
        io.write(i, "\t")
      else
        count = count + 1
      end
    end
  end
  print(showValues and "\n" or count)
end

local testCases = {
  {1, 145, true},
  {1000000000000, 1000000000145, true},
  {1, 100},
  {1, 1000},
  {1, 10000},
  {1, 100000},
  {1, 1000000}
}
for _, example in pairs(testCases) do run(unpack(example)) end


Square but not cube

Show the first   '''30'''   positive integers which are squares but not cubes of such integers.

Optionally, show also the first   '''3'''   positive integers which are both squares and cubes,   and mark them as such.

Solution:
function nthroot (x, n)
  local r = 1
  for i = 1, 16 do
    r = (((n - 1) * r) + x / (r ^ (n - 1))) / n
  end
  return r
end

local i, count, sq, cbrt = 0, 0
while count < 30 do
  i = i + 1
  sq = i * i
  -- The next line should say nthroot(sq, 3), right? But this works. Maths, eh?
  cbrt = nthroot(i, 3)
  if cbrt == math.floor(cbrt) then
    print(sq .. " is square and cube")
  else
    print(sq)
    count = count + 1
  end
end


Stair-climbing puzzle

From Chung-Chieh Shan (LtU):

Your stair-climbing robot has a very simple low-level API: the "step" function takes no argument and attempts to climb one step as a side effect. Unfortunately, sometimes the attempt fails and the robot clumsily falls one step instead. The "step" function detects what happens and returns a boolean flag: true on success, false on failure.

Write a function "step_up" that climbs one step up [from the initial position] (by repeating "step" attempts if necessary). Assume that the robot is not already at the top of the stairs, and neither does it ever reach the bottom of the stairs. How small can you make "step_up"? Can you avoid using variables (even immutable ones) and numbers?

Here's a pseudo-code of a simple recursive solution without using variables:

func step_up()
{
    if not step() {
        step_up();
        step_up();
    }
}

Inductive proof that step_up() steps up one step, if it terminates:
* Base case (if the step() call returns true): it stepped up one step. QED
* Inductive case (if the step() call returns false): Assume that recursive calls to step_up() step up one step. It stepped down one step (because step() returned false), but now we step up two steps using two step_up() calls. QED

The second (tail) recursion above can be turned into an iteration, as follows:

func step_up()
{
    while not step() {
        step_up();
    }
}

Solution:
function step_up()
    while not step() do step_up() end
end


Statistics/Normal distribution

The derive normally distributed random numbers from a uniform generator.

;The task:
# Take a uniform random number generator and create a large (you decide how large) set of numbers that follow a normal (Gaussian) distribution.  Calculate the dataset's mean and standard deviation, and show a histogram of the data.
# Mention any native language support for the generation of normally distributed random numbers.

;Reference:
* You may refer to code in [[Statistics/Basic]] if available.

Solution:
function gaussian (mean, variance)
    return  math.sqrt(-2 * variance * math.log(math.random())) *
            math.cos(2 * math.pi * math.random()) + mean
end

function mean (t)
    local sum = 0
    for k, v in pairs(t) do
        sum = sum + v
    end
    return sum / #t
end

function std (t)
    local squares, avg = 0, mean(t)
    for k, v in pairs(t) do
        squares = squares + ((avg - v) ^ 2)
    end
    local variance = squares / #t
    return math.sqrt(variance)
end

function showHistogram (t)
    local lo = math.ceil(math.min(unpack(t)))
    local hi = math.floor(math.max(unpack(t)))
    local hist, barScale = {}, 200
    for i = lo, hi do
        hist[i] = 0
        for k, v in pairs(t) do
            if math.ceil(v - 0.5) == i then
                hist[i] = hist[i] + 1
            end
        end
        io.write(i .. "\t" .. string.rep('=', hist[i] / #t * barScale))
        print(" " .. hist[i])
    end
end

math.randomseed(os.time())
local t, average, variance = {}, 50, 10
for i = 1, 1000 do
    table.insert(t, gaussian(average, variance))
end
print("Mean:", mean(t) .. ", expected " .. average)
print("StdDev:", std(t) .. ", expected " .. math.sqrt(variance) .. "\n")
showHistogram(t)


Stern-Brocot sequence

For this task, the Stern-Brocot sequence is to be generated by an algorithm similar to that employed in generating the [[Fibonacci sequence]].

# The first and second members of the sequence are both 1:
#*     1, 1
# Start by considering the second member of the sequence
# Sum the considered member of the sequence and its precedent, (1 + 1) = 2, and append it to the end of the sequence:
#*     1, 1, 2
# Append the considered member of the sequence to the end of the sequence:
#*     1, 1, 2, 1
# Consider the next member of the series, (the third member i.e. 2)
# GOTO 3
#*
#*         --- Expanding another loop we get: ---
#*
# Sum the considered member of the sequence and its precedent, (2 + 1) = 3, and append it to the end of the sequence:
#*     1, 1, 2, 1, 3
# Append the considered member of the sequence to the end of the sequence:
#*     1, 1, 2, 1, 3, 2
# Consider the next member of the series, (the fourth member i.e. 1)

;The task is to:
* Create a function/method/subroutine/procedure/... to generate the Stern-Brocot sequence of integers using the method outlined above.
* Show the first fifteen members of the sequence. (This should be: 1, 1, 2, 1, 3, 2, 3, 1, 4, 3, 5, 2, 5, 3, 4)
* Show the (1-based) index of where the numbers 1-to-10 first appear in the sequence.
* Show the (1-based) index of where the number 100 first appears in the sequence.
* Check that the greatest common divisor of all the two consecutive members of the series up to the 1000th member, is always one.

Show your output on this page.

;Related tasks:
:*   [[Fusc sequence]].
:*   [[Continued fraction/Arithmetic]]

;Ref:
* Infinite Fractions - Numberphile (Video).
* Trees, Teeth, and Time: The mathematics of clock making.
* A002487 The On-Line Encyclopedia of Integer Sequences.

Solution:
-- Task 1
function sternBrocot (n)
    local sbList, pos, c = {1, 1}, 2
    repeat
        c = sbList[pos]
        table.insert(sbList, c + sbList[pos - 1])
        table.insert(sbList, c)
        pos = pos + 1
    until #sbList >= n
    return sbList
end

-- Return index in table 't' of first value matching 'v'
function findFirst (t, v)
    for key, value in pairs(t) do
        if v then
            if value == v then return key end
        else
            if value ~= 0 then return key end
        end
    end
    return nil
end

-- Return greatest common divisor of 'x' and 'y'
function gcd (x, y)
    if y == 0 then
        return math.abs(x)
    else
        return gcd(y, x % y)
    end
end

-- Check GCD of adjacent values in 't' up to 1000 is always 1
function task5 (t)
    for pos = 1, 1000 do
        if gcd(t[pos], t[pos + 1]) ~= 1 then return "FAIL" end
    end
    return "PASS"
end

-- Main procedure
local sb = sternBrocot(10000)
io.write("Task 2: ")
for n = 1, 15 do io.write(sb[n] .. " ") end
print("\n\nTask 3:")
for i = 1, 10 do print("\t" .. i, findFirst(sb, i)) end
print("\nTask 4: " .. findFirst(sb, 100))
print("\nTask 5: " .. task5(sb))


Strip control codes and extended characters from a string.

The solution should demonstrate how to achieve each of the following results:
:*   a string with control codes stripped (but extended characters not stripped)
:*   a string with control codes and extended characters stripped

In ASCII, the control codes have decimal codes 0 through to 31 and 127.

On an ASCII based system, if the control codes are stripped, the resultant string would have all of its characters within the range of 32 to 126 decimal on the ASCII table.

On a non-ASCII based system, we consider characters that do not have a corresponding glyph on the ASCII table (within the ASCII range of 32 to 126 decimal) to be an extended character for the purpose of this task.

Solution:
function Strip_Control_Codes( str )
    local s = ""
    for i in str:gmatch( "%C+" ) do
 	s = s .. i
    end
    return s
end

function Strip_Control_and_Extended_Codes( str )
    local s = ""
    for i = 1, str:len() do
	if str:byte(i) >= 32 and str:byte(i) <= 126 then
  	    s = s .. str:sub(i,i)
	end
    end
    return s
end

q = ""
for i = 0, 255 do
	q = q .. string.char(i)
end

print( Strip_Control_Codes(q) )
print( Strip_Control_and_Extended_Codes(q) )


Subleq

One-Instruction Set Computer (OISC).

It is named after its only instruction, which is '''SU'''btract and '''B'''ranch if '''L'''ess than or '''EQ'''ual to zero.

;Task
Your task is to create an interpreter which emulates a SUBLEQ machine.

The machine's memory consists of an array of signed integers.   These integers may be interpreted in three ways:
::::*   simple numeric values
::::*   memory addresses
::::*   characters for input or output

Any reasonable word size that accommodates all three of the above uses is fine.

The program should load the initial contents of the emulated machine's memory, set the instruction pointer to the first address (which is defined to be address 0), and begin emulating the machine, which works as follows:
:#   Let '''A''' be the value in the memory location identified by the instruction pointer;   let '''B''' and '''C''' be the values stored in the next two consecutive addresses in memory.
:#   Advance the instruction pointer three words, to point at the address ''after'' the address containing '''C'''.
:#   If '''A''' is   '''-1'''   (negative unity),   then a character is read from the machine's input and its numeric value stored in the address given by '''B'''.   '''C''' is unused.
:#   If '''B''' is   '''-1'''   (negative unity),   then the number contained in the address given by '''A''' is interpreted as a character and written to the machine's output.   '''C''' is unused.
:#   Otherwise, both '''A''' and '''B''' are treated as addresses.   The number contained in address '''A''' is subtracted from the number in address '''B''' (and the difference left in address '''B''').   If the result is positive, execution continues uninterrupted; if the result is zero or negative, the number in '''C''' becomes the new instruction pointer.
:#   If the instruction pointer becomes negative, execution halts.

Your solution may initialize the emulated machine's memory in any convenient manner, but if you accept it as input, it should be a separate input stream from the one fed to the emulated machine once it is running. And if fed as text input, it should be in the form of raw subleq "machine code" - whitespace-separated decimal numbers, with no symbolic names or other assembly-level extensions, to be loaded into memory starting at address   '''0'''   (zero).

For purposes of this task, show the output of your solution when fed the below   "Hello, world!"   program.

As written, this example assumes ASCII or a superset of it, such as any of the Latin-N character sets or Unicode;   you may translate the numbers representing characters (starting with 72=ASCII 'H') into another character set if your implementation runs in a non-ASCII-compatible environment. If 0 is not an appropriate terminator in your character set, the program logic will need some adjustment as well.

15 17 -1 17 -1 -1 16 1 -1 16 3 -1 15 15 0 0 -1 72 101 108 108 111 44 32 119 111 114 108 100 33 10 0

The above "machine code" corresponds to something like this in a hypothetical assembler language for a signed 8-bit version of the machine:

start:
    0f 11 ff subleq (zero), (message), -1
    11 ff ff subleq (message), -1, -1    ; output character at message
    10 01 ff subleq (neg1), (start+1), -1
    10 03 ff subleq (neg1), (start+3), -1
    0f 0f 00 subleq (zero), (zero), start
; useful constants
zero:
    00      .data 0
neg1:
    ff      .data -1
; the message to print
message: .data "Hello, world!\n\0"
    48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0a 00

Solution:
function subleq (prog)
    local mem, p, A, B, C = {}, 0
    for word in prog:gmatch("%S+") do
        mem[p] = tonumber(word)
        p = p + 1
    end
    p = 0
    repeat
        A, B, C = mem[p], mem[p + 1], mem[p + 2]
        if A == -1 then
            mem[B] = io.read()
        elseif B == -1 then
            io.write(string.char(mem[A]))
        else
            mem[B] = mem[B] - mem[A]
            if mem[B] <= 0 then p = C end
        end
        p = p + 3
    until not mem[mem[p]]
end

subleq("15 17 -1 17 -1 -1 16 1 -1 16 3 -1 15 15 0 0 -1 72 101 108 108 111 44 32 119 111 114 108 100 33 10 0")


Substring/Top and tail

The task is to demonstrate how to remove the first and last characters from a string.

The solution should demonstrate how to obtain the following results:

* String with first character removed
* String with last character removed
* String with both the first and last characters removed

If the program uses UTF-8 or UTF-16, it must work on any valid Unicode code point, whether in the Basic Multilingual Plane or above it.

The program must reference logical characters (code points), not 8-bit code units for UTF-8 or 16-bit code units for UTF-16.

Programs for other encodings (such as 8-bit ASCII, or EUC-JP) are not required to handle all Unicode characters.

Solution:
print (string.sub("knights",2))    -- remove the first character
print (string.sub("knights",1,-2))    -- remove the last character
print (string.sub("knights",2,-2))    -- remove the first and last characters


Sum and product puzzle

Solution:
function print_count(t)
    local cnt = 0
    for k,v in pairs(t) do
        cnt = cnt + 1
    end
    print(cnt .. ' candidates')
end

function make_pair(a,b)
    local t = {}
    table.insert(t, a) -- 1
    table.insert(t, b) -- 2
    return t
end

function setup()
    local candidates = {}
    for x = 2, 98 do
        for y = x + 1, 98 do
            if x + y <= 100 then
                local p = make_pair(x, y)
                table.insert(candidates, p)
            end
        end
    end
    return candidates
end

function remove_by_sum(candidates, sum)
    for k,v in pairs(candidates) do
        local s = v[1] + v[2]
        if s == sum then
            table.remove(candidates, k)
        end
    end
end

function remove_by_prod(candidates, prod)
    for k,v in pairs(candidates) do
        local p = v[1] * v[2]
        if p == prod then
            table.remove(candidates, k)
        end
    end
end

function statement1(candidates)
    local unique = {}
    for k,v in pairs(candidates) do
        local prod = v[1] * v[2]
        if unique[prod] ~= nil then
            unique[prod] = unique[prod] + 1
        else
            unique[prod] = 1
        end
    end

    local done
    repeat
        done = true
        for k,v in pairs(candidates) do
            local prod = v[1] * v[2]
            if unique[prod] == 1 then
                local sum = v[1] + v[2]
                remove_by_sum(candidates, sum)
                done = false
                break
            end
        end
    until done
end

function statement2(candidates)
    local unique = {}
    for k,v in pairs(candidates) do
        local prod = v[1] * v[2]
        if unique[prod] ~= nil then
            unique[prod] = unique[prod] + 1
        else
            unique[prod] = 1
        end
    end

    local done
    repeat
        done = true
        for k,v in pairs(candidates) do
            local prod = v[1] * v[2]
            if unique[prod] > 1 then
                remove_by_prod(candidates, prod)
                done = false
                break
            end
        end
    until done
end

function statement3(candidates)
    local unique = {}
    for k,v in pairs(candidates) do
        local sum = v[1] + v[2]
        if unique[sum] ~= nil then
            unique[sum] = unique[sum] + 1
        else
            unique[sum] = 1
        end
    end

    local done
    repeat
        done = true
        for k,v in pairs(candidates) do
            local sum = v[1] + v[2]
            if unique[sum] > 1 then
                remove_by_sum(candidates, sum)
                done = false
                break
            end
        end
    until done
end

function main()
    local candidates = setup()
    print_count(candidates)

    statement1(candidates)
    print_count(candidates)

    statement2(candidates)
    print_count(candidates)

    statement3(candidates)
    print_count(candidates)

    for k,v in pairs(candidates) do
        local sum = v[1] + v[2]
        local prod = v[1] * v[2]
        print("a=" .. v[1] .. ", b=" .. v[2] .. "; S=" .. sum .. ", P=" .. prod)
    end
end

main()


Sum digits of an integer

Take a   Natural Number   in a given base and return the sum of its digits:
:*   '''1'''10                  sums to   '''1'''
:*   '''1234'''10       sums to   '''10'''
:*   '''fe'''16              sums to   '''29'''
:*   '''f0e'''16           sums to   '''29'''

Solution:
function sum_digits(n, base)
    sum = 0
    while n > 0.5 do
        m = math.floor(n / base)
        digit = n - m * base
        sum = sum + digit
        n = m
    end
    return sum
end

print(sum_digits(1, 10))
print(sum_digits(1234, 10))
print(sum_digits(0xfe, 16))
print(sum_digits(0xf0e, 16))


Sum multiples of 3 and 5

The objective is to write a function that finds the sum of all positive multiples of 3 or 5 below ''n''.

Show output for ''n'' = 1000.

This is is the same as Project Euler problem 1.

'''Extra credit:''' do this efficiently for ''n'' = 1e20 or higher.

Solution:
function tri (n) return n * (n + 1) / 2 end

function sum35 (n)
	n = n - 1
	return	(	3 * tri(math.floor(n / 3)) +
			5 * tri(math.floor(n / 5)) -
			15 * tri(math.floor(n / 15))
		)
end

print(sum35(1000))
print(sum35(1e+20))


Sum to 100

Find solutions to the    ''sum to one hundred''    puzzle.

Add (insert) the mathematical
operators      '''+'''    or    '''-'''      (plus
or minus)   before any of the digits in the
decimal numeric string    '''123456789'''    such that the
resulting mathematical expression adds up to a
particular sum    (in this iconic case,   '''100''').

Example:
              123 + 4 - 5 + 67 - 89   =   100

Show all output here.

:*   Show all solutions that sum to    '''100'''
:*   Show the sum that has the maximum   ''number''   of solutions   (from zero to infinity++)
:*   Show the lowest positive sum that   ''can't''   be expressed   (has no solutions),   using the rules for this task
:*   Show the ten highest numbers that can be expressed using the rules for this task   (extra credit)

++   (where   ''infinity''   would be a relatively small   123,456,789)

An example of a sum that can't be expressed   (within the rules of this task)   is:   '''5074'''
(which,   of course,   isn't the lowest positive sum that can't be expressed).

Solution:
local expressionsLength = 0
function compareExpressionBySum(a, b)
    return a.sum - b.sum
end

local countSumsLength = 0
function compareCountSumsByCount(a, b)
    return a.counts - b.counts
end

function evaluate(code)
    local value = 0
    local number = 0
    local power = 1
    for k=9,1,-1 do
        number = power*k + number
        local mod = code % 3
        if mod == 0 then
            -- ADD
            value = value + number
            number = 0
            power = 1
        elseif mod == 1 then
            -- SUB
            value = value - number
            number = 0
            power = 1
        elseif mod == 2 then
            -- JOIN
            power = 10 * power
        else
            print("This should not happen.")
        end
        code = math.floor(code / 3)
    end
    return value
end

function printCode(code)
    local a = 19683
    local b = 6561
    local s = ""
    for k=1,9 do
        local temp = math.floor((code % a) / b)
        if temp == 0 then
            -- ADD
            if k>1 then
                s = s .. '+'
            end
        elseif temp == 1 then
            -- SUB
            s = s .. '-'
        end
        a = b
        b = math.floor(b/3)
        s = s .. tostring(k)
    end
    print("\t"..evaluate(code).." = "..s)
end

-- Main
local nexpr = 13122

print("Show all solutions that sum to 100")
for i=0,nexpr-1 do
    if evaluate(i) == 100 then
        printCode(i)
    end
end
print()

print("Show the sum that has the maximum number of solutions")
local nbest = -1
for i=0,nexpr-1 do
    local test = evaluate(i)
    if test>0 then
        local ntest = 0
        for j=0,nexpr-1 do
            if evaluate(j) == test then
                ntest = ntest + 1
            end
            if ntest > nbest then
                best = test
                nbest = ntest
            end
        end
    end
end
print(best.." has "..nbest.." solutions\n")

print("Show the lowest positive number that can't be expressed")
local code = -1
for i=0,123456789 do
    for j=0,nexpr-1 do
        if evaluate(j) == i then
            code = j
            break
        end
    end
    if evaluate(code) ~= i then
        code = i
        break
    end
end
print(code.."\n")

print("Show the ten highest numbers that can be expressed")
local limit = 123456789 + 1
for i=1,10 do
    local best=0
    for j=0,nexpr-1 do
        local test = evaluate(j)
        if (test<limit) and (test>best) then
            best = test
        end
    end
    for j=0,nexpr-1 do
        if evaluate(j) == best then
            printCode(j)
        end
    end
    limit = best
end


Summarize and say sequence

There are several ways to generate a self-referential sequence. One very common one (the [[Look-and-say sequence]]) is to start with a positive integer, then generate the next term by concatenating enumerated groups of adjacent alike digits:
        0, 10, 1110, 3110, 132110, 1113122110, 311311222110 ...
The terms generated grow in length geometrically and never converge.

Another way to generate a self-referential sequence is to summarize the previous term.

Count how many of each alike digit there is, then concatenate the sum and digit for each of the sorted enumerated digits. Note that the first five terms are the same as for the previous sequence.
        0, 10, 1110, 3110, 132110, 13123110, 23124110 ...
Sort the digits largest to smallest. Do not include counts of digits that do not appear in the previous term.

Depending on the seed value, series generated this way always either converge to a stable value or to a short cyclical pattern. (For our purposes, I'll use converge to mean an element matches a previously seen element.) The sequence shown, with a seed value of 0, converges to a stable value of 1433223110 after 11 iterations. The seed value that converges most quickly is 22. It goes stable after the first element. (The next element is 22, which has been seen before.)

;Task:
Find all the positive integer seed values under 1000000, for the above convergent self-referential sequence, that takes the largest number of iterations before converging. Then print out the number of iterations and the sequence they return. Note that different permutations of the digits of the seed will yield the same sequence. For this task, assume leading zeros are not permitted.

Seed Value(s): 9009 9090 9900

Iterations: 21

Sequence: (same for all three seeds except for first element)
9009
2920
192210
19222110
19323110
1923123110
1923224110
191413323110
191433125110
19151423125110
19251413226110
1916151413325110
1916251423127110
191716151413326110
191726151423128110
19181716151413327110
19182716151423129110
29181716151413328110
19281716151423228110
19281716151413427110
19182716152413228110

;Related tasks:
*   [[Fours is the number of letters in the ...]]
*   [[Look-and-say sequence]]
*   [[Number names]]
*   [[Self-describing numbers]]
*   [[Spelling of ordinal numbers]]

;Also see:
*   The On-Line Encyclopedia of Integer Sequences.

Solution:
-- Return the next term in the self-referential sequence
function findNext (nStr)
    local nTab, outStr, pos, count = {}, "", 1, 1
    for i = 1, #nStr do nTab[i] = nStr:sub(i, i) end
    table.sort(nTab, function (a, b) return a > b end)
    while pos <= #nTab do
        if nTab[pos] == nTab[pos + 1] then
            count = count + 1
        else
            outStr = outStr .. count .. nTab[pos]
            count = 1
        end
        pos = pos + 1
    end
    return outStr
end

-- Return boolean indicating whether table t contains string s
function contains (t, s)
    for k, v in pairs(t) do
        if v == s then return true end
    end
    return false
end

-- Return the sequence generated by the given seed term
function buildSeq (term)
    local sequence = {}
    repeat
        table.insert(sequence, term)
        if not nextTerm[term] then nextTerm[term] = findNext(term) end
        term = nextTerm[term]
    until contains(sequence, term)
    return sequence
end

-- Main procedure
nextTerm = {}
local highest, seq, hiSeq = 0
for i = 1, 10^6 do
    seq = buildSeq(tostring(i))
    if #seq > highest then
        highest = #seq
        hiSeq = {seq}
    elseif #seq == highest then
        table.insert(hiSeq, seq)
    end
end
io.write("Seed values: ")
for _, v in pairs(hiSeq) do io.write(v[1] .. " ") end
print("\n\nIterations: " .. highest)
print("\nSample sequence:")
for _, v in pairs(hiSeq[1]) do print(v) end


Superellipse

A superellipse is a geometric figure defined as the set of all points (x, y) with

::: \left|\frac{x}{a}\right|^n\! + \left|\frac{y}{b}\right|^n\! = 1,

where ''n'', ''a'', and ''b'' are positive numbers.

;Task
Draw a superellipse with n = 2.5, and a = b = 200

Solution:
local abs,cos,floor,pi,pow,sin = math.abs,math.cos,math.floor,math.pi,math.pow,math.sin
local bitmap = {
  init = function(self, w, h, value)
    self.w, self.h, self.pixels = w, h, {}
    for y=1,h do self.pixels[y]={} end
    self:clear(value)
  end,
  clear = function(self, value)
    for y=1,self.h do
      for x=1,self.w do
        self.pixels[y][x] = value or "  "
      end
    end
  end,
  set = function(self, x, y, value)
    x,y = floor(x+0.5),floor(y+0.5)
    if x>0 and y>0 and x<=self.w and y<=self.h then
      self.pixels[y][x] = value or "#"
    end
  end,
  superellipse = function(self, ox, oy, n, a, b, c)
    local function sgn(n) return n>=0 and 1 or -1 end
    for t = 0, 1, 0.002 do
      local theta = t * 2 * pi
      local x = ox + a * pow(abs(cos(theta)), 2/n) * sgn(cos(theta))
      local y = oy + b * pow(abs(sin(theta)), 2/n) * sgn(sin(theta))
      self:set(x, y, c)
    end
  end,
  render = function(self)
    for y=1,self.h do
      print(table.concat(self.pixels[y]))
    end
  end,
}

bitmap:init(80, 60, "..")
bitmap:superellipse(40, 30, 2.5, 38, 28, "[]")
bitmap:render()


Tau function

Given a positive integer, count the number of its positive divisors.

;Task
Show the result for the first   '''100'''   positive integers.

;Related task
*  [[Tau number]]

Solution:
function divisorCount(n)
    local total = 1
    -- Deal with powers of 2 first
    while (n & 1) == 0 do
        total = total + 1
        n = math.floor(n / 2)
    end
    -- Odd prime factors up tot eh square root
    local p = 3
    while p * p <= n do
        local count = 1
        while n % p == 0 do
            count = count + 1
            n = n / p
        end
        total = total * count
        p = p + 2
    end
    -- If n > 1 then it's prime
    if n > 1 then
        total = total * 2
    end
    return total
end

limit = 100
print("Count of divisors for the first " .. limit .. " positive integers:")
for n=1,limit do
    io.write(string.format("%3d", divisorCount(n)))
    if n % 20 == 0 then
        print()
    end
end


Temperature conversion

There are quite a number of temperature scales. For this task we will concentrate on four of the perhaps best-known ones:
Rankine.

The Celsius and Kelvin scales have the same magnitude, but different null points.

: 0 degrees Celsius corresponds to 273.15 kelvin.
: 0 kelvin is absolute zero.

The Fahrenheit and Rankine scales also have the same magnitude, but different null points.

: 0 degrees Fahrenheit corresponds to 459.67 degrees Rankine.
: 0 degrees Rankine is absolute zero.

The Celsius/Kelvin and Fahrenheit/Rankine scales have a ratio of 5 : 9.

;Task
Write code that accepts a value of kelvin, converts it to values of the three other scales, and prints the result.

;Example:

K  21.00

C  -252.15

F  -421.87

R  37.80

Solution:
function convert_temp(k)
    local c = k - 273.15
    local r = k * 1.8
    local f = r - 459.67
    return k, c, r, f
end

print(string.format([[
Kelvin: %.2f K
Celcius: %.2f °C
Rankine: %.2f °R
Fahrenheit: %.2f °F
]],convert_temp(21.0)))


Terminal control/Coloured text

Display a word in various colours on the terminal.

The system palette, or colours such as Red, Green, Blue, Magenta, Cyan, and Yellow can be used.

Optionally demonstrate:
* How the system should determine if the terminal supports colour
* Setting of the background colour
* How to cause blinking or flashing (if supported by the terminal)

Solution:
print("Normal \027[1mBold\027[0m \027[4mUnderline\027[0m \027[7mInverse\027[0m")
colors = { 30,31,32,33,34,35,36,37,90,91,92,93,94,95,96,97 }
for _,bg in ipairs(colors) do
  for _,fg in ipairs(colors) do
    io.write("\027["..fg..";"..(bg+10).."mX")
  end
  print("\027[0m") -- be nice, reset
end


Test integerness

{| class="wikitable"
|-
! colspan=2 | Input
! colspan=2 | Output
! rowspan=2 | Comment
|-
! Type
! Value
! exact
! tolerance = 0.00001
|-
| rowspan=3 | decimal
| 25.000000
| colspan=2 | true
|
|-
| 24.999999
| false
| true
|
|-
| 25.000100
| colspan=2 | false
|
|-
| rowspan=4 | floating-point
| -2.1e120
| colspan=2 | true
| This one is tricky, because in most languages it is too large to fit into a native integer type.It is, nonetheless, mathematically an integer, and your code should identify it as such.
|-
| -5e-2
| colspan=2 | false
|
|-
| NaN
| colspan=2 | false
|
|-
| Inf
| colspan=2 | false
| This one is debatable. If your code considers it an integer, that's okay too.
|-
| rowspan=2 | complex
| 5.0+0.0i
| colspan=2 | true
|
|-
| 5-5i
| colspan=2 | false
|
|}

(The types and notations shown in these tables are merely examples - you should use the native data types and number literals of your programming language and standard library. Use a different set of test-cases, if this one doesn't demonstrate all relevant behavior.)

Solution:
function isInt (x) return type(x) == "number" and x == math.floor(x) end

print("Value\tInteger?")
print("=====\t========")
local testCases = {2, 0, -1, 3.5, "String!", true}
for _, input in pairs(testCases) do print(input, isInt(input)) end


Textonyms

When entering text on a phone's digital pad it is possible that a particular combination of digits corresponds to more than one word. Such are called textonyms.

Assuming the digit keys are mapped to letters as follows:
     2 -> ABC
     3 -> DEF
     4 -> GHI
     5 -> JKL
     6 -> MNO
     7 -> PQRS
     8 -> TUV
     9 -> WXYZ

;Task:
Write a program that finds textonyms in a list of words such as
[[Textonyms/wordlist]]   or
unixdict.txt.

The task should produce a report:

 There are #{0} words in #{1} which can be represented by the digit key mapping.
 They require #{2} digit combinations to represent them.
 #{3} digit combinations represent Textonyms.

Where:
 #{0} is the number of words in the list which can be represented by the digit key mapping.
 #{1} is the URL of the wordlist being used.
 #{2} is the number of digit combinations required to represent the words in #{0}.
 #{3} is the number of #{2} which represent more than one word.

At your discretion show a couple of examples of your solution displaying Textonyms.

E.G.:

  2748424767 -> "Briticisms", "criticisms"

;Extra credit:
Use a word list and keypad mapping other than English.

Solution:
-- Global variables
http = require("socket.http")
keys = {"VOICEMAIL", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}
dictFile = "http://www.puzzlers.org/pub/wordlists/unixdict.txt"

-- Return the sequence of keys required to type a given word
function keySequence (str)
    local sequence, noMatch, letter = ""
    for pos = 1, #str do
        letter = str:sub(pos, pos)
        for i, chars in pairs(keys) do
            noMatch = true
            if chars:match(letter) then
                sequence = sequence .. tostring(i)
                noMatch = false
                break
            end
        end
        if noMatch then return nil end
    end
    return tonumber(sequence)
end

-- Generate table of words grouped by key sequence
function textonyms (dict)
    local combTable, keySeq = {}
    for word in dict:gmatch("%S+") do
        keySeq = keySequence(word)
        if keySeq then
            if combTable[keySeq] then
                table.insert(combTable[keySeq], word)
            else
                combTable[keySeq] = {word}
            end
        end
    end
    return combTable
end

-- Analyse sequence table and print details
function showReport (keySeqs)
    local wordCount, seqCount, tCount = 0, 0, 0
    for seq, wordList in pairs(keySeqs) do
        wordCount = wordCount + #wordList
        seqCount = seqCount + 1
        if #wordList > 1 then tCount = tCount + 1 end
    end
    print("There are " .. wordCount .. " words in " .. dictFile)
    print("which can be represented by the digit key mapping.")
    print("They require " .. seqCount .. " digit combinations to represent them.")
    print(tCount .. " digit combinations represent Textonyms.")
end

-- Main procedure
showReport(textonyms(http.request(dictFile)))


The Name Game

Write a program that accepts a name as input and outputs the lyrics to the Shirley Ellis song "The Name Game".

The regular verse

Unless your name begins with a vowel (A, E, I, O, U), 'B', 'F' or 'M' you don't have to care about special rules.
The verse for the name 'Gary' would be like this:

    Gary, Gary, bo-bary
    Banana-fana fo-fary
    Fee-fi-mo-mary
    Gary!

At the end of every line, the name gets repeated without the first letter: Gary becomes ary
If we take (X) as the full name (Gary) and (Y) as the name without the first letter (ary) the verse would look like this:

    (X), (X), bo-b(Y)
    Banana-fana fo-f(Y)
    Fee-fi-mo-m(Y)
    (X)!

Vowel as first letter of the name

If you have a vowel as the first letter of your name (e.g. Earl) you do not truncate the name.
The verse looks like this:

    Earl, Earl, bo-bearl
    Banana-fana fo-fearl
    Fee-fi-mo-mearl
    Earl!

'B', 'F' or 'M' as first letter of the name

In case of a 'B', an 'F' or an 'M' (e.g. Billy, Felix, Mary) there is a special rule.
The line which would 'rebuild' the name (e.g. bo-billy) is sung without the first letter of the name.
The verse for the name Billy looks like this:

    Billy, Billy, bo-illy
    Banana-fana fo-filly
    Fee-fi-mo-milly
    Billy!

For the name 'Felix', this would be right:

    Felix, Felix, bo-belix
    Banana-fana fo-elix
    Fee-fi-mo-melix
    Felix!

Solution:
function printVerse(name)
    local sb = string.lower(name)
    sb = sb:gsub("^%l", string.upper)
    local x = sb
    local x0 = x:sub(1,1)

    local y
    if x0 == 'A' or x0 == 'E' or x0 == 'I' or x0 == 'O' or x0 == 'U' then
        y = string.lower(x)
    else
        y = x:sub(2)
    end

    local b = "b" .. y
    local f = "f" .. y
    local m = "m" .. y

    if x0 == 'B' then
        b = y
    elseif x0 == 'F' then
        f = y
    elseif x0 == 'M' then
        m = y
    end

    print(x .. ", " .. x .. ", bo-" .. b)
    print("Banana-fana fo-" .. f)
    print("Fee-fi-mo-" .. m)
    print(x .. "!")
    print()

    return nil
end

local nameList = { "Gary", "Earl", "Billy", "Felix", "Mary", "Steve" }
for _,name in pairs(nameList) do
    printVerse(name)
end


The Twelve Days of Christmas

Write a program that outputs the lyrics of the Christmas carol ''The Twelve Days of Christmas''.
The lyrics can be found here.

(You must reproduce the words in the correct order, but case, format, and punctuation are left to your discretion.)

Solution:
local days = {
    'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth',
    'tenth', 'eleventh', 'twelfth',
}

local gifts = {
    "A partridge in a pear tree",
    "Two turtle doves",
    "Three french hens",
    "Four calling birds",
    "Five golden rings",
    "Six geese a-laying",
    "Seven swans a-swimming",
    "Eight maids a-milking",
    "Nine ladies dancing",
    "Ten lords a-leaping",
    "Eleven pipers piping",
    "Twelve drummers drumming",
}

local verses = {}

for i = 1, 12 do
    local lines = {}
    lines[1] = "On the " .. days[i] .. " day of Christmas, my true love gave to me"

    local j = i
    local k = 2
    repeat
        lines[k] = gifts[j]
        k = k + 1
        j = j - 1
    until j == 0

    verses[i] = table.concat(lines, '\n')
end

print(table.concat(verses, '\n\n'))


Thue-Morse

Create a Thue-Morse sequence.

;See also
*   YouTube entry: The Fairest Sharing Sequence Ever
*   YouTube entry: Math and OCD - My story with the Thue-Morse sequence
*   Task: [[Fairshare between two and more]]

Solution:
ThueMorse = {sequence = "0"}

function ThueMorse:show ()
    print(self.sequence)
end

function ThueMorse:addBlock ()
    local newBlock = ""
    for bit = 1, self.sequence:len() do
        if self.sequence:sub(bit, bit) == "1" then
            newBlock = newBlock .. "0"
        else
            newBlock = newBlock .. "1"
        end
    end
    self.sequence = self.sequence .. newBlock
end

for i = 1, 5 do
    ThueMorse:show()
    ThueMorse:addBlock()
end


Top rank per group

Find the top   ''N''   salaries in each department,   where   ''N''   is provided as a parameter.

Use this data as a formatted internal data structure (adapt it to your language-native idioms, rather than parse at runtime), or identify your external data source:

Employee Name,Employee ID,Salary,Department
Tyler Bennett,E10297,32000,D101
John Rappl,E21437,47000,D050
George Woltman,E00127,53500,D101
Adam Smith,E63535,18000,D202
Claire Buckman,E39876,27800,D202
David McClellan,E04242,41500,D101
Rich Holcomb,E01234,49500,D202
Nathan Adams,E41298,21900,D050
Richard Potter,E43128,15900,D101
David Motsinger,E27002,19250,D202
Tim Sampair,E03033,27000,D101
Kim Arlich,E10001,57000,D190
Timothy Grove,E16398,29900,D190

Solution:
--Employee Class
local EmployeeMethods = {

}
local EmployeeMetamethods = {
    __index=EmployeeMethods,
    __tostring=function(self)
        return ("%s  %s  %s  %s"):format(self.Name,self.EmployeeId,self.Salary,self.DepartmentName)
    end,
    __metatable="Locked",
}
local EmployeeBase = {}

EmployeeBase.new = function(Name,EmployeeId,Salary,DepartmentName)
    return setmetatable({
        Name=Name,
        EmployeeId=EmployeeId,
        Salary=Salary,
        DepartmentName=DepartmentName,
    },EmployeeMetamethods)
end

--Department Class
local DepartmentMethods = {
    NewEmployee=function(self,Employee)
        table.insert(self.__Employees,Employee)
    end,
    CalculateHighestSalaries=function(self,Amount)
        local Highest = {}
        local EL = #self.__Employees
        table.sort(self.__Employees,function(a,b)
            return a.Salary > b.Salary
        end)
        for i=1,Amount do
            if i>EL then
               break
            end
            table.insert(Highest,self.__Employees[i])
        end
        return Highest
    end,
}
local DepartmentMetamethods = {
    __index=DepartmentMethods,
    __tostring=function(self)
        return ("Department %s"):format(self.Name)
    end,
    __metatable="Locked",
}
local DepartmentBase = {
    __Departments={},
}

DepartmentBase.new = function(Name)
    local Department = DepartmentBase.__Departments[Name]
    if Department then return Department end
    Department = setmetatable({
        __Employees={},
        Name=Name,
    },DepartmentMetamethods)
    DepartmentBase.__Departments[Name] = Department
    return Department
end

--Main Program

local Employees = {
    EmployeeBase.new("Tyler Bennett","E10297",32000,"D101"),
    EmployeeBase.new("John Rappl","E21437",47000,"D050"),
    EmployeeBase.new("George Woltman","E00127",53500,"D101"),
    EmployeeBase.new("Adam Smith","E63535",18000,"D202"),
    EmployeeBase.new("Claire Buckman","E39876",27800,"D202"),
    EmployeeBase.new("David McClellan","E04242",41500,"D101"),
    EmployeeBase.new("Rich Holcomb","E01234",49500,"D202"),
    EmployeeBase.new("Nathan Adams","E41298",21900,"D050"),
    EmployeeBase.new("Richard Potter","E43128",15900,"D101"),
    EmployeeBase.new("David Motsinger","E27002",19250,"D202"),
    EmployeeBase.new("Tim Sampair","E03033",27000,"D101"),
    EmployeeBase.new("Kim Arlich","E10001",57000,"D190"),
    EmployeeBase.new("Timothy Grove","E16398",29900,"D190"),
}

for _,Employee in next,Employees do
    local Department = DepartmentBase.new(Employee.DepartmentName)
    Department:NewEmployee(Employee)
end

for _,Department in next,DepartmentBase.__Departments do
    local Highest = Department:CalculateHighestSalaries(2)
    print(Department)
    for _,Employee in next,Highest do
        print("\t"..tostring(Employee))
    end
end


Topswops

Topswops is a card game created by John Conway in the 1970's.

Assume you have a particular permutation of a set of   n   cards numbered   1..n   on both of their faces, for example the arrangement of four cards given by   [2, 4, 1, 3]   where the leftmost card is on top.

A round is composed of reversing the first   m   cards where   m   is the value of the topmost card.

Rounds are repeated until the topmost card is the number   1   and the number of swaps is recorded.

For our example the swaps produce:

    [2, 4, 1, 3]    # Initial shuffle
    [4, 2, 1, 3]
    [3, 1, 2, 4]
    [2, 1, 3, 4]
    [1, 2, 3, 4]

For a total of four swaps from the initial ordering to produce the terminating case where   1   is on top.

For a particular number    n    of cards,    topswops(n)    is the maximum swaps needed for any starting permutation of the   n   cards.

;Task:
The task is to generate and show here a table of    n    vs    topswops(n)    for    n    in the range   1..10   inclusive.

;Note:
Topswops   is also known as   Fannkuch   from the German word   ''Pfannkuchen''    meaning   pancake.

;Related tasks:
*   [[Number reversal game]]
*   [[Sorting algorithms/Pancake sort]]

Solution:
-- Return an iterator to produce every permutation of list
function permute (list)
    local function perm (list, n)
        if n == 0 then coroutine.yield(list) end
        for i = 1, n do
            list[i], list[n] = list[n], list[i]
            perm(list, n - 1)
            list[i], list[n] = list[n], list[i]
        end
    end
    return coroutine.wrap(function() perm(list, #list) end)
end

-- Perform one topswop round on table t
function swap (t)
    local new, limit = {}, t[1]
    for i = 1, #t do
        if i <= limit then
            new[i] = t[limit - i + 1]
        else
            new[i] = t[i]
        end
    end
    return new
end

-- Find the most swaps needed for any starting permutation of n cards
function topswops (n)
    local numTab, highest, count = {}, 0
    for i = 1, n do numTab[i] = i end
    for numList in permute(numTab) do
        count = 0
        while numList[1] ~= 1 do
            numList = swap(numList)
            count = count + 1
        end
        if count > highest then highest = count end
    end
    return highest
end

-- Main procedure
for i = 1, 10 do print(i, topswops(i)) end


Trabb Pardo–Knuth algorithm

The TPK algorithm is an early example of a programming chrestomathy.
It was used in Donald Knuth and Luis Trabb Pardo's Stanford tech report The Early Development of Programming Languages.
The report traces the early history of work in developing computer languages in the 1940s and 1950s, giving several translations of the algorithm.

From the wikipedia entry:

 '''ask''' for 11 numbers to be read into a sequence ''S''
 '''reverse''' sequence ''S''
 '''for each''' ''item'' '''in''' sequence ''S''
     ''result'' ''':=''' '''call''' a function to do an ''operation''
     '''if''' ''result'' overflows
         '''alert''' user
     '''else'''
         '''print''' ''result''

The task is to implement the algorithm:
# Use the function:     f(x) = |x|^{0.5} + 5x^3
# The overflow condition is an answer of greater than 400.
# The 'user alert' should not stop processing of other items of the sequence.
# Print a prompt before accepting '''eleven''', textual, numeric inputs.
# You may optionally print the item as well as its associated result, but the results must be in reverse order of input.
# The sequence   ''' ''S'' '''   may be 'implied' and so not shown explicitly.
# ''Print and show the program in action from a typical run here''. (If the output is graphical rather than text then either add a screendump or describe textually what is displayed).

Solution:
function f (x) return math.abs(x)^0.5 + 5*x^3 end

function reverse (t)
    local rev = {}
    for i, v in ipairs(t) do rev[#t - (i-1)] = v end
    return rev
end

local sequence, result = {}
print("Enter 11 numbers...")
for n = 1, 11 do
    io.write(n .. ": ")
    sequence[n] = io.read()
end
for _, x in ipairs(reverse(sequence)) do
    result = f(x)
    if result > 400 then print("Overflow!") else print(result) end
end


Truncate a file

Truncate a file to a specific length.   This should be implemented as a routine that takes two parameters: the filename and the required file length (in bytes).

Truncation can be achieved using system or library calls intended for such a task, if such methods exist, or by creating a temporary file of a reduced size and renaming it, after first deleting the original file, if no other method is available.   The file may contain non human readable binary data in an unspecified format, so the routine should be "binary safe", leaving the contents of the untruncated part of the file unchanged.

If the specified filename does not exist, or the provided length is not less than the current file length, then the routine should raise an appropriate error condition.

On some systems, the provided file truncation facilities might not change the file or may extend the file, if the specified length is greater than the current length of the file.

This task permits the use of such facilities.   However, such behaviour should be noted, or optionally a warning message relating to an non change or increase in file size may be implemented.

Solution:
function truncate (filename, length)
    local inFile = io.open(filename, 'r')
    if not inFile then
        error("Specified filename does not exist")
    end
    local wholeFile = inFile:read("*all")
    inFile:close()
    if length >= wholeFile:len() then
        error("Provided length is not less than current file length")
    end
    local outFile = io.open(filename, 'w')
    outFile:write(wholeFile:sub(1, length))
    outFile:close()
end


URL decoding

This task   (the reverse of   [[URL encoding]]   and distinct from   [[URL parser]])   is to provide a function
or mechanism to convert an URL-encoded string into its original unencoded form.

;Test cases:
*   The encoded string   "http%3A%2F%2Ffoo%20bar%2F"   should be reverted to the unencoded form   "http://foo bar/".

*   The encoded string   "google.com/search?q=%60Abdu%27l-Bah%C3%A1"   should revert to the unencoded form   "google.com/search?q=`Abdu'l-Baha".

*   The encoded string   "%25%32%35"   should revert to the unencoded form   "%25" and '''not''' "%".

Solution:
function decodeChar(hex)
	return string.char(tonumber(hex,16))
end

function decodeString(str)
	local output, t = string.gsub(str,"%%(%x%x)",decodeChar)
	return output
end

-- will print "http://foo bar/"
print(decodeString("http%3A%2F%2Ffoo%20bar%2F"))


URL encoding

Provide a function or mechanism to convert a provided string into URL encoding representation.

In URL encoding, special characters, control characters and extended characters
are converted into a percent symbol followed by a two digit hexadecimal code,
So a space character encodes into %20 within the string.

For the purposes of this task, every character except 0-9, A-Z and a-z requires conversion, so the following characters all require conversion by default:

* ASCII control codes (Character ranges 00-1F hex (0-31 decimal) and 7F (127 decimal).
* ASCII symbols (Character ranges 32-47 decimal (20-2F hex))
* ASCII symbols (Character ranges 58-64 decimal (3A-40 hex))
* ASCII symbols (Character ranges 91-96 decimal (5B-60 hex))
* ASCII symbols (Character ranges 123-126 decimal (7B-7E hex))
* Extended characters with character codes of 128 decimal (80 hex) and above.

;Example:
The string "http://foo bar/" would be encoded as "http%3A%2F%2Ffoo%20bar%2F".

;Variations:
* Lowercase escapes are legal, as in "http%3a%2f%2ffoo%20bar%2f".
* Special characters have different encodings for different standards:
** RFC 3986, ''Uniform Resource Identifier (URI): Generic Syntax'', section 2.3, says to preserve "-._~".
** HTML 5, section 4.10.22.5 URL-encoded form data, says to preserve "-._*", and to encode space " " to "+".
** encodeURI function in Javascript will preserve "-._~" (RFC 3986) and ";,/?:@&=+$!*'()#".

;Options:
It is permissible to use an exception string (containing a set of symbols
that do not need to be converted).
However, this is an optional feature and is not a requirement of this task.

;Related tasks:
*   [[URL decoding]]
*   [[URL parser]]

Solution:
function encodeChar(chr)
	return string.format("%%%X",string.byte(chr))
end

function encodeString(str)
	local output, t = string.gsub(str,"[^%w]",encodeChar)
	return output
end

-- will print "http%3A%2F%2Ffoo%20bar%2F"
print(encodeString("http://foo bar/"))


UTF-8 encode and decode

As described in Wikipedia, UTF-8 is a popular encoding of (multi-byte) [[Unicode]] code-points into eight-bit octets.

The goal of this task is to write a encoder that takes a unicode code-point (an integer representing a unicode character) and returns a sequence of 1-4 bytes representing that character in the UTF-8 encoding.

Then you have to write the corresponding decoder that takes a sequence of 1-4 UTF-8 encoded bytes and return the corresponding unicode character.

Demonstrate the functionality of your encoder and decoder on the following five characters:

Character   Name                                  Unicode    UTF-8 encoding (hex)
---------------------------------------------------------------------------------
A           LATIN CAPITAL LETTER A                U+0041     41
o           LATIN SMALL LETTER O WITH DIAERESIS   U+00F6     C3 B6
Zh           CYRILLIC CAPITAL LETTER ZHE           U+0416     D0 96
EUR           EURO SIGN                             U+20AC     E2 82 AC
           MUSICAL SYMBOL G CLEF                 U+1D11E    F0 9D 84 9E

Provided below is a reference implementation in Common Lisp.

Solution:
-- Accept an integer representing a codepoint.
-- Return the values of the individual octets.
function encode (codepoint)
  local codepoint_str = utf8.char(codepoint)
  local result = {}

  for i = 1, #codepoint_str do
    result[#result + 1] = string.unpack("B", codepoint_str, i)
  end

  return table.unpack(result)
end

-- Accept a variable number of octets.
-- Return the corresponding Unicode character.
function decode (...)
  local len = select("#", ...) -- the number of octets
  local fmt = string.rep("B", len)

  return string.pack(fmt, ...)
end

-- Run the given test cases.
function test_encode_decode ()
  -- "A", "ö", "Ж", "€", "𝄞"
  local tests = {tonumber("41", 16),  tonumber("f6", 16), tonumber("416", 16),
                  tonumber("20ac", 16), tonumber("1d11e", 16)}

  for i, test in ipairs(tests) do
    print("Char: ", test)
    print("Encoding: ", encode(test))
    print("Decoding: ", decode(encode(test)))
  end
end


Unbias a random generator

Given a weighted one-bit generator of random numbers where the probability of a one occurring, P_1, is not the same as P_0, the probability of a zero occurring, the probability of the occurrence of a one followed by a zero is P_1 x P_0, assuming independence. This is the same as the probability of a zero followed by a one: P_0 x P_1.

;Task details:
* Use your language's random number generator to create a function/method/subroutine/... '''randN''' that returns a one or a zero, but with one occurring, on average, 1 out of N times, where N is an integer from the range 3 to 6 inclusive.
* Create a function '''unbiased''' that uses only randN as its source of randomness to become an unbiased generator of random ones and zeroes.
* For N over its range, generate and show counts of the outputs of randN and unbiased(randN).

The actual unbiasing should be done by generating two numbers at a time from randN and only returning a 1 or 0 if they are different. As long as you always return the first number or always return the second number, the probabilities discussed above should take over the biased probability of randN.

This task is an implementation of Von Neumann debiasing, first described in a 1951 paper.

Solution:
local function randN(n)
  return function()
    if math.random() < 1/n then return 1 else return 0 end
  end
end

local function unbiased(n)
  local biased = randN (n)
  return function()
    local a, b = biased(), biased()
    while a==b do
      a, b = biased(), biased()
    end
    return a
  end
end

local function demonstrate (samples)
  for n = 3, 6 do
    biased = randN(n)
    unbias = unbiased(n)
    local bcounts = {[0]=0,[1]=0}
    local ucounts = {[0]=0,[1]=0}
    for i=1, samples do
      local bnum = biased()
      local unum = unbias()
      bcounts[bnum] = bcounts[bnum]+1
      ucounts[unum] = ucounts[unum]+1
    end
    print(string.format("N = %d",n),
      "# 0", "# 1",
      "% 0", "% 1")
    print("biased", bcounts[0], bcounts[1],
      bcounts[0] / samples * 100,
      bcounts[1] / samples * 100)
    print("unbias", ucounts[0], ucounts[1],
      ucounts[0] / samples * 100,
      ucounts[1] / samples * 100)
  end
end

demonstrate(100000)


Unicode strings

As the world gets smaller each day, internationalization becomes more and more important.   For handling multiple languages, [[Unicode]] is your best friend.

It is a very capable tool, but also quite complex compared to older single- and double-byte character encodings.

How well prepared is your programming language for Unicode?

;Task:
Discuss and demonstrate its unicode awareness and capabilities.

Some suggested topics:
:*   How easy is it to present Unicode strings in source code?
:*   Can Unicode literals be written directly, or be part of identifiers/keywords/etc?
:*   How well can the language communicate with the rest of the world?
:*   Is it good at input/output with Unicode?
:*   Is it convenient to manipulate Unicode strings in the language?
:*   How broad/deep does the language support Unicode?
:*   What encodings (e.g. UTF-8, UTF-16, etc) can be used?
:*   Does it support normalization?

;Note:
This task is a bit unusual in that it encourages general discussion rather than clever coding.

;See also:
*   [[Unicode variable names]]
*   [[Terminal control/Display an extended character]]

Solution: By default, Lua doesn't support Unicode. Most string methods will work properly on the ASCII range only like [[String case#Lua|case transformation]]. But there is a [https://www.lua.org/manual/5.4/manual.html#6.5 utf8] module that add some very basic support with a very limited number of functions. For example, this module brings a new [[String length#Lua|length method]] adapted for UTF-8. But there is no method to transform the case of Unicode string correctly. So globally the Unicode support is very limited and not by default.


Universal Turing machine

One of the foundational mathematical constructs behind computer science
is the universal Turing Machine.

(Alan Turing introduced the idea of such a machine in 1936-1937.)

Indeed one way to definitively prove that a language
is turing-complete
is to implement a universal Turing machine in it.

;Task:
Simulate such a machine capable
of taking the definition of any other Turing machine and executing it.

Of course, you will not have an infinite tape,
but you should emulate this as much as is possible.

The three permissible actions on the tape are "left", "right" and "stay".

To test your universal Turing machine (and prove your programming language
is Turing complete!), you should execute the following two Turing machines
based on the following definitions.

'''Simple incrementer'''
* '''States:''' q0, qf
* '''Initial state:''' q0
* '''Terminating states:''' qf
* '''Permissible symbols:''' B, 1
* '''Blank symbol:''' B
* '''Rules:'''
** (q0, 1, 1, right, q0)
** (q0, B, 1, stay,  qf)

The input for this machine should be a tape of 1 1 1

'''Three-state busy beaver'''
* '''States:''' a, b, c, halt
* '''Initial state:''' a
* '''Terminating states:''' halt
* '''Permissible symbols:''' 0, 1
* '''Blank symbol:''' 0
* '''Rules:'''
** (a, 0, 1, right, b)
** (a, 1, 1, left,  c)
** (b, 0, 1, left,  a)
** (b, 1, 1, right, b)
** (c, 0, 1, left,  b)
** (c, 1, 1, stay,  halt)

The input for this machine should be an empty tape.

'''Bonus:'''

'''5-state, 2-symbol probable Busy Beaver machine from Wikipedia'''
* '''States:''' A, B, C, D, E, H
* '''Initial state:''' A
* '''Terminating states:''' H
* '''Permissible symbols:''' 0, 1
* '''Blank symbol:''' 0
* '''Rules:'''
** (A, 0, 1, right, B)
** (A, 1, 1, left,  C)
** (B, 0, 1, right, C)
** (B, 1, 1, right, B)
** (C, 0, 1, right, D)
** (C, 1, 0, left,  E)
** (D, 0, 1, left,  A)
** (D, 1, 1, left,  D)
** (E, 0, 1, stay,  H)
** (E, 1, 0, left,  A)

The input for this machine should be an empty tape.

This machine runs for more than 47 millions steps.

Solution:
-- Machine definitions
local incrementer = {
    name = "Simple incrementer",
    initState = "q0",
    endState = "qf",
    blank = "B",
    rules = {
        {"q0", "1", "1", "right", "q0"},
        {"q0", "B", "1", "stay", "qf"}
    }
}

local threeStateBB = {
    name = "Three-state busy beaver",
    initState = "a",
    endState = "halt",
    blank = "0",
    rules = {
        {"a", "0", "1", "right", "b"},
        {"a", "1", "1", "left", "c"},
        {"b", "0", "1", "left", "a"},
        {"b", "1", "1", "right", "b"},
        {"c", "0", "1", "left", "b"},
        {"c", "1", "1", "stay", "halt"}
    }
}

local fiveStateBB = {
    name = "Five-state busy beaver",
    initState = "A",
    endState = "H",
    blank = "0",
    rules = {
        {"A", "0", "1", "right", "B"},
        {"A", "1", "1", "left", "C"},
        {"B", "0", "1", "right", "C"},
        {"B", "1", "1", "right", "B"},
        {"C", "0", "1", "right", "D"},
        {"C", "1", "0", "left", "E"},
        {"D", "0", "1", "left", "A"},
        {"D", "1", "1", "left", "D"},
        {"E", "0", "1", "stay", "H"},
        {"E", "1", "0", "left", "A"}
    }
}

-- Display a representation of the tape and machine state on the screen
function show (state, headPos, tape)
    local leftEdge = 1
    while tape[leftEdge - 1] do leftEdge = leftEdge - 1 end
    io.write(" " .. state .. "\t| ")
    for pos = leftEdge, #tape do
        if pos == headPos then io.write("[" .. tape[pos] .. "] ") else io.write(" " .. tape[pos] .. "  ") end
    end
    print()
end

-- Simulate a turing machine
function UTM (machine, tape, countOnly)
    local state, headPos, counter = machine.initState, 1, 0
    print("\n\n" .. machine.name)
    print(string.rep("=", #machine.name) .. "\n")
    if not countOnly then print(" State", "| Tape [head]\n---------------------") end
    repeat
        if not tape[headPos] then tape[headPos] = machine.blank end
        if not countOnly then show(state, headPos, tape) end
        for _, rule in ipairs(machine.rules) do
            if rule[1] == state and rule[2] == tape[headPos] then
                tape[headPos] = rule[3]
                if rule[4] == "left" then headPos = headPos - 1 end
                if rule[4] == "right" then headPos = headPos + 1 end
                state = rule[5]
                break
            end
        end
        counter = counter + 1
    until state == machine.endState
    if countOnly then print("Steps taken: " .. counter) else show(state, headPos, tape) end
end

-- Main procedure
UTM(incrementer, {"1", "1", "1"})
UTM(threeStateBB, {})
UTM(fiveStateBB, {}, "countOnly")


Validate International Securities Identification Number

An International Securities Identification Number (ISIN) is a unique international identifier for a financial security such as a stock or bond.

;Task:
Write a function or program that takes a string as input, and checks whether it is a valid ISIN.

It is only valid if it has the correct format,   ''and''   the embedded checksum is correct.

Demonstrate that your code passes the test-cases listed below.

;Details:
The format of an ISIN is as follows:

+------------- a 2-character ISO country code (A-Z)
| +----------- a 9-character security code (A-Z, 0-9)
| |        +-- a checksum digit (0-9)
AU0000XVGZA3

For this task, you may assume that any 2-character alphabetic sequence is a valid country code.

The checksum can be validated as follows:
# '''Replace letters with digits''', by converting each character from base 36 to base 10, e.g. AU0000XVGZA3 -1030000033311635103.
# '''Perform the Luhn test on this base-10 number.'''There is a separate task for this test: ''[[Luhn test of credit card numbers]]''.You don't have to replicate the implementation of this test here   ---   you can just call the existing function from that task.   (Add a comment stating if you did this.)

;Test cases:
:::: {| class="wikitable"
! ISIN
! Validity
! Comment
|-
| US0378331005  || valid ||
|-
| US0373831005  || not valid || The transposition typo is caught by the checksum constraint.
|-
| U50378331005  || not valid || The substitution typo is caught by the format constraint.
|-
| US03378331005 || not valid || The duplication typo is caught by the format constraint.
|-
| AU0000XVGZA3  || valid ||
|-
| AU0000VXGZA3  || valid || Unfortunately, not ''all'' transposition typos are caught by the checksum constraint.
|-
| FR0000988040  || valid ||
|}

(The comments are just informational.   Your function should simply return a Boolean result.   See [[#Raku]] for a reference solution.)

Related task:
* [[Luhn test of credit card numbers]]

;Also see:
* Interactive online ISIN validator
* Wikipedia article: International Securities Identification Number

Solution:
function luhn (n)
    local revStr, s1, s2, digit, mod = n:reverse(), 0, 0
    for pos = 1, #revStr do
        digit = tonumber(revStr:sub(pos, pos))
        if pos % 2 == 1 then
            s1 = s1 + digit
        else
            digit = digit * 2
            if digit > 9 then
                mod = digit % 10
                digit = mod + ((digit - mod) / 10)
            end
            s2 = s2 + digit
        end
    end
    return (s1 + s2) % 10 == 0
end

function checkISIN (inStr)
    if #inStr ~= 12 then return false end
    local numStr = ""
    for pos = 1, #inStr do
        numStr = numStr .. tonumber(inStr:sub(pos, pos), 36)
    end
    return luhn(numStr)
end

local testCases = {
    "US0378331005",
    "US0373831005",
    "US0373831005",
    "US03378331005",
    "AU0000XVGZA3",
    "AU0000VXGZA3",
    "FR0000988040"
}
for _, ISIN in pairs(testCases) do print(ISIN, checkISIN(ISIN)) end


Van Eck sequence

The sequence is generated by following this pseudo-code:

A:  The first term is zero.
    Repeatedly apply:
        If the last term is *new* to the sequence so far then:
B:          The next term is zero.
        Otherwise:
C:          The next term is how far back this last term occured previously.

;Example:
Using A:
:0
Using B:
:0 0
Using C:
:0 0 1
Using B:
:0 0 1 0
Using C:  (zero last occurred two steps back - before the one)
:0 0 1 0 2
Using B:
:0 0 1 0 2 0
Using C:  (two last occurred two steps back - before the zero)
:0 0 1 0 2 0 2 2
Using C:  (two last occurred one step back)
:0 0 1 0 2 0 2 2 1
Using C:  (one last appeared six steps back)
:0 0 1 0 2 0 2 2 1 6
...

;Task:
# Create a function/procedure/method/subroutine/... to generate the Van Eck sequence of numbers.
# Use it to display here, on this page:
:# The first ten terms of the sequence.
:# Terms 991 - to - 1000 of the sequence.

;References:
* Don't Know (the Van Eck Sequence) - Numberphile video.
* Wikipedia Article: Van Eck's Sequence.
*  OEIS sequence: A181391.

Solution:
-- Return a table of the first n values of the Van Eck sequence
function vanEck (n)
  local seq, foundAt = {0}
  while #seq < n do
    foundAt = nil
    for pos = #seq - 1, 1, -1 do
      if seq[pos] == seq[#seq] then
        foundAt = pos
        break
      end
    end
    if foundAt then
      table.insert(seq, #seq - foundAt)
    else
      table.insert(seq, 0)
    end
  end
  return seq
end

-- Show the set of values in table t from key numbers lo to hi
function showValues (t, lo, hi)
  for i = lo, hi do
    io.write(t[i] .. " ")
  end
  print()
end

-- Main procedure
local sequence = vanEck(1000)
showValues(sequence, 1, 10)
showValues(sequence, 991, 1000)


Van der Corput sequence

When counting integers in binary, if you put a (binary) point to the right of the count then the column immediately to the left denotes a digit with a multiplier of 2^0; the digit in the next column to the left has a multiplier of 2^1; and so on.

So in the following table:
  0.
  1.
 10.
 11.
 ...
the binary number "10" is 1 \times 2^1 + 0 \times 2^0.

You can also have binary digits to the right of the "point", just as in the decimal number system. In that case, the digit in the place immediately to the right of the point has a weight of 2^{-1}, or 1/2.
The weight for the second column to the right of the point is 2^{-2} or 1/4. And so on.

If you take the integer binary count of the first table, and ''reflect'' the digits about the binary point, you end up with '''the van der Corput sequence of numbers in base 2'''.

  .0
  .1
  .01
  .11
  ...

The third member of the sequence, binary 0.01, is therefore 0 \times 2^{-1} + 1 \times 2^{-2} or 1/4.

 Monte Carlo simulations.
This sequence is also a superset of the numbers representable by the "fraction" field of an old IEEE floating point standard. In that standard, the "fraction" field represented the fractional part of a binary number beginning with "1." e.g. 1.101001101.

'''Hint'''

A ''hint'' at a way to generate members of the sequence is to modify a routine used to change the base of an integer:
>>> def base10change(n, base):
	digits = []
	while n:
		n,remainder = divmod(n, base)
		digits.insert(0, remainder)
	return digits

>>> base10change(11, 2)
[1, 0, 1, 1]
the above showing that 11 in decimal is 1\times 2^3 + 0\times 2^2 + 1\times 2^1 + 1\times 2^0.
Reflected this would become .1101 or 1\times 2^{-1} + 1\times 2^{-2} + 0\times 2^{-3} + 1\times 2^{-4}

;Task description:
* Create a function/method/routine that given ''n'', generates the ''n'''th term of the van der Corput sequence in base 2.
* Use the function to compute ''and display'' the first ten members of the sequence. (The first member of the sequence is for ''n''=0).

* As a stretch goal/extra credit, compute and show members of the sequence for bases other than 2.

;See also:
* The Basic Low Discrepancy Sequences
* [[Non-decimal radices/Convert]]
* Van der Corput sequence

Solution:
function vdc(n, base)
    local digits = {}
    while n ~= 0 do
        local m = math.floor(n / base)
        table.insert(digits, n - m * base)
        n = m
    end
    m = 0
    for p, d in pairs(digits) do
        m = m + math.pow(base, -p) * d
    end
    return m
end