Knight's tour

Task
Problem: you have a standard 8x8 chessboard, empty but for a single knight on some square.   Your task is to emit a series of legal knight moves that result in the knight visiting every square on the chessboard exactly once. Note that it is ''not'' a requirement that the tour be "closed"; that is, the knight need not end within a single move of its start position.

Input and output may be textual or graphical, according to the conventions of the programming environment.  If textual, squares should be indicated in algebraic notation.  The output should indicate the order in which the knight visits the squares, starting with the initial position.  The form of the output may be a diagram of the board with the squares numbered according to visitation sequence, or a textual list of algebraic coordinates in order, or even an actual animation of the knight moving around the chessboard.

Input: starting square

Output: move sequence

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

Solution:
class Board
  Cell = Struct.new(:value, :adj) do
    def self.end=(end_val)
      @@end = end_val
    end

    def try(seq_num)
      self.value = seq_num
      return true  if seq_num==@@end
      a = []
      adj.each_with_index do |cell, n|
        a << [wdof(cell.adj)*10+n, cell]  if cell.value.zero?
      end
      a.sort.each {|_, cell| return true  if cell.try(seq_num+1)}
      self.value = 0
      false
    end

    def wdof(adj)
      adj.count {|cell| cell.value.zero?}
    end
  end

  def initialize(rows, cols)
    @rows, @cols = rows, cols
    unless defined? ADJACENT                      # default move (Knight)
      eval("ADJACENT = [[-1,-2],[-2,-1],[-2,1],[-1,2],[1,2],[2,1],[2,-1],[1,-2]]")
    end
    frame = ADJACENT.flatten.map(&:abs).max
    @board = Array.new(rows+frame) do |i|
      Array.new(cols+frame) do |j|
        (i<rows and j<cols) ? Cell.new(0) : nil   # frame (Sentinel value : nil)
      end
    end
    rows.times do |i|
      cols.times do |j|
        @board[i][j].adj = ADJACENT.map{|di,dj| @board[i+di][j+dj]}.compact
      end
    end
    Cell.end = rows * cols
    @format = " %#{(rows * cols).to_s.size}d"
  end

  def solve(sx, sy)
    if (@rows*@cols).odd? and (sx+sy).odd?
      puts "No solution"
    else
      puts (@board[sx][sy].try(1) ? to_s : "No solution")
    end
  end

  def to_s
    (0...@rows).map do |x|
      (0...@cols).map{|y| @format % @board[x][y].value}.join
    end
  end
end

def knight_tour(rows=8, cols=rows, sx=rand(rows), sy=rand(cols))
  puts "\nBoard (%d x %d), Start:[%d, %d]" % [rows, cols, sx, sy]
  Board.new(rows, cols).solve(sx, sy)
end

knight_tour(8,8,3,1)

knight_tour(5,5,2,2)

knight_tour(4,9,0,0)

knight_tour(5,5,0,1)

knight_tour(12,12,1,1)


Knuth's algorithm S

This is a method of randomly sampling n items from a set of M items, with equal probability; where M >= n and M, the number of items is unknown until the end.
This means that the equal probability sampling should be maintained  for all successive items > n as they become available (although the content of successive samples can change).

;The algorithm:
:* Select the first n items as the sample as they become available;
:* For the i-th item where i > n, have a random chance of n/i of keeping it.  If failing this chance, the sample remains the same.  If not, have it randomly (1/n) replace one of the previously selected n items of the sample.
:* Repeat   2nd step   for any subsequent items.

;The Task:
:* Create a function s_of_n_creator that given n the maximum sample size, returns a function s_of_n that takes one parameter, item.
:* Function  s_of_n when called with successive items returns an equi-weighted random sample of up to n of its items so far, each time it is called, calculated using Knuths Algorithm S.
:* Test your functions by printing and showing the frequency of occurrences of the selected digits from 100,000 repetitions of:
:::# Use the s_of_n_creator with n == 3 to generate an s_of_n.
:::# call s_of_n with each of the digits 0 to 9 in order, keeping the returned three digits of its random sampling from its last call with argument item=9.

Note: A class taking n and generating a callable instance/function might also be used.

;Reference:
* The Art of Computer Programming, Vol 2, 3.4.2 p.142

;Related tasks:
* [[One of n lines in a file]]
* [[Accumulator factory]]

Solution:
def s_of_n_creator(n)
  sample = []
  i = 0
  Proc.new do |item|
    i += 1
    if i <= n
      sample << item
    elsif rand(i) < n
      sample[rand(n)] = item
    end
    sample
  end
end

frequency = Array.new(10,0)
100_000.times do
  s_of_n = s_of_n_creator(3)
  sample = nil
  (0..9).each {|digit| sample = s_of_n[digit]}
  sample.each {|digit| frequency[digit] += 1}
end

(0..9).each {|digit| puts "#{digit}\t#{frequency[digit]}"}


Kolakoski sequence

The natural numbers, (excluding zero); with the property that:
: ''if you form a new sequence from the counts of runs of the same number in the first sequence, this new sequence is the same as the first sequence''.

;Example:
This is ''not'' a Kolakoski sequence:
1,1,2,2,2,1,2,2,1,2,...
Its sequence of run counts, (sometimes called a run length encoding, (RLE); but a true RLE also gives the character that each run encodes), is calculated like this:

: Starting from the leftmost number of the sequence we have 2 ones, followed by 3 twos, then 1 ones, 2 twos, 1 one, ...

The above gives the RLE of:
2, 3, 1, 2, 1, ...

The original sequence is different from its RLE in this case. '''It would be the same for a true Kolakoski sequence'''.

;Creating a Kolakoski sequence:

Lets start with the two numbers (1, 2) that we will cycle through; i.e. they will be used in this order: 1,2,1,2,1,2,....

# We start the sequence s with the first item from the cycle c: 1
# An index, k, into the, (expanding), sequence will step, or index through each item of the sequence s from the first, at its own rate.
We will arrange that the k'th item of s states how many ''times'' the ''last'' item of sshould appear at the end of s.

We started s with 1 and therefore s[k] states that it should appear only the 1 time.

Increment k
Get the next item from c and append it to the end of sequence s. s will then become: 1, 2
k was moved to the second item in the list and s[k] states that it should appear two times, so append another of the last item to the sequence s: 1, 2,2
Increment k
Append the next item from the cycle to the list: 1, 2,2, 1
k is now at the third item in the list that states that the last item should appear twice so add another copy of the last item to the sequence s: 1, 2,2, 1,1
increment k

...

'''Note''' that the RLE of 1, 2, 2, 1, 1, ... begins 1, 2, 2 which is the beginning of the original sequence. The generation algorithm ensures that this will always be the case.

;Task:
# Create a routine/proceedure/function/... that given an initial ordered list/array/tuple etc of the natural numbers (1, 2), returns the next number from the list when accessed in a cycle.
# Create another routine that when given the initial ordered list (1, 2) and the minimum length of the sequence  to generate; uses the first routine and the algorithm above, to generate at least the requested first members of the kolakoski sequence.
# Create a routine that when given a sequence, creates the run length encoding of that sequence (as defined above) and returns the result of checking if sequence starts with the exact members of its RLE. (But ''note'', due to sampling, do not compare the last member of the RLE).
# Show, on this page, (compactly), the first 20 members of the sequence generated from (1, 2)
# Check the sequence againt its RLE.
# Show, on this page, the first 20 members of the sequence generated from (2, 1)
# Check the sequence againt its RLE.
# Show, on this page, the first 30 members of the Kolakoski sequence generated from (1, 3, 1, 2)
# Check the sequence againt its RLE.
# Show, on this page, the first 30 members of the Kolakoski sequence generated from (1, 3, 2, 1)
# Check the sequence againt its RLE.
(There are rules on generating Kolakoski sequences from this method that are broken by the last example)

Solution:
def create_generator(ar)
  Enumerator.new do |y|
    cycle = ar.cycle
    s = []
    loop do
      t = cycle.next
      s.push(t)
      v = s.shift
      y << v
      (v-1).times{s.push(t)}
    end
  end
end

def rle(ar)
  ar.slice_when{|a,b| a != b}.map(&:size)
end

[[20, [1,2]],
 [20, [2,1]],
 [30, [1,3,1,2]],
 [30, [1,3,2,1]]].each do |num,ar|
  puts "\nFirst #{num} of the sequence generated by #{ar.inspect}:"
  p res = create_generator(ar).take(num)
  puts "Possible Kolakoski sequence? #{res.join.start_with?(rle(res).join)}"
end


Lah numbers

Lah numbers, sometimes referred to as ''Stirling numbers of the third kind'', are coefficients of polynomial expansions expressing rising factorials in terms of falling factorials.

Unsigned Lah numbers count the number of ways a set of '''n''' elements can be partitioned into '''k''' non-empty linearly ordered subsets.

Lah numbers are closely related to Stirling numbers of the first & second kinds, and may be derived from them.

Lah numbers obey the identities and relations:
   L(n, 0), L(0, k) = 0   # for n, k > 0
   L(n, n) = 1
   L(n, 1) = n!
   L(n, k) =           ( n! * (n - 1)! ) / ( k! * (k - 1)! ) / (n - k)!      # For unsigned Lah numbers
      ''or''
   L(n, k) = (-1)**n * ( n! * (n - 1)! ) / ( k! * (k - 1)! ) / (n - k)!      # For   signed Lah numbers

;Task:
:* Write a routine (function, procedure, whatever) to find '''unsigned Lah numbers'''. There are several methods to generate unsigned Lah numbers. You are free to choose the most appropriate for your language. If your language has a built-in, or easily, publicly available library implementation, it is acceptable to use that.

:* Using the routine, generate and show here, on this page, a table (or triangle) showing the unsigned Lah numbers, '''L(n, k)''', up to '''L(12, 12)'''. it is optional to show the row / column for n == 0 and k == 0. It is optional to show places where L(n, k) == 0 (when k > n).

:* If your language supports large integers, find and show here, on this page, the maximum value of '''L(n, k)''' where '''n == 100'''.

;See also:

:* '''Wikipedia - Lah number'''
:* '''OEIS:A105278 - Unsigned Lah numbers'''
:* '''OEIS:A008297 - Signed Lah numbers'''

;Related Tasks:

:* '''Stirling numbers of the first kind'''
:* '''Stirling numbers of the second kind'''
:* '''Bell numbers'''

Solution:
def fact(n) = n.zero? ? 1 :  1.upto(n).inject(&:*)

def lah(n, k)
  case k
    when 1 then fact(n)
    when n then 1
    when (..1),(n..) then 0
    else n<1 ? 0 : (fact(n)*fact(n-1)) / (fact(k)*fact(k-1)) / fact(n-k)
  end
end

r = (0..12)
puts "Unsigned Lah numbers: L(n, k):"
puts "n/k #{r.map{|n| "%11d" % n}.join}"

r.each do |row|
  print "%-4s" % row
  puts "#{(0..row).map{|col| "%11d" % lah(row,col)}.join}"
end

puts "\nMaximum value from the L(100, *) row:";
puts (1..100).map{|a| lah(100,a)}.max


Largest int from concatenated ints

Given a set of positive integers, write a function to order the integers in such a way that the concatenation of the numbers forms the largest possible integer and return this integer.

Use the following two sets of integers as tests   and   show your program output here.

:::::*   {1, 34, 3, 98, 9, 76, 45, 4}
:::::*   {54, 546, 548, 60}

;Possible algorithms:
# A solution could be found by trying all combinations and return the best.
# Another way to solve this is to note that in the best arrangement, for any two adjacent original integers '''X''' and '''Y''', the concatenation '''X''' followed by '''Y''' will be numerically greater than or equal to the concatenation '''Y''' followed by '''X.
# Yet another way to solve this is to pad the integers to the same size by repeating the digits then sort using these repeated integers as a sort key.

;See also:
*   Algorithms: What is the most efficient way to arrange the given numbers to form the biggest number?
*   Constructing the largest number possible by rearranging a list

Solution:
def icsort nums
  nums.sort { |x, y| "#{y}#{x}" <=> "#{x}#{y}" }
end

[[54, 546, 548, 60], [1, 34, 3, 98, 9, 76, 45, 4]].each do |c|
  p c # prints nicer in Ruby 1.8
  puts icsort(c).join
end


Largest number divisible by its digits

Find the largest base 10 integer whose digits are all different,   and   is evenly divisible by each of its individual digits.

These numbers are also known as   '''Lynch-Bell numbers''',   numbers   '''n'''   such that the
(base ten) digits are all different (and do not include zero)   and   '''n'''   is divisible by each of its individual digits.

;Example:
'''135'''   is evenly divisible by   '''1''',   '''3''',   and   '''5'''.

Note that the digit zero (0) can not be in the number as integer division by zero is undefined.

The digits must all be unique so a base ten number will have at most '''9''' digits.

Feel free to use analytics and clever algorithms to reduce the search space your example needs to visit, but it must do an actual search. (Don't just feed it the answer and verify it is correct.)

;Stretch goal:
Do the same thing for hexadecimal.

;Related tasks:
:*   gapful numbers.
:*   palindromic gapful numbers.

;Also see:
:*   The OEIS sequence:   A115569: Lynch-Bell numbers.

Solution:
magic_number = 9*8*7
div          = 9876432.div(magic_number) * magic_number
candidates   = div.step(0, -magic_number)

res = candidates.find do |c|
  digits = c.digits
  (digits & [0,5]).empty? && digits == digits.uniq
end

puts "Largest decimal number is #{res}"


Largest number divisible by its digits

Solution:
def divByAll(num, digits)
  digits.all? { |digit| num % digit.to_i(16) == 0 }
end

magic = 15 * 14 * 13 * 12 * 11
high = (0xfedcba987654321 / magic) * magic

high.step(magic, -magic) do |i|
  s = i.to_s(16)               # always generates lower case a-f
  next if s.include? "0"       # can't contain '0'
  sd = s.chars.uniq
  next if sd.size != s.size    # digits must be unique
  (puts "Largest hex number is #{i.to_s(16)}"; break) if divByAll(i, sd)
end


Largest proper divisor of n

a(1) = 1; for n > 1, a(n) = '''largest''' proper divisor of n, where '''n < 101 '''.

Solution:
require 'prime'

def a(n)
  return 1 if n == 1 || n.prime?
  (n/2).downto(1).detect{|d| n.remainder(d) == 0}
end

(1..100).map{|n| a(n).to_s.rjust(3)}.each_slice(10){|slice| puts slice.join}


Last Friday of each month

Write a program or a script that returns the date of the last Fridays of each month of a given year.

The year may be given through any simple input method in your language (command line, std in, etc).

Example of an expected output:
./last_fridays 2012
2012-01-27
2012-02-24
2012-03-30
2012-04-27
2012-05-25
2012-06-29
2012-07-27
2012-08-31
2012-09-28
2012-10-26
2012-11-30
2012-12-28

;Related tasks
* [[Five weekends]]
* [[Day of the week]]
* [[Find the last Sunday of each month]]

Solution:
require 'date'

def last_friday(year, month)
  # Last day of month: Date.new interprets a negative number as a relative month/day from the end of year/month.
  d = Date.new(year, month, -1)
  d -= (d.wday - 5) % 7  # Subtract days after Friday.
end

year = Integer(ARGV.shift)
(1..12).each {|month| puts last_friday(year, month)}


Last letter-first letter

A certain children's game involves starting with a word in a particular category.   Each participant in turn says a word, but that word must begin with the final letter of the previous word.   Once a word has been given, it cannot be repeated.   If an opponent cannot give a word in the category, they fall out of the game.

For example, with   "animals"   as the category,

Child 1: dog
Child 2: goldfish
Child 1: hippopotamus
Child 2: snake
...

;Task:
Take the following selection of 70 English Pokemon names   (extracted from   Wikipedia's list of Pokemon)   and generate the/a sequence with the highest possible number of Pokemon names where the subsequent name starts with the final letter of the preceding name.

No Pokemon name is to be repeated.

audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon
cresselia croagunk darmanitan deino emboar emolga exeggcute gabite
girafarig gulpin haxorus heatmor heatran ivysaur jellicent jumpluff kangaskhan
kricketune landorus ledyba loudred lumineon lunatone machamp magnezone mamoswine
nosepass petilil pidgeotto pikachu pinsir poliwrath poochyena porygon2
porygonz registeel relicanth remoraid rufflet sableye scolipede scrafty seaking
sealeo silcoon simisear snivy snorlax spoink starly tirtouga trapinch treecko
tyrogue vigoroth vulpix wailord wartortle whismur wingull yamask

Extra brownie points for dealing with the full list of   646   names.

Solution:
class LastL_FirstL
  def initialize(names)
    @names = names.dup
    @first = names.group_by {|name| name[0]}
    @sequences = []
  end

  def add_name(seq)
    last_letter = seq[-1][-1]
    potentials = @first.include?(last_letter) ? (@first[last_letter] - seq) : []
    if potentials.empty?
      @sequences << seq
    else
      potentials.each {|name| add_name(seq + [name])}
    end
  end

  def search
    @names.each {|name| add_name [name]}
    max = @sequences.max_by {|seq| seq.length}.length
    max_seqs = @sequences.select {|seq| seq.length == max}
    puts "there are #{@sequences.length} possible sequences"
    puts "the longest is #{max} names long"
    puts "there are #{max_seqs.length} such sequences. one is:"
    max_seqs.last.each_with_index {|name, idx| puts "  %2d %s" % [idx+1, name]}
  end
end

names = %w{
  audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon
  cresselia croagunk darmanitan deino emboar emolga exeggcute gabite
  girafarig gulpin haxorus heatmor heatran ivysaur jellicent jumpluff kangaskhan
  kricketune landorus ledyba loudred lumineon lunatone machamp magnezone mamoswine
  nosepass petilil pidgeotto pikachu pinsir poliwrath poochyena porygon2
  porygonz registeel relicanth remoraid rufflet sableye scolipede scrafty seaking
  sealeo silcoon simisear snivy snorlax spoink starly tirtouga trapinch treecko
  tyrogue vigoroth vulpix wailord wartortle whismur wingull yamask
}

lf = LastL_FirstL.new(names)
lf.search


Latin Squares in reduced form

A Latin Square is in its reduced form if the first row and first column contain items in their natural order. The order n is the number of items. For any given n there is a set of reduced Latin Squares whose size increases rapidly with n. g is a number which identifies a unique element within the set of reduced Latin Squares of order n. The objective of this task is to construct the set of all Latin Squares of a given order and to provide a means which given suitable values for g any element within the set may be obtained.

For a reduced Latin Square the first row is always 1 to n. The second row is all [[Permutations/Derangements]] of 1 to n starting with 2. The third row is all [[Permutations/Derangements]] of 1 to n starting with 3 which do not clash (do not have the same item in any column) with row 2. The fourth row is all [[Permutations/Derangements]] of 1 to n starting with 4 which do not clash with rows 2 or 3. Likewise continuing to the nth row.

Demonstrate by:
* displaying the four reduced Latin Squares of order 4.
* for n = 1 to 6 (or more) produce the set of reduced Latin Squares; produce a table which shows the size of the set of reduced Latin Squares and compares this value times n! times (n-1)! with the values in OEIS A002860.

Solution:
def printSquare(a)
    for row in a
        print row, "\n"
    end
    print "\n"
end

def dList(n, start)
    start = start - 1 # use 0 based indexing
    a = Array.new(n) {|i| i}
    a[0], a[start] = a[start], a[0]
    a[1..] = a[1..].sort
    first = a[1]

    r = []
    recurse = lambda {|last|
        if last == first then
            # bottom of recursion, reached once for each permutation
            # test if permutation is deranged
            a[1..].each_with_index {|v, j|
                if j + 1 == v then
                    return # no, ignore it
                end
            }
            # yes, save a copy with 1 based indexing
            b = a.map { |i| i + 1 }
            r << b
            return
        end

        i = last
        while i >= 1 do
            a[i], a[last] = a[last], a[i]
            recurse.call(last - 1)
            a[i], a[last] = a[last], a[i]
            i = i - 1
        end
    }

    recurse.call(n - 1)
    return r
end

def reducedLatinSquares(n, echo)
    if n <= 0 then
        if echo then
            print "[]\n\n"
        end
        return 0
    end
    if n == 1 then
        if echo then
            print "[1]\n\n"
        end
        return 1
    end

    rlatin = Array.new(n) { Array.new(n, Float::NAN)}

    # first row
    for j in 0 .. n - 1
        rlatin[0][j] = j + 1
    end

    count = 0
    recurse = lambda {|i|
        rows = dList(n, i)

        for r in 0 .. rows.length - 1
            rlatin[i - 1] = rows[r].dup
            catch (:outer) do
                for k in 0 .. i - 2
                    for j in 1 .. n - 1
                        if rlatin[k][j] == rlatin[i - 1][j] then
                            if r < rows.length - 1 then
                                throw :outer
                            end
                            if i > 2 then
                                return
                            end
                        end
                    end
                end
                if i < n then
                    recurse.call(i + 1)
                else
                    count = count + 1
                    if echo then
                        printSquare(rlatin)
                    end
                end
            end
        end
    }

    # remaining rows
    recurse.call(2)
    return count
end

def factorial(n)
    if n == 0 then
        return 1
    end
    prod = 1
    for i in 2 .. n
        prod = prod * i
    end
    return prod
end

print "The four reduced latin squares of order 4 are:\n"
reducedLatinSquares(4, true)

print "The size of the set of reduced latin squares for the following orders\n"
print "and hence the total number of latin squares of these orders are:\n"
for n in 1 .. 6
    size = reducedLatinSquares(n, false)
    f = factorial(n - 1)
    f = f * f * n * size
    print "Order %d Size %-4d x %d! x %d! => Total %d\n" % [n, size, n, n - 1, f]
end


Law of cosines - triples

The Law of cosines states that for an angle g, (gamma) of any triangle, if the sides adjacent to the angle are A and B and the side opposite is C; then the lengths of the sides are related by this formula:
           A2 + B2 - 2ABcos(g) = C2

;Specific angles:
For an angle of of   '''90o'''   this becomes the more familiar "Pythagoras equation":
           A2 + B2  =  C2

For an angle of   '''60o'''   this becomes the less familiar  equation:
           A2 + B2 - AB  =  C2

And finally for an angle of   '''120o'''   this becomes the equation:
           A2 + B2 + AB  =  C2

;Task:
*   Find all integer solutions (in order) to the three specific cases, distinguishing between each angle being considered.
*   Restrain all sides to the integers   '''1..13'''   inclusive.
*   Show how many results there are for each of the three angles mentioned above.
*   Display results on this page.

Note: Triangles with the same length sides but different order are to be treated as the same.

;Optional Extra credit:
* How many 60deg integer triples are there for sides in the range 1..10_000 ''where the sides are not all of the same length''.

;Related Task
* [[Pythagorean triples]]

;See also:
* Visualising Pythagoras: ultimate proofs and crazy contortions Mathlogger Video

Solution:
grouped =  (1..13).to_a.repeated_permutation(3).group_by do |a,b,c|
  sumaabb, ab = a*a + b*b, a*b
  case c*c
    when sumaabb      then 90
    when sumaabb - ab then 60
    when sumaabb + ab then 120
  end
end

grouped.delete(nil)
res = grouped.transform_values{|v| v.map(&:sort).uniq }

res.each do |k,v|
  puts "For an angle of #{k} there are #{v.size} solutions:"
  puts v.inspect, "\n"
end


Least common multiple

Compute the   least common multiple   (LCM)   of two integers.

Given   ''m''   and   ''n'',   the least common multiple is the smallest positive integer that has both   ''m''   and   ''n''   as factors.

;Example:
The least common multiple of   '''12'''   and   '''18'''   is   '''36''',       because:
:*   '''12'''   is a factor     ('''12''' x '''3''' = '''36'''),     and
:*   '''18'''   is a factor     ('''18''' x '''2''' = '''36'''),     and
:*   there is no positive integer less than   '''36'''   that has both factors.

As a special case,   if either   ''m''   or   ''n''   is zero,   then the least common multiple is zero.

One way to calculate the least common multiple is to iterate all the multiples of   ''m'',   until you find one that is also a multiple of   ''n''.

If you already have   ''gcd''   for [[greatest common divisor]],   then this formula calculates   ''lcm''.

:::: \operatorname{lcm}(m, n) = \frac{|m \times n|}{\operatorname{gcd}(m, n)}

One can also find   ''lcm''   by merging the [[prime decomposition]]s of both   ''m''   and   ''n''.

;Related task
:*   greatest common divisor.

;See also:
*   MathWorld entry:   Least Common Multiple.
*   Wikipedia entry:   Least common multiple.

Solution:
def gcd(m, n)
  m, n = n, m % n until n.zero?
  m.abs
end

def lcm(*args)
  args.inject(1) do |m, n|
    return 0 if n.zero?
    (m * n).abs / gcd(m, n)
  end
end

p lcm 12, 18, 22
p lcm 15, 14, -6, 10, 21


Left factorials

'''Left factorials''',   !n,   may refer to either   ''subfactorials''   or to   ''factorial sums'';
the same notation can be confusingly seen being used for the two different definitions.

Sometimes,   ''subfactorials''   (also known as ''derangements'')   may use any of the notations:
:::::::*     !''n''`
:::::::*     !''n''
:::::::*     ''n''!

(It may not be visually obvious, but the last example uses an upside-down exclamation mark.)

This Rosetta Code task will be using this formula   (''factorial sums'')   for   '''left factorial''':

:::::    !n = \sum_{k=0}^{n-1} k!

:::: where

:::::   !0 = 0

;Task
Display the left factorials for:
*   zero      through        ten     (inclusive)
*   20   through   110          (inclusive)   by tens

Display the length (in decimal digits) of the left factorials for:
*   1,000   through   10,000   (inclusive), by thousands.

;Also see:
*   The OEIS entry: A003422 left factorials
*   The MathWorld entry: left factorial
*   The MathWorld entry: factorial sums
*   The MathWorld entry: subfactorial

;Related task:
*   permutations/derangements (subfactorials)

Solution:
tens = 20.step(110, 10)
thousands = 1000.step(10_000, 1000)

10001.times do |n|
  lf = left_fact.next
  case n
  when 0..10, *tens
    puts "!#{n} = #{lf}"
  when *thousands
    puts "!#{n} has #{lf.to_s.size} digits"
  end
end


Levenshtein distance

{{Wikipedia}}

In information theory and computer science, the '''Levenshtein distance''' is a edit distance). The Levenshtein distance between two strings is defined as the minimum number of edits needed to transform one string into the other, with the allowable edit operations being insertion, deletion, or substitution of a single character.

;Example:
The Levenshtein distance between "'''kitten'''" and "'''sitting'''" is 3, since the following three edits change one into the other, and there isn't a way to do it with fewer than three edits:
::#   '''k'''itten    '''s'''itten       (substitution of 'k' with 's')
::#   sitt'''e'''n    sitt'''i'''n       (substitution of 'e' with 'i')
::#   sittin          sittin'''g'''      (insert 'g' at the end).

''The Levenshtein distance between   "'''rosettacode'''",   "'''raisethysword'''"   is   '''8'''.

''The distance between two strings is same as that when both strings are reversed.''

;Task:
Implements a Levenshtein distance function, or uses a library function, to show the Levenshtein distance between   "kitten"   and   "sitting".

;Related task:
*   [[Longest common subsequence]]

Solution:
module Levenshtein

  def self.distance(a, b)
    a, b = a.downcase, b.downcase
    costs = Array(0..b.length) # i == 0
    (1..a.length).each do |i|
      costs[0], nw = i, i - 1  # j == 0; nw is lev(i-1, j)
      (1..b.length).each do |j|
        costs[j], nw = [costs[j] + 1, costs[j-1] + 1, a[i-1] == b[j-1] ? nw : nw + 1].min, costs[j]
      end
    end
    costs[b.length]
  end

  def self.test
    %w{kitten sitting saturday sunday rosettacode raisethysword}.each_slice(2) do |a, b|
      puts "distance(#{a}, #{b}) = #{distance(a, b)}"
    end
  end

end

Levenshtein.test


Levenshtein distance/Alignment

The [[Levenshtein distance]] algorithm returns the number of atomic operations (insertion, deletion or edition) that must be performed on a string in order to obtain an other one, but it does not say anything about the actual operations used or their order.

An alignment is a notation used to describe the operations used to turn a string into an other.  At some point in the strings, the minus character ('-') is placed in order to signify that a character must be added at this very place.  For instance, an alignment between the words 'place' and 'palace' is:

P-LACE
PALACE

;Task:
Write a function that shows the alignment of two strings for the corresponding levenshtein distance.

As an example, use the words "rosettacode" and "raisethysword".

You can either implement an algorithm, or use a dedicated library (thus showing us how it is named in your language).

Solution:
require 'lcs'

def levenshtein_align(a, b)
  apos, bpos = LCS.new(a, b).backtrack2

  c = ""
  d = ""
  x0 = y0 = -1
  dx = dy = 0
  apos.zip(bpos) do |x,y|
    diff = x + dx - y - dy
    if diff < 0
      dx -= diff
      c += "-" * (-diff)
    elsif diff > 0
      dy += diff
      d += "-" * diff
    end
    c += a[x0+1..x]
    x0 = x
    d += b[y0+1..y]
    y0 = y
  end

  c += a[x0+1..-1]
  d += b[y0+1..-1]
  diff = a.length + y0 - b.length - x0
  if diff < 0
    c += "-" * (-diff)
  elsif diff > 0
    d += "-" * diff
  end
  [c, d]
end

puts levenshtein_align("rosettacode", "raisethysword")


List rooted trees

You came back from grocery shopping.    After putting away all the goods, you are left with a pile of plastic bags, which you want to save for later use, so you take one bag and stuff all the others into it, and throw it under the sink.   In doing so, you realize that there are various ways of nesting the bags, with all bags viewed as identical.

If we use a matching pair of parentheses to represent a bag, the ways are:

For 1 bag, there's one way:
  ()	<- a bag

for 2 bags, there's one way:
  (())	<- one bag in another

for 3 bags, there are two:
  ((())) <- 3 bags nested Russian doll style
  (()()) <- 2 bags side by side, inside the third

for 4 bags, four:
  (()()())
  ((())())
  ((()()))
  (((())))

Note that because all bags are identical, the two 4-bag strings ((())()) and (()(())) represent the same configuration.

It's easy to see that each configuration for ''n'' bags represents a ''n''-node rooted tree, where a bag is a tree node, and a bag with its content forms a subtree.  The outermost bag is the tree root.  Number of configurations for given ''n'' is given by OEIS A81.

;Task:
Write a program that, when given ''n'', enumerates all ways of nesting ''n'' bags.   You can use the parentheses notation above, or any tree representation that's unambiguous and preferably intuitive.

This task asks for enumeration of trees only; for counting solutions without enumeration, that OEIS page lists various formulas, but that's not encouraged by this task, especially if implementing it would significantly increase code size.

As an example output, run 5 bags.   There should be 9 ways.

Solution:
TREE_LIST = []
OFFSET = []

for i in 0..31
    if i == 1 then
        OFFSET << 1
    else
        OFFSET << 0
    end
end

def append(t)
    TREE_LIST << (1 | (t << 1))
end

def show(t, l)
    while l > 0
        l = l - 1
        if t % 2 == 1 then
            print '('
        else
            print ')'
        end
        t = t >> 1
    end
end

def listTrees(n)
    for i in OFFSET[n] .. OFFSET[n + 1] - 1
        show(TREE_LIST[i], n * 2)
        print "\n"
    end
end

def assemble(n, t, sl, pos, rem)
    if rem == 0 then
        append(t)
        return
    end

    if sl > rem then
        sl = rem
        pos = OFFSET[sl]
    elsif pos >= OFFSET[sl + 1] then
        sl = sl - 1
        if sl == 0 then
            return
        end
        pos = OFFSET[sl]
    end

    assemble(n, t << (2 * sl) | TREE_LIST[pos], sl, pos, rem - sl)
    assemble(n, t, sl, pos + 1, rem)
end

def makeTrees(n)
    if OFFSET[n + 1] != 0 then
        return
    end
    if n > 0 then
        makeTrees(n - 1)
    end
    assemble(n, 0, n - 1, OFFSET[n - 1], n - 1)
    OFFSET[n + 1] = TREE_LIST.length()
end

def test(n)
    if n < 1 || n > 12 then
        raise ArgumentError.new("Argument must be between 1 and 12")
    end

    append(0)

    makeTrees(n)
    print "Number of %d-trees: %d\n" % [n, OFFSET[n + 1] - OFFSET[n]]
    listTrees(n)
end

test(5)


Long literals, with continuations

This task is about writing a computer program that has long literals   (character
literals that may require specifying the words/tokens on more than one (source)
line,   either with continuations or some other method, such as abutments or
concatenations   (or some other mechanisms).

The literal is to be in the form of a "list",    a literal that contains many
words (tokens) separated by a blank (space),   in this case   (so as to have a
common list),   the (English) names of the chemical elements of the periodic table.

The list is to be in (ascending) order of the (chemical) element's atomic number:

 ''hydrogen helium lithium beryllium boron carbon nitrogen oxygen fluorine neon sodium aluminum silicon ...''

... up to the last known (named) chemical element   (at this time).

Do not include any of the   "unnamed"   chemical element names such as:

 ''ununennium unquadnilium triunhexium penthextrium penthexpentium septhexunium octenntrium ennennbium''

To make computer programming languages comparable,   the statement widths should be
restricted to less than   '''81'''   bytes (characters),   or less
if a computer programming language has more restrictive limitations or standards.

Also mention what column the programming statements can start in if   ''not''
in column one.

The list   ''may''   have leading/embedded/trailing blanks during the
declaration   (the actual program statements),   this is allow the list to be
more readable.   The "final" list shouldn't have any leading/trailing or superfluous
blanks   (when stored in the program's "memory").

This list should be written with the idea in mind that the
program   ''will''   be updated,   most likely someone other than the
original author,   as there will be newer (discovered) elements of the periodic
table being added   (possibly in the near future).   These future updates
should be one of the primary concerns in writing these programs and it should be "easy"
for someone else to add chemical elements to the list   (within the computer
program).

Attention should be paid so as to not exceed the   ''clause length''   of
continued or specified statements,   if there is such a restriction.   If the
limit is greater than (say) 4,000 bytes or so,   it needn't be mentioned here.

;Task:
:*   Write a computer program (by whatever name) to contain a list of the known elements.
:*   The program should eventually contain a long literal of words   (the elements).
:*   The literal should show how one could create a long list of blank-delineated words.
:*   The "final" (stored) list should only have a single blank between elements.
:*   Try to use the most idiomatic approach(es) in creating the final list.
:*   Use continuation if possible, and/or show alternatives   (possibly using concatenation).
:*   Use a program comment to explain what the continuation character is if it isn't obvious.
:*   The program should contain a variable that has the date of the last update/revision.
:*   The program, when run, should display with verbiage:
:::*   The last update/revision date   (and should be unambiguous).
:::*   The number of chemical elements in the list.
:::*   The name of the highest (last) element name.

Show all output here, on this page.

Solution:
elements = %w(
hydrogen     helium        lithium      beryllium
boron        carbon        nitrogen     oxygen
fluorine     neon          sodium       magnesium
aluminum     silicon       phosphorous  sulfur
chlorine     argon         potassium    calcium
scandium     titanium      vanadium     chromium
manganese    iron          cobalt       nickel
copper       zinc          gallium      germanium
arsenic      selenium      bromine      krypton
rubidium     strontium     yttrium      zirconium
niobium      molybdenum    technetium   ruthenium
rhodium      palladium     silver       cadmium
indium       tin           antimony     tellurium
iodine       xenon         cesium       barium
lanthanum    cerium        praseodymium neodymium
promethium   samarium      europium     gadolinium
terbium      dysprosium    holmium      erbium
thulium      ytterbium     lutetium     hafnium
tantalum     tungsten      rhenium      osmium
iridium      platinum      gold         mercury
thallium     lead          bismuth      polonium
astatine     radon         francium     radium
actinium     thorium       protactinium uranium
neptunium    plutonium     americium    curium
berkelium    californium   einsteinium  fermium
mendelevium  nobelium      lawrencium   rutherfordium
dubnium      seaborgium    bohrium      hassium
meitnerium   darmstadtium  roentgenium  copernicium
nihonium     flerovium     moscovium    livermorium
tennessine   oganesson)

puts "Last mutation #{ File.mtime(__FILE__) }
number of elements: #{elements.size}
last element: #{elements.last}"


Long year

Most years have 52 weeks, some have 53, according to ISO8601.

;Task:
Write a function which determines if a given year is long (53 weeks) or not, and demonstrate it.

Solution:
require 'date'

def long_year?(year = Date.today.year)
  Date.new(year, 12, 28).cweek == 53
end

(2020..2030).each{|year| puts "#{year} is long? #{ long_year?(year) }." }


Longest common subsequence

'''Introduction'''

Define a ''subsequence'' to be any output string obtained by deleting zero or more symbols from an input string.

The '''Longest Common Subsequence''' ('''LCS''') is a subsequence of maximum length common to two or more strings.

Let ''A''  ''A''[0]... ''A''[m - 1] and ''B''  ''B''[0]... ''B''[n - 1], m < n be strings drawn from an alphabet S of size s, containing every distinct symbol in A + B.

An ordered pair (i, j) will be referred to as a match if ''A''[i] = ''B''[j], where 0 <= i < m and 0 <= j < n.

The set of matches '''M''' defines a relation over matches: '''M'''[i, j] = (i, j)  '''M'''.

Define a ''non-strict'' product-order (<=) over ordered pairs, such that (i1, j1) <= (i2, j2) = i1 <= i2 and j1 <= j2.  We define (>=) similarly.

We say ordered pairs p1 and p2 are ''comparable'' if either p1 <= p2 or p1 >= p2 holds.  If i1 < i2 and j2 < j1 (or i2 < i1 and j1 < j2) then neither p1 <= p2 nor p1 >= p2 are possible, and we say p1 and p2 are ''incomparable''.

Define the ''strict'' product-order (<) over ordered pairs, such that (i1, j1) < (i2, j2) = i1 < i2 and j1 < j2.  We define (>) similarly.

A chain '''C''' is a subset of '''M''' consisting of at least one element m; and where either m1 < m2 or m1 > m2 for every pair of distinct elements m1 and m2.  An antichain '''D''' is any subset of '''M''' in which every pair of distinct elements m1 and m2 are incomparable.

A chain can be visualized as a strictly increasing curve that passes through matches (i, j) in the m*n coordinate space of '''M'''[i, j].

Every Common Sequence of length ''q'' corresponds to a chain of cardinality ''q'', over the set of matches '''M'''.  Thus, finding an LCS can be restated as the problem of finding a chain of maximum cardinality ''p''.

According to [Dilworth 1950], this cardinality ''p'' equals the minimum number of disjoint antichains into which '''M''' can be decomposed.  Note that such a decomposition into the minimal number p of disjoint antichains may not be unique.

'''Background'''

Where the number of symbols appearing in matches is small relative to the length of the input strings, reuse of the symbols increases; and the number of matches will tend towards O(''m*n'') quadratic growth.  This occurs, for example, in the Bioinformatics application of nucleotide and protein sequencing.

The divide-and-conquer approach of [Hirschberg 1975] limits the space required to O(''n'').  However, this approach requires O(''m*n'') time even in the best case.

This quadratic time dependency may become prohibitive, given very long input strings.  Thus, heuristics are often favored over optimal Dynamic Programming solutions.

In the application of comparing file revisions, records from the input files form a large symbol space; and the number of symbols approaches the length of the LCS.  In this case the number of matches reduces to linear, O(''n'') growth.

A binary search optimization due to [Hunt and Szymanski 1977] can be applied to the basic Dynamic Programming approach, resulting in an expected performance of O(''n log m'').  Performance can degrade to O(''m*n log m'') time in the worst case, as the number of matches grows to O(''m*n'').

'''Note'''

[Rick 2000] describes a linear-space algorithm with a time bound of O(''n*s + p*min(m, n - p)'').

'''Legend'''

 A, B are input strings of lengths m, n respectively
 p is the length of the LCS
 M is the set of matches (i, j) such that A[i] = B[j]
 r is the magnitude of M
 s is the magnitude of the alphabet S of distinct symbols in A + B

'''References'''

[Dilworth 1950] "A decomposition theorem for partially ordered sets"
by Robert P. Dilworth, published January 1950,
Annals of Mathematics [Volume 51, Number 1, ''pp.'' 161-166]

[Goeman and Clausen 2002] "A New Practical Linear Space Algorithm for the Longest Common
Subsequence Problem" by Heiko Goeman and Michael Clausen,
published 2002, Kybernetika [Volume 38, Issue 1, ''pp.'' 45-66]

[Hirschberg 1975] "A linear space algorithm for computing maximal common subsequences"
by Daniel S. Hirschberg, published June 1975
Communications of the ACM [Volume 18, Number 6, ''pp.'' 341-343]

[Hunt and McIlroy 1976] "An Algorithm for Differential File Comparison"
by James W. Hunt and M. Douglas McIlroy, June 1976
Computing Science Technical Report, Bell Laboratories 41

[Hunt and Szymanski 1977] "A Fast Algorithm for Computing Longest Common Subsequences"
by James W. Hunt and Thomas G. Szymanski, published May 1977
Communications of the ACM [Volume 20, Number 5, ''pp.'' 350-353]

[Rick 2000] "Simple and fast linear space computation of longest common subsequences"
by Claus Rick, received 17 March 2000, Information Processing Letters,
Elsevier Science [Volume 75, ''pp.'' 275-281]

'''Examples'''

The sequences "1234" and "1224533324" have an LCS of "1234":
 '''1234'''
 '''12'''245'''3'''332'''4'''

For a string example, consider the sequences "thisisatest" and "testing123testing". An LCS would be "tsitest":
 '''t'''hi'''si'''sa'''test'''
 '''t'''e'''s'''t'''i'''ng123'''test'''ing

In this puzzle, your code only needs to deal with strings. Write a function which returns an LCS of two strings (case-sensitive). You don't need to show multiple LCS's.

For more information on this problem please see Wikipedia.

Solution:
===Recursion===
This solution is similar to the Haskell one. It is slow (The time complexity is exponential.)


Longest common subsequence

Solution:
class LCS
  SELF, LEFT, UP, DIAG = [0,0], [0,-1], [-1,0], [-1,-1]

  def initialize(a, b)
    @m = Array.new(a.length) { Array.new(b.length) }
    a.each_char.with_index do |x, i|
      b.each_char.with_index do |y, j|
        match(x, y, i, j)
      end
    end
  end

  def match(c, d, i, j)
    @i, @j = i, j
    @m[i][j] = compute_entry(c, d)
  end

  def lookup(x, y)        [@i+x, @j+y]                      end
  def valid?(i=@i, j=@j)  i >= 0 && j >= 0                  end

  def peek(x, y)
    i, j = lookup(x, y)
    valid?(i, j) ? @m[i][j] : 0
  end

  def compute_entry(c, d)
    c == d ? peek(*DIAG) + 1 : [peek(*LEFT), peek(*UP)].max
  end

  def backtrack
    @i, @j = @m.length-1, @m[0].length-1
    y = []
    y << @i+1 if backstep? while valid?
    y.reverse
  end

  def backtrack2
    @i, @j = @m.length-1, @m[0].length-1
    y = []
    y << @j+1 if backstep? while valid?
    [backtrack, y.reverse]
  end

  def backstep?
    backstep = compute_backstep
    @i, @j = lookup(*backstep)
    backstep == DIAG
  end

  def compute_backstep
    case peek(*SELF)
    when peek(*LEFT) then LEFT
    when peek(*UP)   then UP
    else                  DIAG
    end
  end
end

def lcs(a, b)
  walker = LCS.new(a, b)
  walker.backtrack.map{|i| a[i]}.join
end

if $0 == __FILE__
  puts lcs('thisisatest', 'testing123testing')
  puts lcs("rosettacode", "raisethysword")
end


Longest common substring

Write a function that returns the longest common substring of two strings.

Use it within a program that demonstrates sample output from the function, which will consist of the longest common substring between "thisisatest" and "testing123testing".

Note that substrings are consecutive characters within a string.   This distinguishes them from subsequences, which is any sequence of characters within a string, even if there are extraneous characters in between them.

Hence, the [[longest common subsequence]] between "thisisatest" and "testing123testing" is "tsitest", whereas the longest common sub''string'' is just "test".

;References:
*Generalize Suffix Tree
*[[Ukkonen's Suffix Tree Construction]]

Solution:
def longest_common_substring(a,b)
  lengths = Array.new(a.length){Array.new(b.length, 0)}
  greatestLength = 0
  output = ""
  a.each_char.with_index do |x,i|
    b.each_char.with_index do |y,j|
      next if x != y
      lengths[i][j] = (i.zero? || j.zero?) ? 1 : lengths[i-1][j-1] + 1
      if lengths[i][j] > greatestLength
        greatestLength = lengths[i][j]
        output = a[i - greatestLength + 1, greatestLength]
      end
    end
  end
  output
end

p longest_common_substring("thisisatest", "testing123testing")


Longest increasing subsequence

Calculate and show here a longest increasing subsequence of the list:
:\{3, 2, 6, 4, 5, 1\}
And of the list:
:\{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15\}

Note that a list may have more than one subsequence that is of the maximum length.

;Ref:
# Dynamic Programming #1: Longest Increasing Subsequence on YouTube
# An efficient solution can be based on Patience sorting.

Solution:
Node = Struct.new(:val, :back)

def lis(n)
  pileTops = []
  # sort into piles
  for x in n
    # binary search
    low, high = 0, pileTops.size-1
    while low <= high
      mid = low + (high - low) / 2
      if pileTops[mid].val >= x
        high = mid - 1
      else
        low = mid + 1
      end
    end
    i = low
    node = Node.new(x)
    node.back = pileTops[i-1]  if i > 0
    pileTops[i] = node
  end

  result = []
  node = pileTops.last
  while node
    result.unshift(node.val)
    node = node.back
  end
  result
end

p lis([3, 2, 6, 4, 5, 1])
p lis([0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15])


Lucky and even lucky numbers

Note that in the following explanation list indices are assumed to start at ''one''.

;Definition of lucky numbers
''Lucky numbers'' are positive integers that are formed by:

# Form a list of all the positive odd integers > 01, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39 ...
# Return the first number from the list (which is '''1''').
# (Loop begins here)
#* Note then return the second number from the list (which is '''3''').
#* Discard every third, (as noted), number from the list to form the new list1, 3, 7, 9, 13, 15, 19, 21, 25, 27, 31, 33, 37, 39, 43, 45, 49, 51, 55, 57 ...
# (Expanding the loop a few more times...)
#* Note then return the third number from the list (which is '''7''').
#* Discard every 7th, (as noted), number from the list to form the new list1, 3, 7, 9, 13, 15, 21, 25, 27, 31, 33, 37, 43, 45, 49, 51, 55, 57, 63, 67 ...
#* Note then return the 4th number from the list (which is '''9''').
#* Discard every 9th, (as noted), number from the list to form the new list1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 45, 49, 51, 55, 63, 67, 69, 73 ...
#* Take the 5th, i.e. '''13'''.  Remove every 13th.
#* Take the 6th, i.e. '''15'''.  Remove every 15th.
#* Take the 7th, i.e. '''21'''.  Remove every 21th.
#* Take the 8th, i.e. '''25'''.  Remove every 25th.
# (Rule for the loop)
#* Note the nth, which is m.
#* Remove every mth.
#* Increment n.

;Definition of even lucky numbers
This follows the same rules as the definition of lucky numbers above ''except for the very first step'':
# Form a list of all the positive '''even''' integers > 02, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40 ...
# Return the first number from the list (which is '''2''').
# (Loop begins here)
#* Note then return the second number from the list (which is '''4''').
#* Discard every 4th, (as noted), number from the list to form the new list2, 4, 6, 10, 12, 14, 18, 20, 22, 26, 28, 30, 34, 36, 38, 42, 44, 46, 50, 52 ...
# (Expanding the loop a few more times...)
#* Note then return the third number from the list (which is '''6''').
#* Discard every 6th, (as noted), number from the list to form the new list2, 4, 6, 10, 12, 18, 20, 22, 26, 28, 34, 36, 38, 42, 44, 50, 52, 54, 58, 60 ...
#* Take the 4th, i.e. '''10'''.  Remove every 10th.
#* Take the 5th, i.e. '''12'''.  Remove every 12th.
# (Rule for the loop)
#* Note the nth, which is m.
#* Remove every mth.
#* Increment n.

;Task requirements
* Write one or two subroutines (functions) to generate ''lucky numbers'' and ''even lucky numbers''
* Write a command-line interface to allow selection of which kind of numbers and which number(s). Since input is from the command line, tests should be made for the common errors:
** missing arguments
** too many arguments
** number (or numbers) aren't legal
** misspelled argument ('''lucky''' or '''evenLucky''')
* The command line handling should:
** support mixed case handling of the (non-numeric) arguments
** support printing a particular number
** support printing a range of numbers by their index
** support printing a range of numbers by their values
* The resulting list of numbers should be printed on a single line.

The program should support the arguments:

                             what is displayed  (on a single line)
       argument(s)              (optional verbiage is encouraged)
  +-------------------+----------------------------------------------------+
  |  j                |  Jth       lucky number                            |
  |  j  ,      lucky  |  Jth       lucky number                            |
  |  j  ,  evenLucky  |  Jth  even lucky number                            |
  |                   |                                                    |
  |  j  k             |  Jth  through  Kth (inclusive)       lucky numbers |
  |  j  k      lucky  |  Jth  through  Kth (inclusive)       lucky numbers |
  |  j  k  evenLucky  |  Jth  through  Kth (inclusive)  even lucky numbers |
  |                   |                                                    |
  |  j -k             |  all       lucky numbers in the range  j --> |k|   |
  |  j -k      lucky  |  all       lucky numbers in the range  j --> |k|   |
  |  j -k  evenLucky  |  all  even lucky numbers in the range  j --> |k|   |
  +-------------------+----------------------------------------------------+
                           where    |k|    is the absolute value of   k

Demonstrate the program by:
* showing the first twenty ''lucky'' numbers
* showing the first twenty ''even lucky'' numbers
* showing all ''lucky'' numbers between 6,000 and 6,100 (inclusive)
* showing all ''even lucky'' numbers in the same range as above
* showing the 10,000th ''lucky'' number (extra credit)
* showing the 10,000th ''even lucky'' number (extra credit)

;See also:
* This task is related to the [[Sieve of Eratosthenes]] task.
* OEIS Wiki Lucky numbers.
* Sequence A000959 lucky numbers on The On-Line Encyclopedia of Integer Sequences.
* Sequence A045954 even lucky numbers or ELN on The On-Line Encyclopedia of Integer Sequences.
* Entry lucky numbers on The Eric Weisstein's World of Mathematics.

Solution:
def generator(even=false, nmax=1000000)
  start = even ? 2 : 1
  Enumerator.new do |y|
    n = 1
    ary = [0] + (start..nmax).step(2).to_a      # adds [0] to revise the 0 beginnings.
    y << ary[n]
    while (m = ary[n+=1]) < ary.size
      y << m
      (m...ary.size).step(m){|i| ary[i]=nil}
      ary.compact!                              # remove nil
    end
    # drain
    ary[n..-1].each{|i| y << i}
    raise StopIteration
  end
end

def lucky(argv)
  j, k = argv[0].to_i, argv[1].to_i
  mode = /even/i=~argv[2] ? :'even lucky' : :lucky
  seq = generator(mode == :'even lucky')
  ord = ->(n){"#{n}#{(n%100).between?(11,19) ? 'th' : %w[th st nd rd th th th th th th][n%10]}"}
  if k.zero?
    puts "#{ord[j]} #{mode} number: #{seq.take(j).last}"
  elsif 0 < k
    puts "#{ord[j]} through #{ord[k]} (inclusive) #{mode} numbers",
         "  #{seq.take(k)[j-1..-1]}"
  else
    k = -k
    ary = []
    loop do
      case num=seq.next
      when 1...j
      when j..k  then ary << num
      else break
      end
    end
    puts "all #{mode} numbers in the range #{j}..#{k}",
         "  #{ary}"
  end
end

if __FILE__ == $0
  lucky(ARGV)
end


Lychrel numbers

::#   Take an integer n, greater than zero.
::#   Form the next n of its series by reversing the digits of the current n and adding the result to the current n.
::#   Stop when n becomes palindromic - i.e. the digits of n in reverse order == n.

The above recurrence relation when applied to most starting numbers n = 1, 2, ... terminates in a palindrome quite quickly.

;Example:
If n0 = 12 we get

       12
       12 +  21 =  33,   a palindrome!

And if n0 = 55 we get

       55
       55 +  55 = 110
      110 + 011 = 121,   a palindrome!

Notice that the check for a palindrome happens   ''after''   an addition.

Some starting numbers seem to go on forever; the recurrence relation for 196 has been calculated for millions of repetitions forming numbers with millions of digits, without forming a palindrome.

These numbers that do not end in a palindrome are called '''Lychrel numbers'''.

For the purposes of this task a Lychrel number is any starting number that does not form a palindrome within 500 (or more) iterations.

;Seed and related Lychrel numbers:
Any integer produced in the sequence of a Lychrel number is also a Lychrel number.

In general, any sequence from one Lychrel number ''might'' converge to join the sequence from a prior Lychrel number candidate; for example the sequences for the numbers 196 and then 689 begin:

        196
        196 +    691 =   887
        887 +    788 =  1675
       1675 +   5761 =  7436
       7436 +   6347 = 13783
      13783 +  38731 = 52514
      52514 +  41525 = 94039
       ...

        689
        689 +    986 =  1675
       1675 +   5761 =  7436
       ...

So we see that the sequence starting with 689 converges to, and continues with the same numbers as that for 196.

Because of this we can further split the Lychrel numbers into true '''Seed''' Lychrel number candidates, and '''Related''' numbers that produce no palindromes but have integers in their sequence seen as part of the sequence generated from a lower Lychrel number.

;Task:
*   Find the number of seed Lychrel number candidates and related numbers for n in the range 1..10000 inclusive. (With that iteration limit of 500).
*    Print the number of seed Lychrels found; the actual seed Lychrels; and just the ''number'' of relateds found.
*    Print any seed Lychrel or related number that is itself a palindrome.

Show all output here.

;References:
*   What's special about 196? Numberphile video.
*   A023108 Positive integers which apparently never result in a palindrome under repeated applications of the function f(x) = x + (x with digits reversed).
*   Status of the 196 conjecture? Mathoverflow.

Solution:
require 'set'

def add_reverse(num, max_iter=1000)
  (1..max_iter).each_with_object(Set.new([num])) do |_,nums|
    num += reverse_int(num)
    nums << num
    return nums if palindrome?(num)
  end
end

def palindrome?(num)
  num == reverse_int(num)
end

def reverse_int(num)
  num.to_s.reverse.to_i
end

def split_roots_from_relateds(roots_and_relateds)
  roots = roots_and_relateds.dup
  i = 1
  while i < roots.length
    this = roots[i]
    if roots[0...i].any?{|prev| this.intersect?(prev)}
      roots.delete_at(i)
    else
      i += 1
    end
  end
  root = roots.map{|each_set| each_set.min}
  related = roots_and_relateds.map{|each_set| each_set.min}
  related = related.reject{|n| root.include?(n)}
  return root, related
end

def find_lychrel(maxn, max_reversions)
  series = (1..maxn).map{|n| add_reverse(n, max_reversions*2)}
  roots_and_relateds = series.select{|s| s.length > max_reversions}
  split_roots_from_relateds(roots_and_relateds)
end

maxn, reversion_limit = 10000, 500
puts "Calculations using n = 1..#{maxn} and limiting each search to 2*#{reversion_limit} reverse-digits-and-adds"
lychrel, l_related = find_lychrel(maxn, reversion_limit)
puts "  Number of Lychrel numbers: #{lychrel.length}"
puts "    Lychrel numbers: #{lychrel}"
puts "  Number of Lychrel related: #{l_related.length}"
pals = (lychrel + l_related).select{|x| palindrome?(x)}.sort
puts "  Number of Lychrel palindromes: #{pals.length}"
puts "    Lychrel palindromes: #{pals}"


MAC vendor lookup

Every connected device around the world comes with a unique Media Access Control address, or a   MAC address.

A common task a network administrator may come across is being able to identify a network device's manufacturer when given only a MAC address.

;Task:
Interface with one (or numerous) APIs that exist on the internet and retrieve the device manufacturer based on a supplied MAC address.

A MAC address that does not return a valid result should return the String "N/A".   An error related to the network connectivity or the API should return a null result.

Many implementations on this page use http://api.macvendors.com/ which, as of 19th September 2021, is throttling requests. After only 2 calls, the following response is returned for all subsequent requests. If you are planning to use the same provider or going to run the examples on this page, consider building in a delay between two calls.

'''{"errors":{"detail":"Too Many Requests","message":"Please slow down your requests or upgrade your plan at https://macvendors.com"}}'''

Solution:
require 'net/http'

arr = ['88:53:2E:67:07:BE', 'FC:FB:FB:01:FA:21', 'D4:F4:6F:C9:EF:8D', '23:45:67']

arr.each do |addr|
  vendor = Net::HTTP.get('api.macvendors.com', "/#{addr}/") rescue nil
  puts "#{addr}  #{vendor}"
end


Mad Libs

{{wikipedia}}

Mad Libs is a phrasal template word game where one player prompts another for a list of words to substitute for blanks in a story, usually with funny results.

;Task;
Write a program to create a Mad Libs like story.

The program should read an arbitrary multiline story from input.

The story will be terminated with a blank line.

Then, find each replacement to be made within the story, ask the user for a word to replace it with, and make all the replacements.

Stop when there are none left and print the final story.

The input should be an arbitrary story in the form:

 went for a walk in the park.
found a .  decided to take it home.

Given this example, it should then ask for a name, a he or she and a noun ( gets replaced both times with the same value).

Solution:
puts "Enter a story, terminated by an empty line:"
story = ""
until (line = gets).chomp.empty?
  story << line
end

story.scan(/(?<=[<]).+?(?=[>])/).uniq.each do |var|
  print "Enter a value for '#{var}': "
  story.gsub!(/<#{var}>/, gets.chomp)
end

puts
puts story


Magic 8-ball

Create Magic 8-Ball.

See details at:   Magic 8-Ball.

Solution:
#!/usr/bin/ruby

class EightBall
  def initialize
    print "Welcome to 8 ball! Ask your question below. "
    puts "Type 'quit' to exit the program.\n\n"
    @responses = ["It is certain", "It is decidedly so",
                          "Without a doubt", "Yes, definitely",
                          "You may rely on it", "As I see it, yes",
                          "Most likely", "Outlook good",
                          "Signs point to yes", "Yes",
                          "Reply hazy, try again", "Ask again later",
                          "Better not tell you now",
                          "Cannot predict now",
                          "Concentrate and ask again", "Don't bet on it",
                          "My reply is no", "My sources say no",
                          "Outlook not so good", "Very doubtful"]
  end

  def ask_question
    print "Question: "
    question = gets

    if question.chomp.eql? "quit"
      exit(0)
    end

    puts "Response: #{@responses.sample} \n\n"
  end

  def run
    loop do
      ask_question
    end
  end
end

eight_ball = EightBall.new
eight_ball.run


Magic squares of doubly even order

Solution:
def double_even_magic_square(n)
  raise ArgumentError, "Need multiple of four" if n%4 > 0
  block_size, max = n/4, n*n
  pre_pat = [true, false, false, true,
             false, true, true, false]
  pre_pat += pre_pat.reverse
  pattern = pre_pat.flat_map{|b| [b] * block_size} * block_size
  flat_ar = pattern.each_with_index.map{|yes, num| yes ? num+1 : max-num}
  flat_ar.each_slice(n).to_a
end

def to_string(square)
  n = square.size
  fmt = "%#{(n*n).to_s.size + 1}d" * n
  square.inject(""){|str,row| str << fmt % row << "\n"}
end

puts to_string(double_even_magic_square(8))


Magic squares of odd order

A magic square is an   '''NxN'''   square matrix whose numbers (usually integers) consist of consecutive numbers arranged so that the sum of each row and column,   ''and''   both long (main) diagonals are equal to the same sum (which is called the   ''magic number''   or   ''magic constant'').

The numbers are usually (but not always) the first   '''N'''2   positive integers.

A magic square whose rows and columns add up to a magic number but whose main diagonals do not, is known as a ''semimagic square''.

{| class="wikitable" style="float:right;border: 4px solid blue; background:lightgreen; color:black; margin-left:auto;margin-right:auto;text-align:center;width:15em;height:15em;table-layout:fixed;font-size:150%"
|-
| '''8''' || '''1''' || '''6'''
|-
| '''3''' || '''5''' || '''7'''
|-
| '''4''' || '''9''' || '''2'''
|}

;Task
For any odd   '''N''',   generate a magic square with the integers   ''' 1''' --> '''N''',   and show the results here.

Optionally, show the ''magic number''.

You should demonstrate the generator by showing at least a magic square for   '''N''' = '''5'''.

; Related tasks
* [[Magic squares of singly even order]]
* [[Magic squares of doubly even order]]

; See also:
* MathWorld(tm) entry: Magic_square
* Odd Magic Squares (1728.org)

Solution:
def odd_magic_square(n)
  raise ArgumentError "Need odd positive number" if n.even? || n <= 0
  n.times.map{|i| n.times.map{|j| n*((i+j+1+n/2)%n) + ((i+2*j-5)%n) + 1} }
end

[3, 5, 9].each do |n|
  puts "\nSize #{n}, magic sum #{(n*n+1)/2*n}"
  fmt = "%#{(n*n).to_s.size + 1}d" * n
  odd_magic_square(n).each{|row| puts fmt % row}
end


Magic squares of singly even order

A magic square is an '''NxN''' square matrix whose numbers consist of consecutive numbers arranged so that the sum of each row and column, ''and'' both diagonals are equal to the same sum (which is called the ''magic number'' or ''magic constant'').

A  magic square of singly even order has a size that is a multiple of 4, plus 2 (e.g. 6, 10, 14). This means that the subsquares have an odd size, which plays a role in the construction.

;Task
Create a magic square of 6 x 6.

; Related tasks
* [[Magic squares of odd order]]
* [[Magic squares of doubly even order]]

; See also
* Singly Even Magic Squares (1728.org)

Solution:
def odd_magic_square(n)
  n.times.map{|i| n.times.map{|j| n*((i+j+1+n/2)%n) + ((i+2*j-5)%n) + 1} }
end

def single_even_magic_square(n)
  raise ArgumentError, "must be even, but not divisible by 4." unless (n-2) % 4 == 0
  raise ArgumentError, "2x2 magic square not possible." if n == 2

  order = (n-2)/4
  odd_square = odd_magic_square(n/2)
  to_add = (0..3).map{|f| f*n*n/4}
  quarts = to_add.map{|f| odd_square.dup.map{|row|row.map{|el| el+f}} }

  sq = []
  quarts[0].zip(quarts[2]){|d1,d2| sq << [d1,d2].flatten}
  quarts[3].zip(quarts[1]){|d1,d2| sq << [d1,d2].flatten}

  sq = sq.transpose
  order.times{|i| sq[i].rotate!(n/2)}
  swap(sq[0][order], sq[0][-order-1])
  swap(sq[order][order], sq[order][-order-1])
  (order-1).times{|i| sq[-(i+1)].rotate!(n/2)}
  randomize(sq)
end

def swap(a,b)
  a,b = b,a
end

def randomize(square)
  square.shuffle.transpose.shuffle
end

def to_string(square)
  n = square.size
  fmt = "%#{(n*n).to_s.size + 1}d" * n
  square.inject(""){|str,row| str << fmt % row << "\n"}
end

puts to_string(single_even_magic_square(6))


Map range

Given two ranges:
:::*   [a_1,a_2]   and
:::*   [b_1,b_2];
:::*   then a value   s   in range   [a_1,a_2]
:::*   is linearly mapped to a value   t   in range   [b_1,b_2]
   where:

:::*   t = b_1 + {(s - a_1)(b_2 - b_1) \over (a_2 - a_1)}

;Task:
Write a function/subroutine/... that takes two ranges and a real number, and returns the mapping of the real number from the first to the second range.

Use this function to map values from the range    [0, 10]    to the range    [-1, 0].

;Extra credit:
Show additional idiomatic ways of performing the mapping, using tools available to the language.

Solution:
def map_range(a, b, s)
  af, al, bf, bl = a.first, a.last, b.first, b.last
  bf + (s - af)*(bl - bf).quo(al - af)
end

(0..10).each{|s| puts "%s maps to %g" % [s, map_range(0..10, -1..0, s)]}


Maximum triangle path sum

Starting from the top of a pyramid of numbers like this, you can walk down going one step on the right or on the left, until you reach the bottom row:

                          55
                        94 48
                       95 30 96
                     77 71 26 67

One of such walks is 55 - 94 - 30 - 26.
You can compute the total of the numbers you have seen in such walk,
in this case it's 205.

Your problem is to find the maximum total among all possible paths from the top to the bottom row of the triangle. In the little example above it's 321.

;Task:
Find the maximum total in the triangle below:

                          55
                        94 48
                       95 30 96
                     77 71 26 67
                    97 13 76 38 45
                  07 36 79 16 37 68
                 48 07 09 18 70 26 06
               18 72 79 46 59 79 29 90
              20 76 87 11 32 07 07 49 18
            27 83 58 35 71 11 25 57 29 85
           14 64 36 96 27 11 58 56 92 18 55
         02 90 03 60 48 49 41 46 33 36 47 23
        92 50 48 02 36 59 42 79 72 20 82 77 42
      56 78 38 80 39 75 02 71 66 66 01 03 55 72
     44 25 67 84 71 67 11 61 40 57 58 89 40 56 36
   85 32 25 85 57 48 84 35 47 62 17 01 01 99 89 52
  06 71 28 75 94 48 37 10 23 51 06 48 53 18 74 98 15
27 02 92 23 08 71 76 84 15 52 92 63 81 10 44 10 69 93

Such numbers can be included in the solution code, or read from a "triangle.txt" file.

This task is derived from the Euler Problem #18.

Solution:
triangle =
"                         55
                        94 48
                       95 30 96
                     77 71 26 67
                    97 13 76 38 45
                  07 36 79 16 37 68
                 48 07 09 18 70 26 06
               18 72 79 46 59 79 29 90
              20 76 87 11 32 07 07 49 18
            27 83 58 35 71 11 25 57 29 85
           14 64 36 96 27 11 58 56 92 18 55
         02 90 03 60 48 49 41 46 33 36 47 23
        92 50 48 02 36 59 42 79 72 20 82 77 42
      56 78 38 80 39 75 02 71 66 66 01 03 55 72
     44 25 67 84 71 67 11 61 40 57 58 89 40 56 36
   85 32 25 85 57 48 84 35 47 62 17 01 01 99 89 52
  06 71 28 75 94 48 37 10 23 51 06 48 53 18 74 98 15
27 02 92 23 08 71 76 84 15 52 92 63 81 10 44 10 69 93"

ar = triangle.each_line.map{|line| line.split.map(&:to_i)}
puts ar.inject([]){|res,x|
  maxes = [0, *res, 0].each_cons(2).map(&:max)
  x.zip(maxes).map{|a,b| a+b}
}.max
# => 1320


McNuggets problem

From Wikipedia:
 The McNuggets version of the coin problem was introduced by Henri Picciotto,
 who included it in his algebra textbook co-authored with Anita Wah. Picciotto
 thought of the application in the 1980s while dining with his son at
 McDonald's, working the problem out on a napkin. A McNugget number is
 the total number of McDonald's Chicken McNuggets in any number of boxes.
 In the United Kingdom, the original boxes (prior to the introduction of
 the Happy Meal-sized nugget boxes) were of 6, 9, and 20 nuggets.

;Task:
Calculate (from 0 up to a limit of 100) the largest non-McNuggets
number (a number ''n'' which cannot be expressed with ''6x + 9y + 20z = n''
where ''x'', ''y'' and ''z'' are natural numbers).

Solution:
def mcnugget(limit)
  sv = (0..limit).to_a

  (0..limit).step(6) do |s|
    (0..limit).step(9) do |n|
      (0..limit).step(20) do |t|
        sv.delete(s + n + t)
      end
    end
  end

  sv.max
end

puts(mcnugget 100)


Memory layout of a data structure

It is often useful to control the memory layout of fields in a data structure to match an interface control definition, or to interface with hardware. Define a data structure matching the RS-232 Plug Definition. Use the 9-pin definition for brevity.
 Pin Settings for Plug
 (Reverse order for socket.)
 __________________________________________
 1  2  3  4  5  6  7  8  9  10 11 12 13
  14 15 16 17 18 19 20 21 22 23 24 25
 _________________
 1  2  3  4  5
 6  7  8  9
 25 pin                        9 pin
 1 - PG   Protective ground
 2 - TD   Transmitted data     3
 3 - RD   Received data        2
 4 - RTS  Request to send      7
 5 - CTS  Clear to send        8
 6 - DSR  Data set ready       6
 7 - SG   Signal ground        5
 8 - CD   Carrier detect       1
 9 - + voltage (testing)
 10 - - voltage (testing)
 11 -
 12 - SCD  Secondary CD
 13 - SCS  Secondary CTS
 14 - STD  Secondary TD
 15 - TC   Transmit clock
 16 - SRD  Secondary RD
 17 - RC   Receiver clock
 18 -
 19 - SRS  Secondary RTS
 20 - DTR  Data terminal ready      4
 21 - SQD  Signal quality detector
 22 - RI   Ring indicator           9
 23 - DRS  Data rate select
 24 - XTC  External clock
 25 -

Solution:
require 'bit-struct'

class RS232_9 < BitStruct
  unsigned :cd,  1, "Carrier detect"       #1
  unsigned :rd,  1, "Received data"        #2
  unsigned :td,  1, "Transmitted data"     #3
  unsigned :dtr, 1, "Data terminal ready"  #4
  unsigned :sg,  1, "Signal ground"        #5
  unsigned :dsr, 1, "Data set ready"       #6
  unsigned :rts, 1, "Request to send"      #7
  unsigned :cts, 1, "Clear to send"        #8
  unsigned :ri,  1, "Ring indicator"       #9

  def self.new_with_int(value)
    data = {}
    fields.each_with_index {|f, i| data[f.name] = value[i]}
    new(data)
  end
end

num = rand(2**9 - 1)
puts "num = #{num}"

sample1 = RS232_9.new([("%09d" % num.to_s(2)).reverse].pack("B*"))
puts sample1.inspect_detailed

sample2 = RS232_9.new_with_int(num)
puts sample2.inspect_detailed

puts "CD is #{sample2.cd == 1 ? 'on' : 'off'}"


Metallic ratios

Many people have heard of the '''Golden ratio''', phi ('''ph'''). Phi is just one of a series
of related ratios that are referred to as the "'''Metallic ratios'''".

The '''Golden ratio''' was discovered and named by ancient civilizations as it was
thought to be the most pure and beautiful (like Gold). The '''Silver ratio''' was was
also known to the early Greeks, though was not named so until later as a nod to
the '''Golden ratio''' to which it is closely related. The series has been extended to
encompass all of the related ratios and was given the general name '''Metallic ratios''' (or ''Metallic means'').
''Somewhat incongruously as the original Golden ratio referred to the adjective "golden" rather than the metal "gold".''

'''Metallic ratios''' are the real roots of the general form equation:

          x2 - bx - 1 = 0

where the integer '''b''' determines which specific one it is.

Using the quadratic equation:

          ( -b +- (b2 - 4ac) ) / 2a = x

Substitute in (from the top equation) '''1''' for '''a''', '''-1''' for '''c''', and recognising that -b is negated we get:

          ( b +- (b2 + 4) ) ) / 2 = x

We only want the real root:

          ( b + (b2 + 4) ) ) / 2 = x

When we set '''b''' to '''1''', we get an irrational number: the '''Golden ratio'''.

          ( 1 + (12 + 4) ) / 2  =  (1 + 5) / 2 = ~1.618033989...

With '''b''' set to '''2''', we get a different irrational number: the '''Silver ratio'''.

          ( 2 + (22 + 4) ) / 2  =  (2 + 8) / 2 = ~2.414213562...

When the ratio '''b''' is '''3''', it is commonly referred to as the '''Bronze''' ratio, '''4''' and '''5'''
are sometimes called the '''Copper''' and '''Nickel''' ratios, though they aren't as
standard. After that there isn't really any attempt at standardized names. They
are given names here on this page, but consider the names fanciful rather than
canonical.

Note that technically, '''b''' can be '''0''' for a "smaller" ratio than the '''Golden ratio'''.
We will refer to it here as the '''Platinum ratio''', though it is kind-of a
degenerate case.

'''Metallic ratios''' where '''b''' > '''0''' are also defined by the irrational continued fractions:

          [b;b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b...]

So, The first ten '''Metallic ratios''' are:

:::::: {| class="wikitable" style="text-align: center;"
|+ Metallic ratios
!Name!!'''b'''!!Equation!!Value!!Continued fraction!!OEIS link
|-
|Platinum||0||(0 + 4) / 2|| 1||-||-
|-
|Golden||1||(1 + 5) / 2|| 1.618033988749895...||[1;1,1,1,1,1,1,1,1,1,1...]||[[OEIS:A001622]]
|-
|Silver||2||(2 + 8) / 2|| 2.414213562373095...||[2;2,2,2,2,2,2,2,2,2,2...]||[[OEIS:A014176]]
|-
|Bronze||3||(3 + 13) / 2|| 3.302775637731995...||[3;3,3,3,3,3,3,3,3,3,3...]||[[OEIS:A098316]]
|-
|Copper||4||(4 + 20) / 2|| 4.23606797749979...||[4;4,4,4,4,4,4,4,4,4,4...]||[[OEIS:A098317]]
|-
|Nickel||5||(5 + 29) / 2|| 5.192582403567252...||[5;5,5,5,5,5,5,5,5,5,5...]||[[OEIS:A098318]]
|-
|Aluminum||6||(6 + 40) / 2|| 6.16227766016838...||[6;6,6,6,6,6,6,6,6,6,6...]||[[OEIS:A176398]]
|-
|Iron||7||(7 + 53) / 2|| 7.140054944640259...||[7;7,7,7,7,7,7,7,7,7,7...]||[[OEIS:A176439]]
|-
|Tin||8||(8 + 68) / 2|| 8.123105625617661...||[8;8,8,8,8,8,8,8,8,8,8...]||[[OEIS:A176458]]
|-
|Lead||9||(9 + 85) / 2|| 9.109772228646444...||[9;9,9,9,9,9,9,9,9,9,9...]||[[OEIS:A176522]]
|}

There are other ways to find the '''Metallic ratios'''; one, (the focus of this task)
is through '''successive approximations of Lucas sequences'''.

A traditional '''Lucas sequence''' is of the form:

    x''n'' = P * x''n-1'' - Q * x''n-2''

and starts with the first 2 values '''0, 1'''.

For our purposes in this task, to find the metallic ratios we'll use the form:

    x''n'' = b * x''n-1'' + x''n-2''

( '''P''' is set to '''b''' and '''Q''' is set to '''-1'''. ) To avoid "divide by zero" issues we'll start the sequence with the first two terms '''1, 1'''. The initial starting value has very little effect on the final ratio or convergence rate. ''Perhaps it would be more accurate to call it a Lucas-like sequence.''

At any rate, when '''b = 1''' we get:

    x''n'' = x''n-1'' + x''n-2''

    1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144...

more commonly known as the Fibonacci sequence.

When '''b = 2''':

    x''n'' = 2 * x''n-1'' + x''n-2''

    1, 1, 3, 7, 17, 41, 99, 239, 577, 1393...

And so on.

To find the ratio by successive approximations, divide the ('''n+1''')th term by the
'''n'''th. As '''n''' grows larger, the ratio will approach the '''b''' metallic ratio.

For '''b = 1''' (Fibonacci sequence):

    1/1   = 1
    2/1   = 2
    3/2   = 1.5
    5/3   = 1.666667
    8/5   = 1.6
    13/8  = 1.625
    21/13 = 1.615385
    34/21 = 1.619048
    55/34 = 1.617647
    89/55 = 1.618182
    etc.

It converges, but pretty slowly. In fact, the '''Golden ratio''' has the slowest
possible convergence for any irrational number.

;Task

For each of the first '''10 Metallic ratios'''; '''b''' = '''0''' through '''9''':

* Generate the corresponding "Lucas" sequence.
* Show here, on this page, at least the first '''15''' elements of the "Lucas" sequence.
* Using successive approximations, calculate the value of the ratio accurate to '''32''' decimal places.
* Show the '''value''' of the '''approximation''' at the required accuracy.
* Show the '''value''' of '''n''' when the approximation reaches the required accuracy (How many iterations did it take?).

Optional, stretch goal - Show the '''value''' and number of iterations '''n''', to approximate the '''Golden ratio''' to '''256''' decimal places.

You may assume that the approximation has been reached when the next iteration does not cause the value (to the desired places) to change.

;See also
* Wikipedia: Metallic mean
* Wikipedia: Lucas sequence

Solution:
require('bigdecimal')
require('bigdecimal/util')

# An iterator over the Lucas Sequence for 'b'.
# (The special case of: x(n) = b * x(n-1) + x(n-2).)

def lucas(b)
  Enumerator.new do |yielder|
    xn2 = 1 ; yielder.yield(xn2)
    xn1 = 1 ; yielder.yield(xn1)
    loop { xn2, xn1 = xn1, b * xn1 + xn2 ; yielder.yield(xn1) }
  end
end

# Compute the Metallic Ratio to 'precision' from the Lucas Sequence for 'b'.
# (Uses the lucas(b) iterator, above.)
# The metallic ratio is approximated by x(n) / x(n-1).
# Returns a struct of the approximate metallic ratio (.ratio) and the
# number of terms required to achieve the given precision (.terms).

def metallic_ratio(b, precision)
  xn2 = xn1 = prev = this = 0
  lucas(b).each.with_index do |xn, inx|
    case inx
      when 0
        xn2 = BigDecimal(xn)
      when 1
        xn1 = BigDecimal(xn)
        prev = xn1.div(xn2, 2 * precision).round(precision)
      else
        xn2, xn1 = xn1, BigDecimal(xn)
        this = xn1.div(xn2, 2 * precision).round(precision)
        return Struct.new(:ratio, :terms).new(prev, inx - 1) if prev == this
        prev = this
    end
  end
end

NAMES = [ 'Platinum', 'Golden', 'Silver', 'Bronze', 'Copper',
          'Nickel', 'Aluminum', 'Iron', 'Tin', 'Lead' ]

puts
puts('Lucas Sequences...')
puts('%1s  %s' % ['b', 'sequence'])
(0..9).each do |b|
  puts('%1d  %s' % [b, lucas(b).first(15)])
end

puts
puts('Metallic Ratios to 32 places...')
puts('%-9s %1s %3s  %s' % ['name', 'b', 'n', 'ratio'])
(0..9).each do |b|
  rn = metallic_ratio(b, 32)
  puts('%-9s %1d %3d  %s' % [NAMES[b], b, rn.terms, rn.ratio.to_s('F')])
end

puts
puts('Golden Ratio to 256 places...')
puts('%-9s %1s %3s  %s' % ['name', 'b', 'n', 'ratio'])
gold_rn = metallic_ratio(1, 256)
puts('%-9s %1d %3d  %s' % [NAMES[1], 1, gold_rn.terms, gold_rn.ratio.to_s('F')])


Metaprogramming

{{omit from|BBC BASIC}}
Name and briefly demonstrate any support your language has for metaprogramming. Your demonstration may take the form of cross-references to other tasks on Rosetta Code. When possible, provide links to relevant documentation.

For the purposes of this task, "support for metaprogramming" means any way the user can effectively modify the language's syntax that's built into the language (like Lisp macros) or that's conventionally used with the language (like the C preprocessor). Such facilities need not be very powerful: even user-defined infix operators count. On the other hand, in general, neither operator overloading nor eval count. The task author acknowledges that what qualifies as metaprogramming is largely a judgment call.

Solution:
class IDVictim

  # Create elements of this man, woman, or child's identification.
  attr_accessor :name, :birthday, :gender, :hometown

  # Allows you to put in a space for anything which is not covered by the
  # preexisting elements.
  def self.new_element(element)
    attr_accessor element
  end

end


Metronome

The task is to implement a   metronome.

The metronome should be capable of producing high and low audio beats, accompanied by a visual beat indicator, and the beat pattern and tempo should be configurable.

For the purpose of this task, it is acceptable to play sound files for production of the beat notes, and an external player may be used.

However, the playing of the sounds should not interfere with the timing of the metronome.

The visual indicator can simply be a blinking red or green area of the screen (depending on whether a high or low beat is being produced), and the metronome can be implemented using a terminal display, or optionally, a graphical display, depending on the language capabilities.

If the language has no facility to output sound, then it is permissible for this to implemented using just the visual indicator.

Solution:
#!/usr/bin/ruby

bpm = Integer(ARGV[0]) rescue 60 # sets BPM by the first command line argument, set to 60 if none provided
msr = Integer(ARGV[1]) rescue 4 # sets number of beats in a measure by the second command line argument, set to 4 if none provided
i = 0

loop do
  (msr-1).times do
    puts "\a"
    sleep(60.0/bpm)
  end
  puts "\aAND #{i += 1}"
  sleep(60.0/bpm)
end


Mian-Chowla sequence

The Mian-Chowla sequence is an integer sequence defined recursively.

Mian-Chowla is an infinite instance of a Sidon sequence, and belongs to the class known as B2 sequences.

The sequence starts with:

::a1 = 1

then for n > 1, an is the smallest positive integer such that every pairwise sum

::ai + aj

is distinct, for all i and j less than or equal to n.

;The Task:

:* Find and display, here, on this page the first 30 terms of the Mian-Chowla sequence.
:* Find and display, here, on this page the 91st through 100th terms of the Mian-Chowla sequence.

Demonstrating working through the first few terms longhand:

::a1 = 1

::1 + 1 = 2

Speculatively try a2 = 2

::1 + 1 = 2
::1 + 2 = 3
::2 + 2 = 4

There are no repeated sums so '''2''' is the next number in the sequence.

Speculatively try a3 = 3

::1 + 1 = 2
::1 + 2 = 3
::1 + 3 = 4
::2 + 2 = 4
::2 + 3 = 5
::3 + 3 = 6

Sum of '''4''' is repeated so '''3''' is rejected.

Speculatively try a3 = 4

::1 + 1 = 2
::1 + 2 = 3
::1 + 4 = 5
::2 + 2 = 4
::2 + 4 = 6
::4 + 4 = 8

There are no repeated sums so '''4''' is the next number in the sequence.

And so on...

;See also:

:* OEIS:A005282 Mian-Chowla sequence

Solution:
require 'set'
n, ts, mc, sums = 100, [], [1], Set.new
sums << 2
st = Time.now
for i in (1 .. (n-1))
   for j in mc[i-1]+1 .. Float::INFINITY
      mc[i] = j
      for k in (0 .. i)
         if (sums.include?(sum = mc[k]+j))
            ts.clear
            break
         end
         ts << sum
      end
      if (ts.length > 0)
         sums = sums | ts
         break
      end
   end
end
et = (Time.now - st) * 1000
s = " of the Mian-Chowla sequence are:\n"
puts "The first 30 terms#{s}#{mc.slice(0..29).join(' ')}\n\n"
puts "Terms 91 to 100#{s}#{mc.slice(90..99).join(' ')}\n\n"
puts "Computation time was #{et.round(1)}ms."


Middle three digits

Write a function/procedure/subroutine that is called with an integer value and returns the middle three digits of the integer if possible or a clear indication of an error if this is not possible.

Note: The order of the middle digits should be preserved.

Your function should be tested with the following values; the first line should return valid answers, those of the second line should return clear indications of an error:

123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345
1, 2, -1, -10, 2002, -2002, 0

Show your output on this page.

Solution:
def middle_three_digits(num)
  # minus sign doesn't factor into digit count,
  # and calling #abs acts as a duck-type assertion
  num = num.abs

  # convert to string and find length
  length = (str = num.to_s).length

  # check validity
  raise ArgumentError, "Number must have at least three digits" if length < 3
  raise ArgumentError, "Number must have an odd number of digits" if length.even?

  return str[length/2 - 1, 3].to_i
end


Mind boggling card trick

Matt Parker of the "Stand Up Maths channel" has a   YouTube video   of a card trick that creates a semblance of order from chaos.

The task is to simulate the trick in a way that mimics the steps shown in the video.

; 1. Cards.
# Create a common deck of cards of 52 cards    (which are half red, half black).
# Give the pack a good shuffle.
; 2. Deal from the shuffled deck, you'll be creating three piles.
#   Assemble the cards face down.
##   Turn up the   ''top card''   and hold it in your hand.
###    if the card is         black,        then add the   ''next''   card (unseen) to the       "black"      pile.
###    If the card is     red,    then add the   ''next''   card (unseen) to the   "red"  pile.
##   Add the   ''top card''   that you're holding to the '''discard''' pile.   (You might optionally show these discarded cards to get an idea of the randomness).
# Repeat the above for the rest of the shuffled deck.
; 3. Choose a random number   (call it '''X''')   that will be used to swap cards from the "red" and "black" piles.
# Randomly choose   '''X'''   cards from the   "red"  pile (unseen), let's call this the   "red"  bunch.
# Randomly choose   '''X'''   cards from the       "black"      pile (unseen), let's call this the      "black"       bunch.
# Put the     "red"    bunch into the         "black"      pile.
# Put the        "black"        bunch into the      "red"  pile.
# (The above two steps complete the swap of   '''X'''   cards of the "red" and "black" piles.  (Without knowing what those cards are --- they could be red or black, nobody knows).
; 4. Order from randomness?
# Verify (or not) the mathematician's assertion that:
      '''The number of black cards in the "black" pile equals the number of red cards in the "red" pile.'''

(Optionally, run this simulation a number of times, gathering more evidence of the truthfulness of the assertion.)

Show output on this page.

Solution:
deck = ([:black, :red] * 26 ).shuffle
black_pile, red_pile, discard = [], [], []

until deck.empty? do
  discard << deck.pop
  discard.last == :black ? black_pile << deck.pop : red_pile << deck.pop
end

x = rand( [black_pile.size, red_pile.size].min )

red_bunch   = x.times.map{ red_pile.delete_at( rand( red_pile.size )) }
black_bunch = x.times.map{ black_pile.delete_at( rand( black_pile.size )) }

black_pile += red_bunch
red_pile   += black_bunch

puts "The magician predicts there will be #{black_pile.count( :black )} red cards in the other pile.
Drumroll...
There were #{red_pile.count( :red )}!"


Minimum multiple of m where digital sum equals m

Generate the sequence '''a(n)''' when each element is the minimum integer multiple '''m''' such that the digit sum of '''n''' times '''m''' is equal to '''n'''.

;Task

* Find the first 40 elements of the sequence.

;Stretch

* Find the next 30 elements of the sequence.

;See also

;* OEIS:A131382 - Minimal number m such that Sum_digits(n*m)=n

Solution:
a131382  = (0..).lazy.map{|n| (1..).detect{|m|(n*m).digits.sum == n} }
a131382.take(70).each_slice(10){|slice| puts "%8d"*slice.size % slice }


Minimum positive multiple in base 10 using only 0 and 1

Every positive integer has infinitely many base-10 multiples that only use the digits '''0''' and '''1'''. The goal of this task is to find and display the '''minimum''' multiple that has this property.

This is simple to do, but can be challenging to do efficiently.

To avoid repeating long, unwieldy phrases, the operation "minimum positive multiple of a positive integer n in base 10 that only uses the digits 0 and 1" will hereafter be referred to as "'''B10'''".

;Task:

Write a routine to find the B10 of a given integer.

E.G.

       '''n'''                  '''B10'''      '''n'''  x '''multiplier'''
       1                    1    ( 1  x 1         )
       2                   10    ( 2  x 5         )
       7                 1001    ( 7  x 143       )
       9            111111111    ( 9  x 12345679  )
      10                   10    ( 10 x 1         )

and so on.

Use the routine to find and display here, on this page, the '''B10''' value for:

    1 through 10, 95 through 105, 297, 576, 594, 891, 909, 999

Optionally find '''B10''' for:

    1998, 2079, 2251, 2277

Stretch goal; find '''B10''' for:

    2439, 2997, 4878

There are many opportunities for optimizations, but avoid using magic numbers as much as possible. If you ''do'' use magic numbers, explain briefly why and what they do for your implementation.

;See also:

:* OEIS:A004290 Least positive multiple of n that when written in base 10 uses only 0's and 1's.
:* How to find Minimum Positive Multiple in base 10 using only 0 and 1

Solution:
def mod(m, n)
    result = m % n
    if result < 0 then
        result = result + n
    end
    return result
end

def getA004290(n)
    if n == 1 then
        return 1
    end
    arr = Array.new(n) { Array.new(n, 0) }
    arr[0][0] = 1
    arr[0][1] = 1
    m = 0
    while true
        m = m + 1
        if arr[m - 1][mod(-10 ** m, n)] == 1 then
            break
        end
        arr[m][0] = 1
        for k in 1 .. n - 1
            arr[m][k] = [arr[m - 1][k], arr[m - 1][mod(k - 10 ** m, n)]].max
        end
    end
    r = 10 ** m
    k = mod(-r, n)
    (m - 1).downto(1) { |j|
        if arr[j - 1][k] == 0 then
            r = r + 10 ** j
            k = mod(k - 10 ** j, n)
        end
    }
    if k == 1 then
        r = r + 1
    end
    return r
end

testCases = Array(1 .. 10)
testCases.concat(Array(95 .. 105))
testCases.concat([297, 576, 594, 891, 909, 999, 1998, 2079, 2251, 2277, 2439, 2997, 4878])
for n in testCases
    result = getA004290(n)
    print "A004290(%d) = %d = %d * %d\n" % [n, result, n, result / n]
end


Modified random distribution

Given a random number generator, (rng), generating numbers in the range 0.0 .. 1.0 called rgen, for example; and a function modifier(x)
taking an number in the same range and generating the probability that the input should be generated, in the same range 0..1; then implement the following algorithm for generating random numbers to the probability given by  function modifier:
while True:
    random1 = rgen()
    random2 = rgen()
    if random2 < modifier(random1):
        answer = random1
        break
    endif
endwhile

;Task:
* Create a modifier function that generates a 'V' shaped probability of number generation using something like, for example:
                       modifier(x)  =  2*(0.5 - x)  if x < 0.5  else 2*(x - 0.5)
* Create a generator of random numbers with probabilities modified by the above function.
* Generate >= 10,000 random numbers subject to the probability modification.
* Output a textual histogram with from 11 to 21 bins showing the distribution of the random numbers generated.

Show your output here, on this page.

Solution:
def modifier(x)  =  (x - 0.5).abs * 2

def mod_rand
  loop do
    random1, random2 = rand, rand
    return random1 if random2 < modifier(random1)
  end
end

bins = 15
bin_size = 1.0/bins
h = {}
(0...bins).each{|b| h[b*bin_size] = 0}

tally = 50_000.times.map{ (mod_rand).div(bin_size) * bin_size}.tally(h)
m = tally.values.max/40
tally.each {|k,v| puts "%f...%f  %s %d" % [k, k+bin_size, "*"*(v/m) , v] }


Modular arithmetic

equivalence relation called ''congruence''.

For any positive integer p called the ''congruence modulus'',
two numbers a and b are said to be ''congruent modulo p'' whenever there exists an integer k such that:
:a = b + k\,p

The corresponding set of multiplicative inverse for this task.

Addition and multiplication on this ring have the same algebraic structure as in usual arithmetic, so that a function such as a polynomial expression could receive a ring element as argument and give a consistent result.

The purpose of this task is to show, if your programming language allows it,
how to redefine operators so that they can be used transparently on modular integers.
You can do it either by using a dedicated library, or by implementing your own class.

You will use the following function for demonstration:
:f(x) = x^{100} + x + 1
You will use 13 as the congruence modulus and you will compute f(10).

It is important that the function f is agnostic about whether or not its argument is modular; it should behave the same way with normal and modular integers.
In other words, the function is an algebraic expression that could be used with any ring, not just integers.

Solution:
# stripped version of Andrea Fazzi's submission to Ruby Quiz #179

class Modulo
  include Comparable

  def initialize(n = 0, m = 13)
    @n, @m = n % m, m
  end

  def to_i
    @n
  end

  def <=>(other_n)
    @n <=> other_n.to_i
  end

  [:+, :-, :*, :**].each do |meth|
    define_method(meth) { |other_n| Modulo.new(@n.send(meth, other_n.to_i), @m) }
  end

  def coerce(numeric)
    [numeric, @n]
  end

end

# Demo
x, y = Modulo.new(10), Modulo.new(20)

p x > y          # true
p x == y         # false
p [x,y].sort     #[#<Modulo:0x000000012ae0f8 @n=7, @m=13>, #<Modulo:0x000000012ae148 @n=10, @m=13>]
p x + y          ##<Modulo:0x0000000117e110 @n=4, @m=13>
p 2 + y          # 9
p y + 2          ##<Modulo:0x00000000ad1d30 @n=9, @m=13>

p x**100 + x +1  ##<Modulo:0x00000000ad1998 @n=1, @m=13>


Modular exponentiation

Find the last   '''40'''   decimal digits of   a^b,   where

::*   a = 2988348162058574136915891421498819466320163312926952423791023078876139
::*   b = 2351399303373464486466122544523690094744975233415544072992656881240319

A computer is too slow to find the entire value of   a^b.

Instead, the program must use a fast algorithm for modular exponentiation:   a^b \mod m.

The algorithm must work for any integers   a, b, m,     where   b \ge 0   and   m > 0.

Solution:
a = 2988348162058574136915891421498819466320163312926952423791023078876139
b = 2351399303373464486466122544523690094744975233415544072992656881240319
m = 10**40
puts a.pow(b, m)


Modular inverse

From Wikipedia:

In modulo    ''m''    is an integer    ''x''    such that

::a\,x \equiv 1 \pmod{m}.

Or in other words, such that:

::\exists k \in\Z,\qquad a\, x = 1 + k\,m

It can be shown that such an inverse exists   if and only if    ''a''    and    ''m''    are coprime,   but we will ignore this for this task.

;Task:
Either by implementing the algorithm, by using a dedicated library or by using a built-in function in
your language,   compute the modular inverse of   42 modulo 2017.

Solution:
#based on pseudo code from http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Iterative_method_2 and from translating the python implementation.
def extended_gcd(a, b)
  last_remainder, remainder = a.abs, b.abs
  x, last_x, y, last_y = 0, 1, 1, 0
  while remainder != 0
    last_remainder, (quotient, remainder) = remainder, last_remainder.divmod(remainder)
    x, last_x = last_x - quotient*x, x
    y, last_y = last_y - quotient*y, y
  end

  return last_remainder, last_x * (a < 0 ? -1 : 1)
end

def invmod(e, et)
  g, x = extended_gcd(e, et)
  if g != 1
    raise 'The maths are broken!'
  end
  x % et
end


Monads/List monad

A Monad is a combination of a data-type with two helper functions written for that type.

The data-type can be of any kind which can contain values of some other type - common examples are lists, records, sum-types, even functions or IO streams. The two special functions, mathematically known as '''eta''' and '''mu''', but usually given more expressive names like 'pure', 'return', or 'yield' and 'bind', abstract away some boilerplate needed for pipe-lining or enchaining sequences of computations on values held in the containing data-type.

The bind operator in the List monad enchains computations which return their values wrapped in lists. One application of this is the representation of indeterminacy, with returned lists representing a set of possible values. An empty list can be returned to express incomputability, or computational failure.

A sequence of two list monad computations (enchained with the use of bind) can be understood as the computation of a cartesian product.

The natural implementation of bind for the List monad is a composition of '''concat''' and '''map''', which, used with a function which returns its value as a (possibly empty) list, provides for filtering in addition to transformation or mapping.

Demonstrate in your programming language the following:

#Construct a List Monad by writing the 'bind' function and the 'pure' (sometimes known as 'return') function for that Monad (or just use what the language already has implemented)
#Make two functions, each which take a number and return a monadic number, e.g. Int -> List Int and Int -> List String
#Compose the two functions with bind

Solution:
class Array
  def bind(f)
    flat_map(&f)
  end
  def self.unit(*args)
    args
  end
  # implementing lift is optional, but is a great helper method for turning
  # ordinary funcitons into monadic versions of them.
  def self.lift(f)
    -> e { self.unit(f[e]) }
  end
end

inc = -> n { n + 1 }
str = -> n { n.to_s }
listy_inc = Array.lift(inc)
listy_str = Array.lift(str)

Array.unit(3,4,5).bind(listy_inc).bind(listy_str) #=> ["4", "5", "6"]

# Note that listy_inc and listy_str cannot be composed directly,
# as they don't have compatible type signature.
# Due to duck typing (Ruby will happily turn arrays into strings),
#   in order to show this, a new function will have to be used:

doub = -> n { 2*n }
listy_doub = Array.lift(doub)
[3,4,5].bind(listy_inc).bind(listy_doub) #=> [8, 10, 12]

# Direct composition will cause a TypeError, as Ruby cannot evaluate 2*[4, 5, 6]
# Using bind with the composition is *supposed* to fail, no matter the programming language.
comp = -> f, g {-> x {f[g[x]]}}
[3,4,5].bind(comp[listy_doub, listy_inc]) #=> TypeError: Array can't be coerced into Fixnum

# Composition needs to be defined in terms of bind
class Array
  def bind_comp(f, g)
    bind(g).bind(f)
  end
end

[3,4,5].bind_comp(listy_doub, listy_inc) #=> [8, 10, 12]