100 doors

There are 100 doors in a row that are all initially closed.

You make 100 passes by the doors.

The first time through, visit every door and  ''toggle''  the door  (if the door is closed,  open it;   if it is open,  close it).

The second time, only visit every 2nd door   (door #2, #4, #6, ...),   and toggle it.

The third time, visit every 3rd door   (door #3, #6, #9, ...), etc,   until you only visit the 100th door.

;Task:
Answer the question:   what state are the doors in after the last pass?   Which are open, which are closed?

'''Alternate:'''
As noted in this page's   discussion page,   the only doors that remain open are those whose numbers are perfect squares.

Opening only those doors is an   optimization   that may also be expressed;
however, as should be obvious, this defeats the intent of comparing implementations across programming languages.

Solution:
class Door
  attr_reader :state

  def initialize
    @state = :closed
  end

  def close
    @state = :closed
  end

  def open
    @state = :open
  end

  def closed?
    @state == :closed
  end

  def open?
    @state == :open
  end

  def toggle
    if closed? then open else close end
  end

  def to_s
    @state.to_s
  end
end

doors = Array.new(100) { Door.new }
1.upto(100) do |multiplier|
  doors.each_with_index do |door, i|
    door.toggle if (i + 1) % multiplier == 0
  end
end

doors.each_with_index { |door, i| puts "Door #{i+1} is #{door}." }


100 prisoners

The Problem:
* 100 prisoners are individually numbered 1 to 100
* A room having a cupboard of 100 opaque drawers numbered 1 to 100, that cannot be seen from outside.
* Cards numbered 1 to 100 are placed randomly, one to a drawer, and the drawers all closed; at the start.
* Prisoners start outside the room
:* They can decide some strategy before any enter the room.
:* Prisoners enter the room one by one, can open a drawer, inspect the card number in the drawer, then close the drawer.
:* A prisoner can open no more than 50 drawers.
:* A prisoner tries to find his own number.
:* A prisoner finding his own number is then held apart from the others.
* If '''all''' 100 prisoners find their own numbers then they will all be pardoned. If ''any'' don't then ''all'' sentences stand.

;The task:
# Simulate several thousand instances of the game where the prisoners randomly open drawers
# Simulate several thousand instances of the game where the prisoners use the optimal strategy mentioned in the Wikipedia article, of:
:* First opening the drawer whose outside number is his prisoner number.
:* If the card within has his number then he succeeds otherwise he opens the drawer with the same number as that of the revealed card. (until he opens his maximum).

Show and compare the computed probabilities of success for the two strategies, here, on this page.

;References:
# The unbelievable solution to the 100 prisoner puzzle standupmaths (Video).
# [[wp:100 prisoners problem]]
# 100 Prisoners Escape Puzzle DataGenetics.
# Random permutation statistics#One hundred prisoners on Wikipedia.

Solution:
prisoners = [*1..100]
N = 10_000
generate_rooms = ->{ [nil]+[*1..100].shuffle }

res = N.times.count do
  rooms = generate_rooms[]
  prisoners.all? {|pr| rooms[1,100].sample(50).include?(pr)}
end
puts "Random strategy : %11.4f %%" % (res.fdiv(N) * 100)

res = N.times.count do
  rooms = generate_rooms[]
  prisoners.all? do |pr|
    cur_room = pr
    50.times.any? do
      found = (rooms[cur_room] == pr)
      cur_room = rooms[cur_room]
      found
    end
  end
end
puts "Optimal strategy: %11.4f %%" % (res.fdiv(N) * 100)


15 puzzle game

Implement the Fifteen Puzzle Game.

The   '''15-puzzle'''   is also known as:
:::*   '''Fifteen Puzzle'''
:::*   '''Gem Puzzle'''
:::*   '''Boss Puzzle'''
:::*   '''Game of Fifteen'''
:::*   '''Mystic Square'''
:::*   '''14-15 Puzzle'''
:::*   and some others.

;Related Tasks:
:*   15 Puzzle Solver
:*   [[16 Puzzle Game]]

Solution:
require 'io/console'

class Board
  SIZE = 4
  RANGE = 0...SIZE

  def initialize
    width = (SIZE*SIZE-1).to_s.size
    @frame = ("+" + "-"*(width+2)) * SIZE + "+"
    @form = "| %#{width}d " * SIZE + "|"
    @step = 0
    @orign = [*0...SIZE*SIZE].rotate.each_slice(SIZE).to_a.freeze
    @board = @orign.map{|row | row.dup}
    randomize
    draw
    message
    play
  end

  private

  def randomize
    @board[0][0], @board[SIZE-1][SIZE-1] = 0, 1
    @board[SIZE-1][0], @board[0][SIZE-1] = @board[0][SIZE-1], @board[SIZE-1][0]
    x, y, dx, dy = 0, 0, 1, 0
    50.times do
      nx,ny = [[x+dx,y+dy], [x+dy,y-dx], [x-dy,y+dx]]
                .select{|nx,ny| RANGE.include?(nx) and RANGE.include?(ny)}
                .sample
      @board[nx][ny], @board[x][y] = 0, @board[nx][ny]
      x, y, dx, dy = nx, ny, nx-x, ny-y
    end
    @x, @y = x, y
  end

  def draw
    puts "\e[H\e[2J"
    @board.each do |row|
      puts @frame
      puts (@form % row).sub(" 0 ", "   ")
    end
    puts @frame
    puts "Step: #{@step}"
  end

  DIR = {up: [-1,0], down: [1,0], left: [0,-1], right: [0,1]}
  def move(direction)
    dx, dy = DIR[direction]
    nx, ny = @x + dx, @y + dy
    if RANGE.include?(nx) and RANGE.include?(ny)
      @board[nx][ny], @board[@x][@y] = 0, @board[nx][ny]
      @x, @y = nx, ny
      @step += 1
      draw
    end
  end

  def play
    until @board == @orign
      case  key_in
      when "\e[A", "w" then move(:up)
      when "\e[B", "s" then move(:down)
      when "\e[C", "d" then move(:right)
      when "\e[D", "a" then move(:left)

      when "q","\u0003","\u0004"  then exit
      when "h"  then message
      end
    end

    puts "Congratulations, you have won!"
  end

  def key_in
    input = STDIN.getch
    if input == "\e"
      2.times {input << STDIN.getch}
    end
    input
  end

  def message
    puts <<~EOM
      Use the arrow-keys or WASD on your keyboard to push board in the given direction.
      PRESS q TO QUIT (or Ctrl-C or Ctrl-D)
    EOM
  end
end

Board.new


21 game

'''21''' is a two player game, the game is played by choosing
a number ('''1''', '''2''', or '''3''')  to be added to the ''running total''.

The game is won by the player whose chosen number causes the ''running total''
to reach ''exactly'' '''21'''.

The ''running total'' starts at zero.
One player will be the computer.

Players alternate supplying a number to be added to the ''running total''.

;Task:
Write a computer program that will:
::* do the prompting (or provide a button menu),
::* check for errors and display appropriate error messages,
::* do the additions (add a chosen number to the ''running total''),
::* display the ''running total'',
::* provide a mechanism for the player to quit/exit/halt/stop/close the program,
::* issue a notification when there is a winner, and
::* determine who goes first (maybe a random or user choice, or can be specified when the game begins).

Solution:
# 21 Game - an example in Ruby for Rosetta Code.

GOAL = 21
MIN_MOVE = 1
MAX_MOVE = 3

DESCRIPTION = "
*** Welcome to the 21 Game! ***
21 is a two player game.
Each player chooses to add 1, 2 or 3 to a running total.
The player whose turn it is when the total reaches 21 will win the game.
The running total starts at zero.

The players start the game in turn.
Enter q to quit at any time.
"

#
# Returns the best move to play.
#
def best_move(total)
  move = rand(1..3)
  MIN_MOVE.upto(MAX_MOVE) do |i|
    move = i if (total + i - 1) % (MAX_MOVE + 1) == 0
  end
  MIN_MOVE.upto(MAX_MOVE) do |i|
    move = i if total + i == GOAL
  end
  move
end

#
# Gets the move of the player.
#
def get_move
  print "Your choice between #{MIN_MOVE} and #{MAX_MOVE}: "
  answer = gets
  move = answer.to_i
  until move.between?(MIN_MOVE, MAX_MOVE)
    exit if answer.chomp == 'q'
    print 'Invalid choice. Try again: '
    answer = gets
    move = answer.to_i
  end
  move
end

#
# Asks the player to restart a game and returns the answer.
#
def restart?
  print 'Do you want to restart (y/n)? '
  restart = gets.chomp
  until ['y', 'n'].include?(restart)
    print 'Your answer is not a valid choice. Try again: '
    restart = gets.chomp
  end
  restart == 'y'
end

#
# Run a game. The +player+ argument is the player that starts:
# * 1 for human
# * 0 for computer
#
def game(player)
  total = round = 0
  while total < GOAL
    round += 1
    puts "--- ROUND #{round} ---\n\n"
    player = (player + 1) % 2
    if player == 0
      move = best_move(total)
      puts "The computer chooses #{move}."
    else
      move = get_move
    end
    total += move
    puts "Running total is now #{total}.\n\n"
  end
  if player == 0
    puts 'Sorry, the computer has won!'
    return false
  end
  puts 'Well done, you have won!'
  true
end

# MAIN
puts DESCRIPTION
run = true
computer_wins = human_wins = 0
games_counter = player = 1
while run
  puts "\n=== START GAME #{games_counter} ==="
  player = (player + 1) % 2
  if game(player)
    human_wins += 1
  else
    computer_wins += 1
  end
  puts "\nComputer wins #{computer_wins} games, you wins #{human_wins} game."
  games_counter += 1
  run = restart?
end
puts 'Good bye!'


24 game

The 24 Game tests one's mental arithmetic.

;Task
Write a program that displays four digits, each from 1 --> 9 (inclusive) with repetitions allowed.

The program should prompt for the player to enter an arithmetic expression using ''just'' those, and ''all'' of those four digits, used exactly ''once'' each. The program should ''check'' then evaluate the expression.

The goal is for the player to enter an expression that (numerically) evaluates to '''24'''.
*  Only the following operators/functions are allowed: multiplication, division, addition, subtraction
*  Division should use floating point or rational arithmetic, etc, to preserve remainders.
*  Brackets are allowed, if using an infix expression evaluator.
*  Forming multiple digit numbers from the supplied digits is ''disallowed''. (So an answer of 12+12 when given 1, 2, 2, and 1 is wrong).
*  The order of the digits when given does not have to be preserved.

;Notes
* The type of expression evaluator used is not mandated. An RPN evaluator is equally acceptable for example.
* The task is not for the program to generate the expression, or test whether an expression is even possible.

;Related tasks
* [[24 game/Solve]]

;Reference
* The 24 Game on h2g2.

Solution:
class Guess < String
  def self.play
    nums = Array.new(4){rand(1..9)}
    loop do
      result = get(nums).evaluate!
      break if result == 24.0
      puts "Try again! That gives #{result}!"
    end
    puts "You win!"
  end

  def self.get(nums)
    loop do
      print "\nEnter a guess using #{nums}: "
      input = gets.chomp
      return new(input) if validate(input, nums)
    end
  end

  def self.validate(guess, nums)
    name, error =
      {
        invalid_character:  ->(str){ !str.scan(%r{[^\d\s()+*/-]}).empty? },
        wrong_number:       ->(str){ str.scan(/\d/).map(&:to_i).sort != nums.sort },
        multi_digit_number: ->(str){ str.match(/\d\d/) }
      }
        .find {|name, validator| validator[guess] }

    error ? puts("Invalid input of a(n) #{name.to_s.tr('_',' ')}!") : true
  end

  def evaluate!
    as_rat = gsub(/(\d)/, '\1r')        # r : Rational suffix
    eval "(#{as_rat}).to_f"
  rescue SyntaxError
    "[syntax error]"
  end
end

Guess.play


24 game/Solve

Write a program that takes four digits, either from user input or by random generation, and computes arithmetic expressions following the rules of the [[24 game]].

Show examples of solutions generated by the program.

;Related task:
*   [[Arithmetic Evaluator]]

Solution:
class TwentyFourGame
  EXPRESSIONS = [
    '((%dr %s %dr) %s %dr) %s %dr',
    '(%dr %s (%dr %s %dr)) %s %dr',
    '(%dr %s %dr) %s (%dr %s %dr)',
    '%dr %s ((%dr %s %dr) %s %dr)',
    '%dr %s (%dr %s (%dr %s %dr))',
  ]

  OPERATORS = [:+, :-, :*, :/].repeated_permutation(3).to_a

  def self.solve(digits)
    solutions = []
    perms = digits.permutation.to_a.uniq
    perms.product(OPERATORS, EXPRESSIONS) do |(a,b,c,d), (op1,op2,op3), expr|
      # evaluate using rational arithmetic
      text = expr % [a, op1, b, op2, c, op3, d]
      value = eval(text)  rescue next                 # catch division by zero
      solutions << text.delete("r")  if value == 24
    end
    solutions
  end
end

# validate user input
digits = ARGV.map do |arg|
  begin
    Integer(arg)
  rescue ArgumentError
    raise "error: not an integer: '#{arg}'"
  end
end
digits.size == 4 or raise "error: need 4 digits, only have #{digits.size}"

solutions = TwentyFourGame.solve(digits)
if solutions.empty?
  puts "no solutions"
else
  puts "found #{solutions.size} solutions, including #{solutions.first}"
  puts solutions.sort
end


4-rings or 4-squares puzzle

Replace       '''a, b, c, d, e, f,'''   and
  '''g '''       with the decimal
digits   LOW   --->   HIGH
such that the sum of the letters inside of each of the four large squares add up to
the same sum.

            +--------------+      +--------------+
            |              |      |              |
            |      a       |      |      e       |
            |              |      |              |
            |          +---+------+---+      +---+---------+
            |          |   |      |   |      |   |         |
            |          | b |      | d |      | f |         |
            |          |   |      |   |      |   |         |
            |          |   |      |   |      |   |         |
            +----------+---+      +---+------+---+         |
                       |       c      |      |      g      |
                       |              |      |             |
                       |              |      |             |
                       +--------------+      +-------------+

Show all output here.

:*   Show all solutions for each letter being unique with
         LOW=1     HIGH=7
:*   Show all solutions for each letter being unique with
         LOW=3     HIGH=9
:*   Show only the   ''number''   of solutions when each letter can be non-unique
         LOW=0     HIGH=9

;Related task:
* [[Solve the no connection puzzle]]

Solution:
def four_squares(low, high, unique=true, show=unique)
  f = -> (a,b,c,d,e,f,g) {[a+b, b+c+d, d+e+f, f+g].uniq.size == 1}
  if unique
    uniq = "unique"
    solutions = [*low..high].permutation(7).select{|ary| f.call(*ary)}
  else
    uniq = "non-unique"
    solutions = [*low..high].repeated_permutation(7).select{|ary| f.call(*ary)}
  end
  if show
    puts " " + [*"a".."g"].join("  ")
    solutions.each{|ary| p ary}
  end
  puts "#{solutions.size} #{uniq} solutions in #{low} to #{high}"
  puts
end

[[1,7], [3,9]].each do |low, high|
  four_squares(low, high)
end
four_squares(0, 9, false)


99 bottles of beer

Display the complete lyrics for the song:     '''99 Bottles of Beer on the Wall'''.

;The beer song:
The lyrics follow this form:

:::              99 bottles of beer on the wall
:::              99 bottles of beer
:::              Take one down, pass it around
:::              98 bottles of beer on the wall

:::              98 bottles of beer on the wall
:::              98 bottles of beer
:::              Take one down, pass it around
:::              97 bottles of beer on the wall

... and so on, until reaching   '''0'''     (zero).

Grammatical support for   ''1 bottle of beer''   is optional.

As with any puzzle, try to do it in as creative/concise/comical a way
as possible (simple, obvious solutions allowed, too).

;See also:
*   http://99-bottles-of-beer.net/
*   [[:Category:99_Bottles_of_Beer]]
*   [[:Category:Programming language families]]
*   Wikipedia 99 bottles of beer

Solution:
def bottles(beer, wall = false)
  "#{beer>0 ? beer : "no more"} bottle#{"s" if beer!=1} of beer#{" on the wall" if wall}"
end

99.downto(0) do |remaining|
  puts "#{bottles(remaining,true).capitalize}, #{bottles(remaining)}."
  if remaining==0
    print "Go to the store and buy some more"
    remaining=100
  else
    print "Take one down, pass it around"
  end
  puts ", #{bottles(remaining-1,true)}.\n\n"
end


9 billion names of God the integer

This task is a variation of the short story by Arthur C. Clarke.

(Solvers should be aware of the consequences of completing this task.)

In detail, to specify what is meant by a   "name":
:The integer 1 has 1 name       "1".
:The integer 2 has 2 names   "1+1",   and   "2".
:The integer 3 has 3 names   "1+1+1",   "2+1",   and   "3".
:The integer 4 has 5 names   "1+1+1+1",   "2+1+1",   "2+2",   "3+1",   "4".
:The integer 5 has 7 names   "1+1+1+1+1",   "2+1+1+1",   "2+2+1",   "3+1+1",   "3+2",   "4+1",   "5".

;Task
Display the first 25 rows of a number triangle which begins:

                                      1
                                    1   1
                                  1   1   1
                                1   2   1   1
                              1   2   2   1   1
                            1   3   3   2   1   1

Where row   n   corresponds to integer   n,   and each column   C   in row   m   from left to right corresponds to the number of names beginning with   C.

A function   G(n)   should return the sum of the   n-th   row.

Demonstrate this function by displaying:   G(23),   G(123),   G(1234),   and   G(12345).

Optionally note that the sum of the   n-th   row   P(n)   is the      integer partition function.

Demonstrate this is equivalent to   G(n)   by displaying:   P(23),   P(123),   P(1234),   and   P(12345).

;Extra credit

If your environment is able, plot   P(n)   against   n   for   n=1\ldots 999.

;Related tasks
* [[Partition function P]]

Solution:
# Generate IPF triangle
# Nigel_Galloway: May 1st., 2013.
def g(n,g)
  return 1 unless 1 < g and g < n-1
  (2..g).inject(1){|res,q| res + (q > n-g ? 0 : g(n-g,q))}
end

(1..25).each {|n|
  puts (1..n).map {|g| "%4s" % g(n,g)}.join
}


ABC problem

You are given a collection of ABC blocks   (maybe like the ones you had when you were a kid).

There are twenty blocks with two letters on each block.

A complete alphabet is guaranteed amongst all sides of the blocks.

The sample collection of blocks:
  (B O)
  (X K)
  (D Q)
  (C P)
  (N A)
  (G T)
  (R E)
  (T G)
  (Q D)
  (F S)
  (J W)
  (H U)
  (V I)
  (A N)
  (O B)
  (E R)
  (F S)
  (L Y)
  (P C)
  (Z M)

;Task:
Write a function that takes a string (word) and determines whether the word can be spelled with the given collection of blocks.

The rules are simple:
::#   Once a letter on a block is used that block cannot be used again
::#   The function should be case-insensitive
::#   Show the output on this page for the following 7 words in the following example

;Example:
    >>> can_make_word("A")
    True
    >>> can_make_word("BARK")
    True
    >>> can_make_word("BOOK")
    False
    >>> can_make_word("TREAT")
    True
    >>> can_make_word("COMMON")
    False
    >>> can_make_word("SQUAD")
    True
    >>> can_make_word("CONFUSE")
    True

Solution:
words = %w(A BaRK BOoK tREaT COmMOn SqUAD CoNfuSE) << ""

words.each do |word|
  blocks = "BO XK DQ CP NA GT RE TG QD FS JW HU VI AN OB ER FS LY PC ZM"
  res = word.each_char.all?{|c| blocks.sub!(/\w?#{c}\w?/i, "")}  #regexps can be interpolated like strings
  puts "#{word.inspect}: #{res}"
end


ASCII art diagram converter

Given the RFC 1035 message diagram from Section 4.1.1 (Header section format) as a string:
http://www.ietf.org/rfc/rfc1035.txt

 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 |                      ID                       |
 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 |                    QDCOUNT                    |
 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 |                    ANCOUNT                    |
 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 |                    NSCOUNT                    |
 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 |                    ARCOUNT                    |
 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Where (every column of the table is 1 bit):

 ID is 16 bits
 QR = Query (0) or Response (1)
 Opcode = Four bits defining kind of query:
   0:    a standard query (QUERY)
   1:    an inverse query (IQUERY)
   2:    a server status request (STATUS)
   3-15: reserved for future use
 AA = Authoritative Answer bit
 TC = Truncation bit
 RD = Recursion Desired bit
 RA = Recursion Available bit
 Z = Reserved
 RCODE = Response code
 QC = Question Count
 ANC = Answer Count
 AUC = Authority Count
 ADC = Additional Count

Write a function, member function, class or template that accepts a similar multi-line string as input to define a data structure or something else able to decode or store a header with that specified bit structure.

If your language has macros, introspection, code generation, or powerful enough templates, then accept such string at compile-time to define the header data structure statically.

Such "Header" function or template should accept a table with 8, 16, 32 or 64 columns, and any number of rows. For simplicity the only allowed symbols to define the table are + - | (plus, minus, pipe), and whitespace. Lines of the input string composed just of whitespace should be ignored. Leading and trailing whitespace in the input string should be ignored, as well as  before and after each table row. The box for each bit of the diagram takes four chars "+--+". The code should perform a little of validation of the input string, but for brevity a full validation is not required.

Bonus: perform a thoroughly validation of the input string.

Solution:
header = <<HEADER
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
HEADER

Item = Struct.new(:name, :bits, :range)
RE = /\| *\w+ */

i = 0
table = header.scan(RE).map{|m| Item.new( m.delete("^A-Za-z"), b = m.size/3, i...(i += b)) }

teststr = "78477bbf5496e12e1bf169a4"
padding = table.sum(&:bits)
binstr  = teststr.hex.to_s(2).rjust(padding, "0")

table.each{|el| p el.values}; puts
table.each{|el| puts "%7s, %2d bits: %s" % [el.name, el.bits, binstr[el.range] ]}


Abbreviations, automatic

The use of   abbreviations    (also sometimes called synonyms, nicknames, AKAs, or aliases)    can be an
easy way to add flexibility when specifying or using commands, sub-commands, options, etc.

It would make a list of words easier to maintain   (as words are added, changed, and/or deleted)   if
the minimum abbreviation length of that list could be automatically (programmatically) determined.

For this task, use the list (below) of the days-of-the-week names that are expressed in about a hundred languages   (note that there is a blank line in the list).

Sunday Monday Tuesday Wednesday Thursday Friday Saturday
Sondag Maandag Dinsdag Woensdag Donderdag Vrydag Saterdag
E_djele E_hene E_marte E_merkure E_enjte E_premte E_shtune
Ehud Segno Maksegno Erob Hamus Arbe Kedame
Al_Ahad Al_Ithinin Al_Tholatha'a Al_Arbia'a Al_Kamis Al_Gomia'a Al_Sabit
Guiragui Yergou_shapti Yerek_shapti Tchorek_shapti Hink_shapti Ourpat Shapat
domingu llunes martes miercoles xueves vienres sabadu
Bazar_gUnU Birinci_gUn Ckinci_gUn UcUncU_gUn DOrdUncU_gUn Bes,inci_gUn Altonco_gUn
Igande Astelehen Astearte Asteazken Ostegun Ostiral Larunbat
Robi_bar Shom_bar Mongal_bar Budhh_bar BRihashpati_bar Shukro_bar Shoni_bar
Nedjelja Ponedeljak Utorak Srijeda Cxetvrtak Petak Subota
Disul Dilun Dimeurzh Dimerc'her Diriaou Digwener Disadorn
nedelia ponedelnik vtornik sriada chetvartak petak sabota
sing_kei_yaht sing_kei_yat sing_kei_yee sing_kei_saam sing_kei_sie sing_kei_ng sing_kei_luk
Diumenge Dilluns Dimarts Dimecres Dijous Divendres Dissabte
Dzeenkk-eh Dzeehn_kk-ehreh Dzeehn_kk-ehreh_nah_kay_dzeeneh Tah_neesee_dzeehn_neh Deehn_ghee_dzee-neh Tl-oowey_tts-el_dehlee Dzeentt-ahzee
dy_Sul dy_Lun dy_Meurth dy_Mergher dy_You dy_Gwener dy_Sadorn
Dimanch Lendi Madi Mekredi Jedi Vandredi Samdi
nedjelja ponedjeljak utorak srijeda cxetvrtak petak subota
nede^le ponde^li utery str^eda c^tvrtek patek sobota
Sondee Mondee Tiisiday Walansedee TOOsedee Feraadee Satadee
s0ndag mandag tirsdag onsdag torsdag fredag l0rdag
zondag maandag dinsdag woensdag donderdag vrijdag zaterdag
Diman^co Lundo Mardo Merkredo ^Jaudo Vendredo Sabato
pUhapaev esmaspaev teisipaev kolmapaev neljapaev reede laupaev

Diu_prima Diu_sequima Diu_tritima Diu_quartima Diu_quintima Diu_sextima Diu_sabbata
sunnudagur manadagur tysdaguy mikudagur hosdagur friggjadagur leygardagur
Yek_Sham'beh Do_Sham'beh Seh_Sham'beh Cha'har_Sham'beh Panj_Sham'beh Jom'eh Sham'beh
sunnuntai maanantai tiistai keskiviiko torsktai perjantai lauantai
dimanche lundi mardi mercredi jeudi vendredi samedi
Snein Moandei Tiisdei Woansdei Tonersdei Freed Sneon
Domingo Segunda_feira Martes Mercores Joves Venres Sabado
k'vira orshabati samshabati otkhshabati khutshabati p'arask'evi shabati
Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag
Kiriaki' Defte'ra Tri'ti Teta'rti Pe'mpti Paraskebi' Sa'bato
ravivaar somvaar mangalvaar budhvaar guruvaar shukravaar shanivaar
popule po`akahi po`alua po`akolu po`aha po`alima po`aono
Yom_rishon Yom_sheni Yom_shlishi Yom_revi'i Yom_chamishi Yom_shishi Shabat
ravivara somavar mangalavar budhavara brahaspativar shukravara shanivar
vasarnap hetfo kedd szerda csutortok pentek szombat
Sunnudagur Manudagur +ridjudagur Midvikudagar Fimmtudagur FOstudagur Laugardagur
sundio lundio mardio merkurdio jovdio venerdio saturdio
Minggu Senin Selasa Rabu Kamis Jumat Sabtu
Dominica Lunedi Martedi Mercuridi Jovedi Venerdi Sabbato
De_Domhnaigh De_Luain De_Mairt De_Ceadaoin De_ardaoin De_hAoine De_Sathairn
domenica lunedi martedi mercoledi giovedi venerdi sabato
Nichiyou_bi Getzuyou_bi Kayou_bi Suiyou_bi Mokuyou_bi Kin'you_bi Doyou_bi
Il-yo-il Wol-yo-il Hwa-yo-il Su-yo-il Mok-yo-il Kum-yo-il To-yo-il
Dies_Dominica Dies_Lunae Dies_Martis Dies_Mercurii Dies_Iovis Dies_Veneris Dies_Saturni
sve-tdien pirmdien otrdien tresvdien ceturtdien piektdien sestdien
Sekmadienis Pirmadienis Antradienis Trec^iadienis Ketvirtadienis Penktadienis S^es^tadienis
Wangu Kazooba Walumbe Mukasa Kiwanuka Nnagawonye Wamunyi
xing-_qi-_ri xing-_qi-_yi-. xing-_qi-_er xing-_qi-_san-. xing-_qi-_si xing-_qi-_wuv. xing-_qi-_liu
Jedoonee Jelune Jemayrt Jecrean Jardaim Jeheiney Jesam
Jabot Manre Juje Wonje Taije Balaire Jarere
geminrongo minomishi martes mierkoles misheushi bernashi mishabaro
Ahad Isnin Selasa Rabu Khamis Jumaat Sabtu
sphndag mandag tirsdag onsdag torsdag fredag lphrdag
lo_dimenge lo_diluns lo_dimarc lo_dimercres lo_dijous lo_divendres lo_dissabte
djadomingo djaluna djamars djarason djaweps djabierna djasabra
Niedziela Poniedzial/ek Wtorek S,roda Czwartek Pia,tek Sobota
Domingo segunda-feire terca-feire quarta-feire quinta-feire sexta-feira sabado
Domingo Lunes martes Miercoles Jueves Viernes Sabado
Duminica Luni Mart'i Miercuri Joi Vineri Sambata
voskresenie ponedelnik vtornik sreda chetverg pyatnitsa subbota
Sunday Di-luain Di-mairt Di-ciadain Di-ardaoin Di-haoine Di-sathurne
nedjelja ponedjeljak utorak sreda cxetvrtak petak subota
Sontaha Mmantaha Labobedi Laboraro Labone Labohlano Moqebelo
Iridha- Sandhudha- Anga.haruwa-dha- Badha-dha- Brahaspa.thindha- Sikura-dha- Sena.sura-dha-
nedel^a pondelok utorok streda s^tvrtok piatok sobota
Nedelja Ponedeljek Torek Sreda Cxetrtek Petek Sobota
domingo lunes martes miercoles jueves viernes sabado
sonde mundey tude-wroko dride-wroko fode-wroko freyda Saturday
Jumapili Jumatatu Jumanne Jumatano Alhamisi Ijumaa Jumamosi
sondag mandag tisdag onsdag torsdag fredag lordag
Linggo Lunes Martes Miyerkoles Huwebes Biyernes Sabado
Le-pai-jit Pai-it Pai-ji Pai-san Pai-si Pai-gO. Pai-lak
wan-ar-tit wan-tjan wan-ang-kaan wan-phoet wan-pha-ru-hat-sa-boh-die wan-sook wan-sao
Tshipi Mosupologo Labobedi Laboraro Labone Labotlhano Matlhatso
Pazar Pazartesi Sali Car,samba Per,sembe Cuma Cumartesi
nedilya ponedilok vivtorok sereda chetver pyatnytsya subota
Chu?_Nha.t Thu*_Hai Thu*_Ba Thu*_Tu* Thu*_Na'm Thu*_Sau Thu*_Ba?y
dydd_Sul dyds_Llun dydd_Mawrth dyds_Mercher dydd_Iau dydd_Gwener dyds_Sadwrn
Dibeer Altine Talaata Allarba Al_xebes Aljuma Gaaw
iCawa uMvulo uLwesibini uLwesithathu uLuwesine uLwesihlanu uMgqibelo
zuntik montik dinstik mitvokh donershtik fraytik shabes
iSonto uMsombuluko uLwesibili uLwesithathu uLwesine uLwesihlanu uMgqibelo
Dies_Dominica Dies_Lunae Dies_Martis Dies_Mercurii Dies_Iovis Dies_Veneris Dies_Saturni
Bazar_gUnU Bazar_aertaesi Caers,aenbae_axs,amo Caers,aenbae_gUnU CUmae_axs,amo CUmae_gUnU CUmae_Senbae
Sun Moon Mars Mercury Jove Venus Saturn
zondag maandag dinsdag woensdag donderdag vrijdag zaterdag
KoseEraa GyoOraa BenEraa Kuoraa YOwaaraa FeEraa Memenaa
Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Sonnabend
Domingo Luns Terza_feira Corta_feira Xoves Venres Sabado
Dies_Solis Dies_Lunae Dies_Martis Dies_Mercurii Dies_Iovis Dies_Veneris Dies_Sabbatum
xing-_qi-_tian xing-_qi-_yi-. xing-_qi-_er xing-_qi-_san-. xing-_qi-_si xing-_qi-_wuv. xing-_qi-_liu
djadomingu djaluna djamars djarason djaweps djabierne djasabra
Killachau Atichau Quoyllurchau Illapachau Chaskachau Kuychichau Intichau

''Caveat:   The list (above) most surely contains errors (or, at the least, differences) of what the actual (or true) names for the days-of-the-week.''

To make this Rosetta Code task page as small as possible, if processing the complete list, read the days-of-the-week from a file (that is created from the above list).

Notes concerning the above list of words
::*   each line has a list of days-of-the-week for a language, separated by at least one blank
::*   the words on each line happen to be in order, from Sunday --> Saturday
::*   most lines have words in mixed case and some have all manner of accented words and other characters
::*   some words were translated to the nearest character that was available to ''code page''   '''437'''
::*   the characters in the words are not restricted except that they may not have imbedded blanks
::*   for this example, the use of an underscore ('''_''') was used to indicate a blank in a word

;Task:
::*   The list of words   (days of the week)   needn't be verified/validated.
::*   Write a function to find the (numeric) minimum length abbreviation for each line that would make abbreviations unique.
::*   A blank line   (or a null line)   should return a null string.
::*   Process and show the output for at least the first '''five''' lines of the file.
::*   Show all output here.

Solution:
require "abbrev"

File.read("daynames.txt").each_line do |line|
  next if line.strip.empty?
  abbr = line.split.abbrev.invert
  puts "Minimum size: #{abbr.values.max_by(&:size).size}", abbr.inspect, "\n"
end


Abbreviations, easy

This task is an easier (to code) variant of the Rosetta Code task:    [[Abbreviations, simple]].

For this task, the following   ''command table''   will be used:
    Add ALTer  BAckup Bottom  CAppend Change SCHANGE  CInsert CLAst COMPress COpy
    COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find
    NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput
    Join SPlit SPLTJOIN  LOAD  Locate CLocate  LOWercase UPPercase  LPrefix MACRO
    MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD  Query  QUIT
    READ  RECover REFRESH RENum REPeat  Replace CReplace  RESet  RESTore  RGTLEFT
    RIght LEft  SAVE  SET SHift SI  SORT  SOS  STAck STATus  TOP TRAnsfer Type Up

Notes concerning the above   ''command table'':
::*   it can be thought of as one long literal string   (with blanks at end-of-lines)
::*   it may have superfluous blanks
::*   it may be in any case (lower/upper/mixed)
::*   the order of the words in the   ''command table''   must be preserved as shown
::*   the user input(s) may be in any case (upper/lower/mixed)
::*   commands will be restricted to the Latin alphabet   (A --> Z,   a --> z)
::*   A valid abbreviation is a word that has:
:::*   at least the minimum length of the number of capital letters of the word in the ''command table''
:::*   compares equal (regardless of case) to the leading characters of the word in the ''command table''
:::*   a length not longer than the word in the ''command table''
::::*   '''ALT''',   '''aLt''',   '''ALTE''',   and   '''ALTER'''   are all abbreviations of   '''ALTer'''
::::*   '''AL''',   '''ALF''',   '''ALTERS''',   '''TER''',   and   '''A'''    aren't valid abbreviations of   '''ALTer'''
::::*   The number of capital letters in   '''ALTer'''   indicates that any abbreviation for   '''ALTer'''   must be at least three letters
::::*   Any word longer than five characters can't be an abbreviation for   '''ALTer'''
::::*   '''o''',    '''ov''',    '''oVe''',    '''over''',    '''overL''',    '''overla'''   are all acceptable abbreviations for   '''Overlay'''
::*   if there isn't any lowercase letters in the word in the ''command table'',   then there isn't an abbreviation permitted

;Task:
::*   The command table needn't be verified/validated.
::*   Write a function to validate if the user "words"   (given as input)   are valid   (in the ''command table'').
::*   If the word   is   valid,   then return the full uppercase version of that "word".
::*   If the word        isn't     valid,   then return the lowercase string:    '''*error*'''        (7 characters).
::*   A blank input   (or a null input)   should return a null string.
::*   Show all output here.

;An example test case to be used for this task:
For a user string of:
  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
the computer program should return the string:
  RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Solution:
#!/usr/bin/env ruby

cmd_table = File.read(ARGV[0]).split
user_str = File.read(ARGV[1]).split

user_str.each do |abbr|
  candidate = cmd_table.find do |cmd|
    cmd.count('A-Z') <= abbr.length && abbr.casecmp(cmd[0...abbr.length]).zero?
  end

  print candidate.nil? ? '*error*' : candidate.upcase

  print ' '
end

puts


Abbreviations, simple

The use of   abbreviations    (also sometimes called synonyms, nicknames, AKAs, or aliases)    can be an
easy way to add flexibility when specifying or using commands, sub-commands, options, etc.

For this task, the following   ''command table''   will be used:
    add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
    compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
    3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
    forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
    locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
    msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
    refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
    2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1

Notes concerning the above   ''command table'':
::*   it can be thought of as one long literal string   (with blanks at end-of-lines)
::*   it may have superfluous blanks
::*   it may be in any case (lower/upper/mixed)
::*   the order of the words in the   ''command table''   must be preserved as shown
::*   the user input(s) may be in any case (upper/lower/mixed)
::*   commands will be restricted to the Latin alphabet   (A --> Z,   a --> z)
::*   a command is followed by an optional number, which indicates the minimum abbreviation
::*   A valid abbreviation is a word that has:
:::*   at least the minimum length of the word's minimum number in the ''command table''
:::*   compares equal (regardless of case) to the leading characters of the word in the ''command table''
:::*   a length not longer than the word in the ''command table''
::::*   '''ALT''',   '''aLt''',   '''ALTE''',   and   '''ALTER'''   are all abbreviations of   '''ALTER 3'''
::::*   '''AL''',   '''ALF''',   '''ALTERS''',   '''TER''',   and   '''A'''    aren't valid abbreviations of   '''ALTER 3'''
::::*   The   '''3'''   indicates that any abbreviation for   '''ALTER'''   must be at least three characters
::::*   Any word longer than five characters can't be an abbreviation for   '''ALTER'''
::::*   '''o''',    '''ov''',    '''oVe''',    '''over''',    '''overL''',    '''overla'''   are all acceptable abbreviations for   '''overlay 1'''
::*   if there isn't a number after the command,   then there isn't an abbreviation permitted

;Task:
::*   The command table needn't be verified/validated.
::*   Write a function to validate if the user "words"   (given as input)   are valid   (in the ''command table'').
::*   If the word   is   valid,   then return the full uppercase version of that "word".
::*   If the word        isn't     valid,   then return the lowercase string:    '''*error*'''        (7 characters).
::*   A blank input   (or a null input)   should return a null string.
::*   Show all output here.

;An example test case to be used for this task:
For a user string of:
  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
the computer program should return the string:
  RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Solution:
str = "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"

RE = /(?<word1>[a-zA-Z]+)\s+(?<word2>[a-zA-Z]+)/
str = str.upcase
# add missing wordsizes
2.times{ str.gsub!(RE){ [  $~[:word1], $~[:word1].size, $~[:word2] ].join(" ")} }

table = Hash[*str.split].transform_values(&:to_i)

test =  "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
ar = test.split.map do |w|
  (res = table.detect{|k,v| k.start_with?(w.upcase) && w.size >= v}) ? res[0] : "*error*"
end

puts ar.join(" ")


Abelian sandpile model/Identity

Our sandpiles are based on a 3 by 3 rectangular grid giving nine areas that
contain a number from 0 to 3 inclusive. (The numbers are said to represent
grains of sand in each area of the sandpile).

E.g. s1 =

    1 2 0
    2 1 1
    0 1 3

and s2 =

    2 1 3
    1 0 1
    0 1 0

Addition on sandpiles is done by adding numbers in corresponding grid areas,
so for the above:

              1 2 0     2 1 3     3 3 3
    s1 + s2 = 2 1 1  +  1 0 1  =  3 1 2
              0 1 3     0 1 0     0 2 3

If the addition would result in more than 3 "grains of sand" in any area then
those areas cause the whole sandpile to become "unstable" and the sandpile
areas are "toppled" in an "avalanche" until the "stable" result is obtained.

Any unstable area (with a number >= 4), is "toppled" by loosing one grain of
sand to each of its four horizontal or vertical neighbours. Grains are lost
at the edge of the grid, but otherwise increase the number in neighbouring
cells by one, whilst decreasing the count in the toppled cell by four in each
toppling.

A toppling may give an adjacent area more than four grains of sand leading to
a chain of topplings called an "avalanche".
E.g.

    4 3 3     0 4 3     1 0 4     1 1 0     2 1 0
    3 1 2 ==> 4 1 2 ==> 4 2 2 ==> 4 2 3 ==> 0 3 3
    0 2 3     0 2 3     0 2 3     0 2 3     1 2 3

The final result is the stable sandpile on the right.

'''Note:''' The order in which cells are toppled does not affect the final result.

;Task:
* Create a class or datastructure and functions to represent and operate on sandpiles.
* Confirm the result of the avalanche of topplings shown above
* Confirm that s1 + s2 == s2 + s1  # Show the stable results
* If s3 is the sandpile with number 3 in every grid area, and s3_id is the following sandpile:

    2 1 2
    1 0 1
    2 1 2

* Show that s3 + s3_id == s3
* Show that s3_id + s3_id == s3_id

Show confirming output here, with your examples.

;References:
*    https://www.youtube.com/watch?v=1MtEUErz7Gg
*    https://en.wikipedia.org/wiki/Abelian_sandpile_model

Solution:
class Sandpile

  def initialize(ar) = @grid = ar

  def to_a = @grid.dup

  def + (other)
    res = self.to_a.zip(other.to_a).map{|row1, row2| row1.zip(row2).map(&:sum) }
    Sandpile.new(res)
  end

  def stable? = @grid.flatten.none?{|v| v > 3}

  def avalanche
    topple until stable?
    self
  end

  def == (other) = self.avalanche.to_a == other.avalanche.to_a

  def topple
    a = @grid
    a.each_index do |row|
       a[row].each_index do |col|
        next if a[row][col] < 4
        a[row+1][col] += 1 unless row == a.size-1
        a[row-1][col] += 1 if row > 0
        a[row][col+1] += 1 unless col == a.size-1
        a[row][col-1] += 1 if col > 0
        a[row][col]   -= 4
      end
    end
    self
  end

  def to_s = "\n" + @grid.map {|row| row.join(" ") }.join("\n")

end

puts "Sandpile:"
puts demo = Sandpile.new( [[4,3,3], [3,1,2],[0,2,3]] )
puts "\nAfter the avalanche:"
puts demo.avalanche
puts "_" * 30,""

s1 = Sandpile.new([[1, 2, 0], [2, 1, 1], [0, 1, 3]] )
puts "s1: #{s1}"
s2 = Sandpile.new([[2, 1, 3], [1, 0, 1], [0, 1, 0]] )
puts "\ns2: #{s2}"
puts "\ns1 + s2 == s2 + s1: #{s1 + s2 == s2 + s1}"
puts "_" * 30,""

s3    = Sandpile.new([[3, 3, 3], [3, 3, 3], [3, 3, 3]] )
s3_id = Sandpile.new([[2, 1, 2], [1, 0, 1], [2, 1, 2]] )
puts "s3 + s3_id == s3: #{s3 + s3_id == s3}"
puts "s3_id + s3_id == s3_id: #{s3_id + s3_id == s3_id}"


Abundant odd numbers

An Abundant number is a number '''n''' for which the   ''sum of divisors''   '''s(n) > 2n''',
or,   equivalently,   the   ''sum of proper divisors''   (or aliquot sum)       '''s(n) > n'''.

;E.G.:
'''12'''   is abundant, it has the proper divisors     '''1,2,3,4 & 6'''     which sum to   '''16'''   ( > '''12''' or '''n''');
       or alternately,   has the sigma sum of   '''1,2,3,4,6 & 12'''   which sum to   '''28'''   ( > '''24''' or '''2n''').

Abundant numbers are common, though '''even''' abundant numbers seem to be much more common than '''odd''' abundant numbers.

To make things more interesting, this task is specifically about finding   ''odd abundant numbers''.

;Task
*Find and display here: at least the first 25 abundant odd numbers and either their proper divisor sum or sigma sum.
*Find and display here: the one thousandth abundant odd number and either its proper divisor sum or sigma sum.
*Find and display here: the first abundant odd number greater than one billion (109) and either its proper divisor sum or sigma sum.

;References:
:*   OEIS:A005231: Odd abundant numbers (odd numbers n whose sum of divisors exceeds 2n)
:*   American Journal of Mathematics, Vol. 35, No. 4 (Oct., 1913), pp. 413-422 - Finiteness of the Odd Perfect and Primitive Abundant Numbers with n Distinct Prime Factors (LE Dickson)

Solution:
require "prime"

class Integer
  def proper_divisors
    return [] if self == 1
    primes = prime_division.flat_map{|prime, freq| [prime] * freq}
    (1...primes.size).each_with_object([1]) do |n, res|
      primes.combination(n).map{|combi| res << combi.inject(:*)}
    end.flatten.uniq
  end
end

def generator_odd_abundants(from=1)
  from += 1 if from.even?
  Enumerator.new do |y|
    from.step(nil, 2) do |n|
      sum = n.proper_divisors.sum
      y << [n, sum] if sum > n
    end
  end
end

generator_odd_abundants.take(25).each{|n, sum| puts "#{n} with sum #{sum}" }
puts "\n%d with sum %#d" % generator_odd_abundants.take(1000).last
puts "\n%d with sum %#d" % generator_odd_abundants(1_000_000_000).next


Accumulator factory

{{requires|Mutable State}}

A problem posed by Paul Graham is that of creating a function that takes a single (numeric) argument and which returns another function that is an accumulator. The returned accumulator function in turn also takes a single numeric argument, and returns the sum of all the numeric values passed in so far to that accumulator (including the initial value passed when the accumulator was created).

;Rules:
The detailed rules are at http://paulgraham.com/accgensub.html and are reproduced here for simplicity (with additions in ''small italic text'').
:Before you submit an example, make sure the function

:# Takes a number n and returns a function (lets call it g), that takes a number i, and returns n incremented by the accumulation of i from every call of function g(i).Although these exact function and parameter names need not be used
:# Works for any numeric type-- i.e. can take both ints and floats and returns functions that can take both ints and floats. (It is not enough simply to convert all input to floats. An accumulator that has only seen integers must return integers.) ''(i.e., if the language doesn't allow for numeric polymorphism, you have to use overloading or something like that)''
:# Generates functions that return the sum of every number ever passed to them, not just the most recent. ''(This requires a piece of state to hold the accumulated value, which in turn means that pure functional languages can't be used for this task.)''
:# Returns a real function, meaning something that you can use wherever you could use a function you had defined in the ordinary way in the text of your program. ''(Follow your language's conventions here.)''
:# Doesn't store the accumulated value or the returned functions in a way that could cause them to be inadvertently modified by other code. ''(No global variables or other such things.)''
: E.g. if after the example, you added the following code (in a made-up language) ''where the factory function is called foo'':
:: x = foo(1);
x(5);
foo(3);
print x(2.3);
: It should print 8.3. ''(There is no need to print the form of the accumulator function returned by foo(3); it's not part of the task at all.)''

;Task:
Create a function that implements the described rules.

It need not handle any special error cases not described above. The simplest way to implement the task as described is typically to use a closure, providing the language supports them.

Where it is not possible to hold exactly to the constraints above, describe the deviations.

Solution:
require 'rational'
require 'complex'
y = accumulator(Rational(2, 3))
puts y[Rational(1, 2)]  # 7/6
puts y[4]               # 31/6
puts y[Complex(0, 1)]   # 31/6+1i

t = accumulator(Time.utc(1999, 8, 7, 6, 5))
                       # (Ruby 1.8.6)                  (Ruby 1.9.2)
puts t[4]              # Sat Aug 07 06:05:04 UTC 1999  1999-08-07 06:05:04 UTC
puts t[-12 * 60 * 60]  # Fri Aug 06 18:05:04 UTC 1999  1999-08-06 18:05:04 UTC

require 'matrix'
m = accumulator(Matrix[[1, 2], [3, 4]])
puts m[Matrix[[5, 6], [7, 8]]]  # Matrix[[6, 8], [10, 12]]


Aliquot sequence classifications

An aliquot sequence of a positive integer K is defined recursively as the first member
being K and subsequent members being the sum of the [[Proper divisors]] of the previous term.

:* If the terms eventually reach 0 then the series for K is said to '''terminate'''.

:There are several classifications for non termination:
:* If the second term is K then all future terms are also K and so the sequence repeats from the first term with period 1 and K is called '''perfect'''.
:* If the third term ''would'' be repeating K then the sequence repeats with period 2 and K is called '''amicable'''.
:* If the Nth term ''would'' be repeating K for the first time, with N > 3 then the sequence repeats with period N - 1 and K is called '''sociable'''.
:Perfect, amicable and sociable numbers eventually repeat the original number K; there are other repetitions...
:* Some K have a sequence that eventually forms a periodic repetition of period 1 but of a number other than K, for example 95 which forms the sequence 95, 25, 6, 6, 6, ... such K are called '''aspiring'''.
:* K that have a sequence that eventually forms a periodic repetition of period >= 2 but of a number other than K, for example 562 which forms the sequence 562, 284, 220, 284, 220, ... such K are called '''cyclic'''.

:And finally:
:* Some K form aliquot sequences that are not known to be either terminating or periodic; these K are to be called '''non-terminating'''. For the purposes of this task, K is to be classed as non-terminating if it has not been otherwise classed after generating '''16''' terms or if any term of the sequence is greater than 2**47 = 140,737,488,355,328.

;Task:
# Create routine(s) to generate the aliquot sequence of a positive integer enough to classify it according to the classifications given above.
# Use it to display the classification and sequences of the numbers one to ten inclusive.
# Use it to show the classification and sequences of the following integers, in order:
:: 11, 12, 28, 496, 220, 1184,  12496, 1264460, 790, 909, 562, 1064, 1488, and optionally 15355717786080.

Show all output on this page.

;Related tasks:
*   [[Abundant, deficient and perfect number classifications]]. (Classifications from only the first two members of the whole sequence).
*   [[Proper divisors]]
*   [[Amicable pairs]]

Solution:
def aliquot(n, maxlen=16, maxterm=2**47)
  return "terminating", [0] if n == 0
  s = []
  while (s << n).size <= maxlen and n < maxterm
    n = n.proper_divisors.inject(0, :+)
    if s.include?(n)
      case n
      when s[0]
        case s.size
        when 1   then   return "perfect", s
        when 2   then   return "amicable", s
        else            return "sociable of length #{s.size}", s
        end
      when s[-1] then   return "aspiring", s
      else              return "cyclic back to #{n}", s
      end
    elsif n == 0 then   return "terminating", s << 0
    end
  end
  return "non-terminating", s
end

for n in 1..10
  puts "%20s: %p" % aliquot(n)
end
puts
for n in [11, 12, 28, 496, 220, 1184,  12496, 1264460, 790, 909, 562, 1064, 1488, 15355717786080]
  puts "%20s: %p" % aliquot(n)
end


Amb

Define and give an example of the Amb operator.

The Amb operator (short for "ambiguous") expresses nondeterminism. This doesn't refer to randomness (as in "nondeterministic universe") but is closely related to the term as it is used in automata theory ("non-deterministic finite automaton").

The Amb operator takes a variable number of expressions (or values if that's simpler in the language) and yields a correct one which will satisfy a constraint in some future computation, thereby avoiding failure.

Problems whose solution the Amb operator naturally expresses can be approached with other tools, such as explicit nested iterations over data sets, or with pattern matching. By contrast, the Amb operator appears integrated into the language. Invocations of Amb are not wrapped in any visible loops or other search patterns; they appear to be independent.

Essentially Amb(x, y, z) splits the computation into three possible futures: a future in which the value x is yielded, a future in which the value y is yielded and a future in which the value z is yielded. The future which leads to a successful subsequent computation is chosen. The other "parallel universes" somehow go away.   Amb called with no arguments fails.

For simplicity, one of the domain values usable with Amb may denote failure, if that is convenient. For instance, it is convenient if a Boolean false denotes failure, so that Amb(false) fails, and thus constraints can be expressed using Boolean expressions like Amb(x * y == 8) which unless x and y add to four.

A pseudo-code program which satisfies this constraint might look like:

let x = Amb(1, 2, 3)
let y = Amb(7, 6, 4, 5)
Amb(x * y = 8)
print x, y

The output is 2 4 because Amb(1, 2, 3) correctly chooses the future in which x has value 2, Amb(7, 6, 4, 5) chooses 4 and consequently Amb(x * y = 8) produces a success.

Alternatively, failure could be represented using strictly Amb():

unless x * y = 8 do Amb()

Or else Amb could take the form of two operators or functions: one for producing values and one for enforcing constraints:

let x = Ambsel(1, 2, 3)
let y = Ambsel(4, 5, 6)
Ambassert(x * y = 8)
print x, y

where Ambassert behaves like Amb() if the Boolean expression is false, otherwise it allows the future computation to take place, without yielding any value.

The task is to somehow implement Amb, and demonstrate it with a program which chooses one word from each of the following four sets of character strings to generate a four-word sentence:

#"the" "that" "a"
#"frog" "elephant" "thing"
#"walked" "treaded" "grows"
#"slowly" "quickly"

The constraint to be satisfied is that the last character of each word (other than the last) is the same as the first character of its successor.

The only successful sentence is "that thing grows slowly"; other combinations do not satisfy the constraint and thus fail.

The goal of this task isn't to simply process the four lists of words with explicit, deterministic program flow such as nested iteration, to trivially demonstrate the correct output. The goal is to implement the Amb operator, or a facsimile thereof that is possible within the language limitations.

Solution:
require "continuation"

class Amb
  class ExhaustedError < RuntimeError; end

  def initialize
    @fail = proc { fail ExhaustedError, "amb tree exhausted" }
  end

  def choose(*choices)
    prev_fail = @fail
    callcc { |sk|
      choices.each { |choice|
	callcc { |fk|
	  @fail = proc {
	    @fail = prev_fail
	    fk.call(:fail)
	  }
	  if choice.respond_to? :call
	    sk.call(choice.call)
	  else
	    sk.call(choice)
	  end
	}
      }
      @fail.call
    }
  end

  def failure
    choose
  end

  def assert(cond)
    failure unless cond
  end
end

A = Amb.new
w1 = A.choose("the", "that", "a")
w2 = A.choose("frog", "elephant", "thing")
w3 = A.choose("walked", "treaded", "grows")
w4 = A.choose("slowly", "quickly")

A.choose() unless w1[-1] == w2[0]
A.choose() unless w2[-1] == w3[0]
A.choose() unless w3[-1] == w4[0]

puts w1, w2, w3, w4


Anagrams/Deranged anagrams

Two or more words are said to be anagrams if they have the same characters, but in a different order.

By analogy with derangements we define a  ''deranged anagram'' as two words with the same characters, but in which the same character does ''not'' appear in the same position in both words.

;Task

Use the word list at unixdict to find and display the longest deranged anagram.

;Related
* [[Permutations/Derangements]]
* Best shuffle

{{Related tasks/Word plays}}

Solution:
def deranged?(a, b)
  a.chars.zip(b.chars).all? {|char_a, char_b| char_a != char_b}
end

def find_derangements(list)
  list.combination(2) {|a,b| return a,b  if deranged?(a,b)}
  nil
end

require 'open-uri'
anagram = open('http://www.puzzlers.org/pub/wordlists/unixdict.txt') do |f|
  f.read.split.group_by {|s| s.each_char.sort}
end

anagram = anagram.select{|k,list| list.size>1}.sort_by{|k,list| -k.size}

anagram.each do |k,list|
  if derangements = find_derangements(list)
    puts "Longest derangement anagram: #{derangements}"
    break
  end
end


Angle difference between two bearings

Finding the angle between two bearings is often confusing.[https://stackoverflow.com/questions/16180595/find-the-angle-between-two-bearings]

;Task:
Find the angle which is the result of the subtraction '''b2 - b1''', where '''b1''' and '''b2''' are the bearings.

Input bearings are expressed in the range   '''-180'''   to   '''+180'''   degrees.
The  result  is also expressed in the range   '''-180'''   to   '''+180'''   degrees.

Compute the angle for the following pairs:
*  20 degrees ('''b1''') and 45 degrees ('''b2''')
* -45 and  45
* -85 and  90
* -95 and  90
* -45 and 125
* -45 and 145
*  29.4803 and  -88.6381
* -78.3251 and -159.036

;Optional extra:
Allow the input bearings to be any (finite) value.

;Test cases:
*  -70099.74233810938   and   29840.67437876723
* -165313.6666297357    and   33693.9894517456
*    1174.8380510598456 and -154146.66490124757
*   60175.77306795546   and   42213.07192354373

Solution:
def getDifference(b1, b2)
	r = (b2 - b1) % 360.0
	# Ruby modulus has same sign as divisor, which is positive here,
	# so no need to consider negative case
	if r >= 180.0
		r -= 360.0
	end
	return r
end

if __FILE__ == $PROGRAM_NAME
	puts "Input in -180 to +180 range"
	puts getDifference(20.0, 45.0)
	puts getDifference(-45.0, 45.0)
	puts getDifference(-85.0, 90.0)
	puts getDifference(-95.0, 90.0)
	puts getDifference(-45.0, 125.0)
	puts getDifference(-45.0, 145.0)
	puts getDifference(-45.0, 125.0)
	puts getDifference(-45.0, 145.0)
	puts getDifference(29.4803, -88.6381)
	puts getDifference(-78.3251, -159.036)

	puts "Input in wider range"
	puts getDifference(-70099.74233810938, 29840.67437876723)
	puts getDifference(-165313.6666297357, 33693.9894517456)
	puts getDifference(1174.8380510598456, -154146.66490124757)
	puts getDifference(60175.77306795546, 42213.07192354373)
end


Anti-primes

The anti-primes
(or highly composite numbers, sequence A002182 in the OEIS)
are the natural numbers with more factors than any smaller than itself.

;Task:
Generate and show here, the first twenty anti-primes.

;Related tasks:
:*   [[Factors of an integer]]
:*   [[Sieve of Eratosthenes]]

Solution:
require 'prime'
def num_divisors(n)
  n.prime_division.inject(1){|prod, (_p,n)| prod *= (n + 1) }
end

anti_primes = Enumerator.new do |y| # y is the yielder
  max = 0
  y << 1                            # yield 1
  2.step(nil,2) do |candidate|      # nil is taken as Infinity
     num = num_divisors(candidate)
     if  num > max
       y << candidate               # yield the candidate
       max = num
     end
  end
end

puts anti_primes.take(20).join(" ")


Apply a digital filter (direct form II transposed)

Digital filters are used to apply a mathematical operation to a sampled signal. One of the common formulations is the "direct form II transposed" which can represent both infinite impulse response (IIR) and finite impulse response (FIR) filters, as well as being more numerically stable than other forms. [https://ccrma.stanford.edu/~jos/fp/Transposed_Direct_Forms.html]

;Task:

Filter a signal using an order 3 low-pass Butterworth filter. The coefficients for the filter are a=[1.00000000, -2.77555756e-16, 3.33333333e-01, -1.85037171e-17] and b = [0.16666667, 0.5, 0.5, 0.16666667]

The signal that needs filtering is the following vector: [-0.917843918645, 0.141984778794, 1.20536903482, 0.190286794412, -0.662370894973, -1.00700480494, -0.404707073677 ,0.800482325044, 0.743500089861, 1.01090520172, 0.741527555207, 0.277841675195, 0.400833448236, -0.2085993586, -0.172842103641, -0.134316096293, 0.0259303398477, 0.490105989562, 0.549391221511, 0.9047198589]

;See also:
[Wikipedia on Butterworth filters]

Solution:
def filter(a,b,signal)
    result = Array.new(signal.length(), 0.0)
    for i in 0..signal.length()-1 do
        tmp = 0.0
        for j in 0 .. b.length()-1 do
            if i - j < 0 then next end
            tmp += b[j] * signal[i - j]
        end
        for j in 1 .. a.length()-1 do
            if i - j < 0 then next end
            tmp -= a[j] * result[i - j]
        end
        tmp /= a[0]
        result[i] = tmp
    end
    return result
end

def main
    a = [1.00000000, -2.77555756e-16, 3.33333333e-01, -1.85037171e-17]
    b = [0.16666667, 0.5, 0.5, 0.16666667]
    signal = [
        -0.917843918645,  0.141984778794, 1.20536903482,   0.190286794412,
        -0.662370894973, -1.00700480494, -0.404707073677,  0.800482325044,
         0.743500089861,  1.01090520172,  0.741527555207,  0.277841675195,
         0.400833448236, -0.2085993586,  -0.172842103641, -0.134316096293,
         0.0259303398477, 0.490105989562, 0.549391221511,  0.9047198589
    ]

    result = filter(a,b,signal)
    for i in 0 .. result.length() - 1 do
        print "%11.8f" % [result[i]]
        if (i + 1) % 5 == 0 then
            print "\n"
        else
            print ", "
        end
    end
end

main()


Approximate equality

Sometimes, when testing whether the solution to a task (for example, here on Rosetta Code) is correct, the
difference in floating point calculations between different language implementations becomes significant.

For example, a difference between '''32''' bit and '''64''' bit floating point calculations may appear by
about the 8th significant digit in base 10 arithmetic.

;Task:
Create a function which returns true if two floating point numbers are approximately equal.

The function should allow for differences in the magnitude of numbers, so that, for example,
'''100000000000000.01'''   may be approximately equal to   '''100000000000000.011''',
even though   '''100.01'''   is not approximately equal to   '''100.011'''.

If the language has such a feature in its standard library, this may be used instead of a custom function.

Show the function results with comparisons on the following pairs of values:
:#     100000000000000.01,                        100000000000000.011       (note: should return ''true'')
:#     100.01,                                    100.011                                                     (note: should return ''false'')
:#     10000000000000.001 / 10000.0,   1000000000.0000001000
:#     0.001,                                     0.0010000001
:#     0.000000000000000000000101,                0.0
:#      sqrt(2) * sqrt(2),                    2.0
:#     -sqrt(2) * sqrt(2),                        -2.0
:#     3.14159265358979323846,                    3.14159265358979324

Answers should be true for the first example and false in the second, so that just rounding the numbers to a fixed number of decimals should not be enough. Otherwise answers may vary and still be correct. See the Python code for one type of solution.

__TOC__

Solution:
require "bigdecimal"

testvalues = [[100000000000000.01,           100000000000000.011],
              [100.01,                       100.011],
              [10000000000000.001 / 10000.0, 1000000000.0000001000],
              [0.001,                        0.0010000001],
              [0.000000000000000000000101,   0.0],
              [(2**0.5) * (2**0.5),            2.0],
              [-(2**0.5) * (2**0.5),          -2.0],
              [BigDecimal("3.14159265358979323846"),       3.14159265358979324],
              [Float::NAN, Float::NAN,],
              [Float::INFINITY, Float::INFINITY],
               ]

class  Numeric
  def close_to?(num, tol = Float::EPSILON)
    return true  if self == num
    return false if (self.to_f.nan? or num.to_f.nan?)        # NaN is not even close to itself
    return false if [self, num].count( Float::INFINITY) == 1 # Infinity is only close to itself
    return false if [self, num].count(-Float::INFINITY) == 1
    (self-num).abs <= tol * ([self.abs, num.abs].max)
  end
end

testvalues.each do |a,b|
  puts "#{a} #{a.close_to?(b) ? '≈' : '≉'} #{b}"
end


Arithmetic-geometric mean

{{wikipedia|Arithmetic-geometric mean}}

;Task:
Write a function to compute the arithmetic-geometric mean of two numbers.

The arithmetic-geometric mean of two numbers can be (usefully) denoted as \mathrm{agm}(a,g), and is equal to the limit of the sequence:
: a_0 = a; \qquad g_0 = g
: a_{n+1} = \tfrac{1}{2}(a_n + g_n); \quad g_{n+1} = \sqrt{a_n g_n}.
Since the limit of a_n-g_n tends (rapidly) to zero with iterations, this is an efficient method.

Demonstrate the function by calculating:
:\mathrm{agm}(1,1/\sqrt{2})

;Also see:
*   mathworld.wolfram.com/Arithmetic-Geometric Mean

Solution:
# The flt package (http://flt.rubyforge.org/) is useful for high-precision floating-point math.
# It lets us control 'context' of numbers, individually or collectively -- including precision
# (which adjusts the context's value of epsilon accordingly).

require 'flt'
include Flt

BinNum.Context.precision = 512  # default 53 (bits)

def agm(a,g)
  new_a = BinNum a
  new_g = BinNum g
  while new_a - new_g > new_a.class.Context.epsilon do
    old_g = new_g
    new_g = (new_a * new_g).sqrt
    new_a = (old_g + new_a) * 0.5
  end
  new_g
end

puts agm(1, 1 / BinNum(2).sqrt)


Arithmetic-geometric mean/Calculate Pi

Almkvist Berndt 1988 begins with an investigation of why the agm is such an efficient algorithm, and proves that it converges quadratically. This is an efficient method to calculate \pi.

With the same notations used in [[Arithmetic-geometric mean]], we can summarize the paper by writing:

\pi =
\frac{4\; \mathrm{agm}(1, 1/\sqrt{2})^2}
{1 - \sum\limits_{n=1}^{\infty} 2^{n+1}(a_n^2-g_n^2)}

This allows you to make the approximation, for any large   '''N''':

\pi \approx
\frac{4\; a_N^2}
{1 - \sum\limits_{k=1}^N 2^{k+1}(a_k^2-g_k^2)}

The purpose of this task is to demonstrate how to use this approximation in order to compute a large number of decimals of \pi.

Solution:
# Calculate Pi using the Arithmetic Geometric Mean of 1 and 1/sqrt(2)
#
#
#  Nigel_Galloway
#  March 8th., 2012.
#
require 'flt'
Flt::BinNum.Context.precision = 8192
a = n = 1
g = 1 / Flt::BinNum(2).sqrt
z = 0.25
(0..17).each{
  x = [(a + g) * 0.5, (a * g).sqrt]
  var = x[0] - a
  z -= var * var * n
  n += n
  a = x[0]
  g = x[1]
}
puts a * a / z


Arithmetic evaluation

Create a program which parses and evaluates arithmetic expressions.
;Requirements:
* An abstract-syntax tree (AST) for the expression must be created from parsing the input.
* The AST must be used in evaluation, also, so the input may not be directly evaluated (e.g. by calling eval or a similar language feature.)
* The expression will be a string or list of symbols like "(1+3)*7".
* The four symbols + - * / must be supported as binary operators with conventional precedence rules.
* Precedence-control parentheses must also be supported.

;Note:
For those who don't remember, mathematical precedence is as follows:
* Parentheses
* Multiplication/Division (left to right)
* Addition/Subtraction (left to right)

;C.f:
* [[24 game Player]].
* [[Parsing/RPN calculator algorithm]].
* [[Parsing/RPN to infix conversion]].

Solution:
$op_priority = {"+" => 0, "-" => 0, "*" => 1, "/" => 1}

class TreeNode
  OP_FUNCTION = {
    "+" => lambda {|x, y| x + y},
    "-" => lambda {|x, y| x - y},
    "*" => lambda {|x, y| x * y},
    "/" => lambda {|x, y| x / y}}
  attr_accessor :info, :left, :right

  def initialize(info)
    @info = info
  end

  def leaf?
    @left.nil? and @right.nil?
  end

  def to_s(order)
    if leaf?
      @info
    else
      left_s, right_s = @left.to_s(order), @right.to_s(order)

      strs = case order
             when :prefix  then [@info, left_s, right_s]
             when :infix   then [left_s, @info, right_s]
             when :postfix then [left_s, right_s, @info]
             else               []
             end

      "(" + strs.join(" ") + ")"
    end
  end

  def eval
    if !leaf? and operator?(@info)
      OP_FUNCTION[@info].call(@left.eval, @right.eval)
    else
      @info.to_f
    end
  end
end

def tokenize(exp)
  exp
    .gsub('(', ' ( ')
    .gsub(')', ' ) ')
    .gsub('+', ' + ')
    .gsub('-', ' - ')
    .gsub('*', ' * ')
    .gsub('/', ' / ')
    .split(' ')
end

def operator?(token)
  $op_priority.has_key?(token)
end

def pop_connect_push(op_stack, node_stack)
  temp = op_stack.pop
  temp.right = node_stack.pop
  temp.left = node_stack.pop
  node_stack.push(temp)
end

def infix_exp_to_tree(exp)
  tokens = tokenize(exp)
  op_stack, node_stack = [], []

  tokens.each do |token|
    if operator?(token)
      # clear stack of higher priority operators
      until (op_stack.empty? or
             op_stack.last.info == "(" or
             $op_priority[op_stack.last.info] < $op_priority[token])
        pop_connect_push(op_stack, node_stack)
      end

      op_stack.push(TreeNode.new(token))
    elsif token == "("
      op_stack.push(TreeNode.new(token))
    elsif token == ")"
      while op_stack.last.info != "("
        pop_connect_push(op_stack, node_stack)
      end

      # throw away the '('
      op_stack.pop
    else
      node_stack.push(TreeNode.new(token))
    end
  end

  until op_stack.empty?
    pop_connect_push(op_stack, node_stack)
  end

  node_stack.last
end


Ascending primes

Generate and show all primes with strictly ascending decimal digits.

Aside: Try solving without peeking at existing solutions. I had a weird idea for generating
a prime sieve faster, which needless to say didn't pan out. The solution may be p(r)etty trivial
but generating them quickly is at least mildly interesting.
Tip: filtering all 7,027,260 primes below 123,456,789 probably won't kill you, but there is
at least one significantly better and much faster way, needing a mere 511 odd/prime tests.

;See also
;* OEIS:A052015 - Primes with distinct digits in ascending order

;Related:
*[[Primes with digits in nondecreasing order]] (infinite series allowing duplicate digits, whereas this isn't and doesn't)
*[[Pandigital prime]] (whereas this is the smallest, with gaps in the used digits being permitted)

Solution:
require 'prime'

digits = [9,8,7,6,5,4,3,2,1]
res = 1.upto(digits.size).flat_map do |n|
   digits.combination(n).filter_map do |set|
      candidate = set.join.to_i
      candidate if candidate.prime?
   end.reverse
 end

 puts res.join(",")


Associative array/Merging

Define two associative arrays, where one represents the following "base" data:

::::: {| class="wikitable"
|+
| '''Key''' || '''Value'''
|-
| "name" || "Rocket Skates"
|-
| "price" || 12.75
|-
| "color" || "yellow"
|}

And the other represents "update" data:

::::: {| class="wikitable"
|+
| '''Key''' || '''Value'''
|-
| "price" || 15.25
|-
| "color" || "red"
|-
| "year" || 1974
|}

Merge these into a new associative array that contains every key found in either of the source ones.  Each key should map to the value in the second (update) table if that exists, or else to the value in the first (base) table.  If possible, do this in a way that does not mutate the original two associative arrays.  Obviously this should be done in a way that would work for any data, not just the specific data given here, but in this example the result should be:

::::: {| class="wikitable"
|+
| '''Key''' || '''Value'''
|-
| "name" || "Rocket Skates"
|-
| "price" || 15.25
|-
| "color" || "red"
|-
| "year" || 1974
|}

Solution:
base = {"name" => "Rocket Skates", "price" => 12.75, "color" => "yellow"}
update = {"price" => 15.25, "color" => "red", "year" => 1974}

result = base.merge(update)
p result


Attractive numbers

A number is an   ''attractive number''   if the number of its prime factors (whether distinct or not) is also prime.

;Example:
The number   '''20''',   whose prime decomposition is   '''2 x 2 x 5''',   is an   ''attractive number''   because the number of its prime factors   ('''3''')   is also prime.

;Task:
Show sequence items up to   '''120'''.

;Reference:
:*   The OEIS entry:   A063989: Numbers with a prime number of prime divisors.

Solution:
require "prime"

p (1..120).select{|n| n.prime_division.sum(&:last).prime? }


Average loop length

Let f be a uniformly-randomly chosen mapping from the numbers 1..N to the numbers 1..N (note: not necessarily a permutation of 1..N; the mapping could produce a number in more than one way or not at all). At some point, the sequence 1, f(1), f(f(1))... will contain a repetition, a number that occurring for the second time in the sequence.

;Task:
Write a program or a script that estimates, for each N, the average length until the first such repetition.

Also calculate this expected length using an analytical formula, and optionally compare the simulated result with the theoretical one.

This problem comes from the end of Donald Knuth's Christmas tree lecture 2011.

Example of expected output:

 N    average    analytical    (error)
===  =========  ============  =========
  1     1.0000        1.0000  (  0.00%)
  2     1.4992        1.5000  (  0.05%)
  3     1.8784        1.8889  (  0.56%)
  4     2.2316        2.2188  (  0.58%)
  5     2.4982        2.5104  (  0.49%)
  6     2.7897        2.7747  (  0.54%)
  7     3.0153        3.0181  (  0.09%)
  8     3.2429        3.2450  (  0.07%)
  9     3.4536        3.4583  (  0.14%)
 10     3.6649        3.6602  (  0.13%)
 11     3.8091        3.8524  (  1.12%)
 12     3.9986        4.0361  (  0.93%)
 13     4.2074        4.2123  (  0.12%)
 14     4.3711        4.3820  (  0.25%)
 15     4.5275        4.5458  (  0.40%)
 16     4.6755        4.7043  (  0.61%)
 17     4.8877        4.8579  (  0.61%)
 18     4.9951        5.0071  (  0.24%)
 19     5.1312        5.1522  (  0.41%)
 20     5.2699        5.2936  (  0.45%)

Solution:
class Integer
  def factorial
    self == 0 ? 1 : (1..self).inject(:*)
  end
end

def rand_until_rep(n)
  rands = {}
  loop do
    r = rand(1..n)
    return rands.size if rands[r]
    rands[r] = true
  end
end

runs = 1_000_000

puts " N    average    exp.        diff   ",
     "===  ========  ========  ==========="
(1..20).each do |n|
  sum_of_runs = runs.times.inject(0){|sum, _| sum += rand_until_rep(n)}
  avg = sum_of_runs / runs.to_f
  analytical = (1..n).inject(0){|sum, i| sum += (n.factorial / (n**i).to_f / (n-i).factorial)}
  puts "%3d  %8.4f  %8.4f  (%8.4f%%)" % [n, avg, analytical, (avg/analytical - 1)*100]
end


Averages/Mean angle

Solution:
require 'complex' # Superfluous in Ruby >= 2.0; complex is added to core.

def deg2rad(d)
  d * Math::PI / 180
end

def rad2deg(r)
  r * 180 / Math::PI
end

def mean_angle(deg)
  rad2deg((deg.inject(0) {|z, d| z + Complex.polar(1, deg2rad(d))} / deg.length).arg)
end

[[350, 10], [90, 180, 270, 360], [10, 20, 30]].each {|angles|
  puts "The mean angle of %p is: %f degrees" % [angles, mean_angle(angles)]
}


Averages/Pythagorean means

Solution:
class Array
  def arithmetic_mean
    inject(0.0, :+) / length
  end

  def geometric_mean
    inject(:*) ** (1.0 / length)
  end

  def harmonic_mean
    length / inject(0.0) {|s, m| s + 1.0/m}
  end
end

class Range
  def method_missing(m, *args)
    case m
    when /_mean$/ then to_a.send(m)
    else super
    end
  end
end

p a = (1..10).arithmetic_mean
p g = (1..10).geometric_mean
p h = (1..10).harmonic_mean
# is h < g < a ??
p g.between?(h, a)


Averages/Root mean square

Task

Compute the   Root mean square   of the numbers 1..10.

The   ''root mean square''   is also known by its initials RMS (or rms), and as the '''quadratic mean'''.

The RMS is calculated as the mean of the squares of the numbers, square-rooted:

::: x_{\mathrm{rms}} = \sqrt {{{x_1}^2 + {x_2}^2 + \cdots + {x_n}^2} \over n}.

;See also

{{Related tasks/Statistical measures}}

Solution:
class Array
  def quadratic_mean
    Math.sqrt( self.inject(0.0) {|s, y| s + y*y} / self.length )
  end
end

class Range
  def quadratic_mean
    self.to_a.quadratic_mean
  end
end

(1..10).quadratic_mean  # => 6.2048368229954285


Babbage problem

Charles Babbage
Charles Babbage's analytical engine.

Charles Babbage, looking ahead to the sorts of problems his Analytical Engine would be able to solve, gave this example:
{{quote
 | What is the smallest positive integer whose square ends in the digits 269,696?
 | Babbage, letter to Lord Bowden, 1837; see Hollingdale and Tootill, Electronic Computers, second edition, 1970, p. 125.
}}
He thought the answer might be 99,736, whose square is 9,947,269,696; but he couldn't be certain.

;Task

The task is to find out if Babbage had the right answer -- and to do so, as far as your language allows it, in code that Babbage himself would have been able to read and understand.
As Babbage evidently solved the task with pencil and paper, a similar efficient solution is preferred.

For these purposes, Charles Babbage may be taken to be an intelligent person, familiar with mathematics and with the idea of a computer; he has written the first drafts of simple computer programmes in tabular form. [Babbage Archive Series L].

;Motivation

The aim of the task is to write a program that is sufficiently clear and well-documented for such a person to be able to read it and be confident that it does indeed solve the specified problem.

Solution:
n = 0
n = n + 2 until (n*n).modulo(1000000) == 269696
print n


Balanced brackets

'''Task''':
* Generate a string with   '''N'''   opening brackets   '''['''   and with   '''N'''   closing brackets   ''']''',   in some arbitrary order.
* Determine whether the generated string is ''balanced''; that is, whether it consists entirely of pairs of opening/closing brackets (in that order), none of which mis-nest.

;Examples:
    (empty)      OK
    []           OK
    [][]         OK
    [[][]]       OK
    ][         NOT OK
    ][][       NOT OK
    []][[]     NOT OK

Solution:
re = /\A     # beginning of string
  (?<bb>     # begin capture group <bb>
    \[       #   literal [
    \g<bb>*  #   zero or more <bb>
    \]       #   literal ]
  )*         # end group, zero or more such groups
\z/x         # end of string

10.times do |i|
  s = (%w{[ ]} * i).shuffle.join
  puts (s =~ re ? " OK: " : "bad: ") + s
end

["[[]", "[]]", "a[ letters[-1] ].xyz[0]"].each do |s|
  t = s.gsub(/[^\[\]]/, "")
  puts (t =~ re ? " OK: " : "bad: ") + s
end


Balanced ternary

Balanced ternary is a way of representing numbers.  Unlike the prevailing binary representation, a balanced ternary integer is in base 3, and each digit can have the values 1, 0, or -1.

;Examples:
Decimal 11 = 32 + 31 - 30, thus it can be written as "++-"

Decimal  6 = 32 - 31 + 0 x 30, thus it can be written as "+-0"

;Task:
Implement balanced ternary representation of integers with the following:
# Support arbitrarily large integers, both positive and negative;
# Provide ways to convert to and from text strings, using digits '+', '-' and '0' (unless you are already using strings to represent balanced ternary; but see requirement 5).
# Provide ways to convert to and from native integer type (unless, improbably, your platform's native integer type ''is'' balanced ternary).  If your native integers can't support arbitrary length, overflows during conversion must be indicated.
# Provide ways to perform addition, negation and multiplication directly on balanced ternary integers; do ''not'' convert to native integers first.
# Make your implementation efficient, with a reasonable definition of "efficient" (and with a reasonable definition of "reasonable").

'''Test case''' With balanced ternaries ''a'' from string "+-0++0+", ''b'' from native integer -436, ''c'' "+-++-":
* write out ''a'', ''b'' and ''c'' in decimal notation;
* calculate ''a'' x (''b'' - ''c''), write out the result in both ternary and decimal notations.

'''Note:''' The pages floating point balanced ternary.

Solution:
class BalancedTernary
  include Comparable
  def initialize(str = "")
    if str =~ /[^-+0]+/
      raise ArgumentError, "invalid BalancedTernary number: #{str}"
    end
    @digits = trim0(str)
  end

  I2BT = {0 => ["0",0], 1 => ["+",0], 2 => ["-",1]}
  def self.from_int(value)
    n = value.to_i
    digits = ""
    while n != 0
      quo, rem = n.divmod(3)
      bt, carry = I2BT[rem]
      digits = bt + digits
      n = quo + carry
    end
    new(digits)
  end

  BT2I = {"-" => -1, "0" => 0, "+" => 1}
  def to_int
    @digits.chars.inject(0) do |sum, char|
      sum = 3 * sum + BT2I[char]
    end
  end
  alias :to_i :to_int

  def to_s
    @digits.dup                 # String is mutable
  end
  alias :inspect :to_s

  def <=>(other)
    to_i <=> other.to_i
  end

  ADDITION_TABLE = {
    "---" => ["-","0"], "--0" => ["-","+"], "--+" => ["0","-"],
    "-0-" => ["-","+"], "-00" => ["0","-"], "-0+" => ["0","0"],
    "-+-" => ["0","-"], "-+0" => ["0","0"], "-++" => ["0","+"],
    "0--" => ["-","+"], "0-0" => ["0","-"], "0-+" => ["0","0"],
    "00-" => ["0","-"], "000" => ["0","0"], "00+" => ["0","+"],
    "0+-" => ["0","0"], "0+0" => ["0","+"], "0++" => ["+","-"],
    "+--" => ["0","-"], "+-0" => ["0","0"], "+-+" => ["0","+"],
    "+0-" => ["0","0"], "+00" => ["0","+"], "+0+" => ["+","-"],
    "++-" => ["0","+"], "++0" => ["+","-"], "+++" => ["+","0"],
  }

  def +(other)
    maxl = [to_s.length, other.to_s.length].max
    a = pad0_reverse(to_s, maxl)
    b = pad0_reverse(other.to_s, maxl)
    carry = "0"
    sum = a.zip( b ).inject("") do |sum, (c1, c2)|
      carry, digit = ADDITION_TABLE[carry + c1 + c2]
      sum = digit + sum
    end
    self.class.new(carry + sum)
  end

  MULTIPLICATION_TABLE = {
    "-" => "+0-",
    "0" => "000",
    "+" => "-0+",
  }

  def *(other)
    product = self.class.new
    other.to_s.each_char do |bdigit|
      row = to_s.tr("-0+", MULTIPLICATION_TABLE[bdigit])
      product += self.class.new(row)
      product << 1
    end
    product >> 1
  end

  # negation
  def -@()
    self.class.new(@digits.tr('-+','+-'))
  end

  # subtraction
  def -(other)
    self + (-other)
  end

  # shift left
  def <<(count)
    @digits = trim0(@digits + "0"*count)
    self
  end

  # shift right
  def >>(count)
    @digits[-count..-1] = "" if count > 0
    @digits = trim0(@digits)
    self
  end

  private

  def trim0(str)
    str = str.sub(/^0+/, "")
    str = "0" if str.empty?
    str
  end

  def pad0_reverse(str, len)
    str.rjust(len, "0").reverse.chars
  end
end

a = BalancedTernary.new("+-0++0+")
b = BalancedTernary.from_int(-436)
c = BalancedTernary.new("+-++-")

%w[a b c a*(b-c)].each do |exp|
  val = eval(exp)
  puts "%8s :%13s,%8d" % [exp, val, val.to_i]
end


Base64 decode data

See [[Base64 encode data]].

Now write a program that takes the output of the [[Base64 encode data]] task as input and regenerate the original file.

When working on the VBA implementation I found several 'solutions' on the net, including one from the software maker himself, that showed output with incorrect padding. Obviously with incorrect padding in the output you can not decode correctly to the original file again.

Solution:
require 'base64'

raku_example ='
VG8gZXJyIGlzIGh1bWFuLCBidXQgdG8gcmVhbGx5IGZvdWwgdGhpbmdzIHVwIHlvdSBuZWVkIGEgY2
9tcHV0ZXIuCiAgICAtLSBQYXVsIFIuIEVocmxpY2g=
'
puts Base64.decode64 raku_example


Bell numbers

Bell or exponential numbers are enumerations of the number of different ways to partition a set that has exactly '''n''' elements. Each element of the sequence '''Bn''' is the number of partitions of a set of size '''n''' where order of the elements and order of the partitions are non-significant. E.G.: '''{a b}''' is the same as '''{b a}''' and '''{a} {b}''' is the same as '''{b} {a}'''.

;So:

:'''B0 = 1''' trivially. There is only one way to partition a set with zero elements. '''{ }'''

:'''B1 = 1''' There is only one way to partition a set with one element. '''{a}'''

:'''B2 = 2''' Two elements may be partitioned in two ways. '''{a} {b}, {a b}'''

:'''B3 = 5''' Three elements may be partitioned in five ways '''{a} {b} {c}, {a b} {c}, {a} {b c}, {a c} {b}, {a b c}'''

: and so on.

A simple way to find the Bell numbers is construct a '''Bell triangle''', also known as an '''Aitken's array''' or '''Peirce triangle''', and read off the numbers in the first column of each row. There are other generating algorithms though, and you are free to choose the best / most appropriate for your case.

;Task:

Write a routine (function, generator, whatever) to generate the Bell number sequence and call the routine to show here, on this page at least the '''first 15''' and (if your language supports big Integers) '''50th''' elements of the sequence.

If you ''do'' use the Bell triangle method to generate the numbers, also show the '''first ten rows''' of the Bell triangle.

;See also:

:* '''OEIS:A000110 Bell or exponential numbers'''
:* '''OEIS:A011971 Aitken's array'''

Solution:
def bellTriangle(n)
    tri = Array.new(n)
    for i in 0 .. n - 1 do
        tri[i] = Array.new(i)
        for j in 0 .. i - 1 do
            tri[i][j] = 0
        end
    end
    tri[1][0] = 1
    for i in 2 .. n - 1 do
        tri[i][0] = tri[i - 1][i - 2]
        for j in 1 .. i - 1 do
            tri[i][j] = tri[i][j - 1] + tri[i - 1][j - 1]
        end
    end
    return tri
end

def main
    bt = bellTriangle(51)
    puts "First fifteen and fiftieth Bell numbers:"
    for i in 1 .. 15 do
        puts "%2d: %d" % [i, bt[i][0]]
    end
    puts "50: %d" % [bt[50][0]]
    puts

    puts "The first ten rows of Bell's triangle:"
    for i in 1 .. 10 do
        puts bt[i].inspect
    end
end

main()


Benford's law

{{Wikipedia|Benford's_law}}

'''Benford's law''', also called the '''first-digit law''', refers to the frequency distribution of digits in many (but not all) real-life sources of data.

In this distribution, the number 1 occurs as the first digit about 30% of the time, while larger numbers occur in that position less frequently: 9 as the first digit less than 5% of the time. This distribution of first digits is the same as the widths of gridlines on a logarithmic scale.

Benford's law also concerns the expected distribution for digits beyond the first, which approach a uniform distribution.

This result has been found to apply to a wide variety of data sets, including electricity bills, street addresses, stock prices, population numbers, death rates, lengths of rivers, physical and mathematical constants, and processes described by power laws (which are very common in nature). It tends to be most accurate when values are distributed across multiple orders of magnitude.

A set of numbers is said to satisfy Benford's law if the leading digit d  (d \in \{1, \ldots, 9\}) occurs with probability

:::: P(d) = \log_{10}(d+1)-\log_{10}(d) = \log_{10}\left(1+\frac{1}{d}\right)

For this task, write (a) routine(s) to calculate the distribution of first significant (non-zero) digits in a collection of numbers, then display the actual vs. expected distribution in the way most convenient for your language (table / graph / histogram / whatever).

Use the first 1000 numbers from the Fibonacci sequence as your data set. No need to show how the Fibonacci numbers are obtained.

You can generate them or load them from a file; whichever is easiest.

Display your actual vs expected distribution.

''For extra credit:'' Show the distribution for one other set of numbers from a page on Wikipedia. State which Wikipedia page it can be obtained from and what the set enumerates. Again, no need to display the actual list of numbers or the code to load them.

;See also:
* numberphile.com.
* A starting page on Wolfram Mathworld is {{Wolfram|Benfords|Law}}.

Solution:
EXPECTED = (1..9).map{|d| Math.log10(1+1.0/d)}

def fib(n)
  a,b = 0,1
  n.times.map{ret, a, b = a, b, a+b; ret}
end

# powers of 3 as a test sequence
def power_of_threes(n)
  n.times.map{|k| 3**k}
end

def heads(s)
  s.map{|a| a.to_s[0].to_i}
end

def show_dist(title, s)
  s = heads(s)
  c = Array.new(10, 0)
  s.each{|x| c[x] += 1}
  size = s.size.to_f
  res = (1..9).map{|d| c[d]/size}
  puts "\n    %s Benfords deviation" % title
  res.zip(EXPECTED).each.with_index(1) do |(r, e), i|
    puts "%2d: %5.1f%%  %5.1f%%  %5.1f%%" % [i, r*100, e*100, (r - e).abs*100]
  end
end

def random(n)
  n.times.map{rand(1..n)}
end

show_dist("fibbed", fib(1000))
show_dist("threes", power_of_threes(1000))

# just to show that not all kind-of-random sets behave like that
show_dist("random", random(10000))


Best shuffle

Shuffle the characters of a string in such a way that as many of the character values are in a different position as possible.

A shuffle that produces a randomized result among the best choices is to be preferred. A deterministic approach that produces the same sequence every time is acceptable as an alternative.

Display the result as follows:

 original string, shuffled string, (score)

The score gives the number of positions whose character value did ''not'' change.

;Example:
 tree, eetr, (0)

;Test cases:
 abracadabra
 seesaw
 elk
 grrrrrr
 up
 a

;Related tasks
*   [[Anagrams/Deranged anagrams]]
*   [[Permutations/Derangements]]

Solution:
def best_shuffle(s)
  # Fill _pos_ with positions in the order
  # that we want to fill them.
  pos = []
  # g["a"] = [2, 4] implies that s[2] == s[4] == "a"
  g = s.length.times.group_by { |i| s[i] }

  # k sorts letters from low to high count
  k = g.sort_by { |k, v| v.length }.map { |k, v| k }

  until g.empty?
    k.each do |letter|
      g[letter] or next
      pos.push(g[letter].pop)
      g[letter].empty? and g.delete letter
    end
  end

  # Now fill in _new_ with _letters_ according to each position
  # in _pos_, but skip ahead in _letters_ if we can avoid
  # matching characters that way.
  letters = s.dup
  new = "?" * s.length
  until letters.empty?
    i, p = 0, pos.pop
    i += 1 while letters[i] == s[p] and i < (letters.length - 1)
    new[p] = letters.slice! i
  end

  score = new.chars.zip(s.chars).count { |c, d| c == d }
  [new, score]
end

%w(abracadabra seesaw elk grrrrrr up a).each do |word|
  puts "%s, %s, (%d)" % [word, *best_shuffle(word)]
end


Bin given limits

Solution:
Test = Struct.new(:limits, :data)
tests = Test.new( [23, 37, 43, 53, 67, 83],
                  [95,21,94,12,99,4,70,75,83,93,52,80,57,5,53,86,65,17,92,83,71,61,54,58,47,
                   16, 8, 9,32,84,7,87,46,19,30,37,96,6,98,40,79,97,45,64,60,29,49,36,43,55]),
        Test.new( [14, 18, 249, 312, 389, 392, 513, 591, 634, 720],
                  [445,814,519,697,700,130,255,889,481,122,932, 77,323,525,570,219,367,523,442,933,
                   416,589,930,373,202,253,775, 47,731,685,293,126,133,450,545,100,741,583,763,306,
                   655,267,248,477,549,238, 62,678, 98,534,622,907,406,714,184,391,913, 42,560,247,
                   346,860, 56,138,546, 38,985,948, 58,213,799,319,390,634,458,945,733,507,916,123,
                   345,110,720,917,313,845,426,  9,457,628,410,723,354,895,881,953,677,137,397, 97,
                   854,740, 83,216,421, 94,517,479,292,963,376,981,480, 39,257,272,157,  5,316,395,
                   787,942,456,242,759,898,576, 67,298,425,894,435,831,241,989,614,987,770,384,692,
                   698,765,331,487,251,600,879,342,982,527,736,795,585, 40, 54,901,408,359,577,237,
                   605,847,353,968,832,205,838,427,876,959,686,646,835,127,621,892,443,198,988,791,
                   466, 23,707,467, 33,670,921,180,991,396,160,436,717,918,  8,374,101,684,727,749])

def bin(limits, data)
  data.map{|d| limits.bsearch{|limit| limit > d} }.tally
end

def present_bins(limits, bins)
  ranges = ([nil]+limits+[nil]).each_cons(2).map{|low, high| Range.new(low, high, true) }
  ranges.each{|range| puts "#{range.to_s.ljust(12)} #{bins[range.end].to_i}"}
end

tests.each do |test|
  present_bins(test.limits, bin(test.limits, test.data))
  puts
end


Bioinformatics/Sequence mutation

Given a string of characters A, C, G, and T representing a DNA sequence write a routine to mutate the sequence, (string) by:
# Choosing a random base position in the sequence.
# Mutate the sequence by  doing one of either:
## '''S'''wap the base at that position by changing it to one of A, C, G, or T. (which has a chance of swapping the base for the same base)
## '''D'''elete the chosen base at the position.
## '''I'''nsert another base randomly chosen from A,C, G, or T into the sequence at that position.
# Randomly generate a test DNA sequence of at least 200 bases
# "Pretty print" the sequence and a count of its size, and the count of each base in the sequence
# Mutate the sequence ten times.
# "Pretty print" the sequence after all mutations, and a count of its size, and the count of each base in the sequence.

;Extra credit:
* Give more information on the individual mutations applied.
* Allow mutations to be weighted and/or chosen.

Solution:
class DNA_Seq
  attr_accessor :seq

  def initialize(bases: %i[A C G T] , size: 0)
    @bases = bases
    @seq   = Array.new(size){ bases.sample }
  end

  def mutate(n = 10)
    n.times{|n| method([:s, :d, :i].sample).call}
  end

  def to_s(n = 50)
    just_size = @seq.size / n
    (0...@seq.size).step(n).map{|from|  "#{from.to_s.rjust(just_size)} " + @seq[from, n].join}.join("\n") +
    "\nTotal #{seq.size}: #{@seq.tally.sort.to_h.inspect}\n\n"
  end

  def s = @seq[rand_index]= @bases.sample
  def d = @seq.delete_at(rand_index)
  def i = @seq.insert(rand_index, @bases.sample )
  alias :swap   :s
  alias :delete :d
  alias :insert :i

  private
  def rand_index = rand( @seq.size )
end

puts test = DNA_Seq.new(size: 200)
test.mutate
puts test
test.delete
puts test


Bioinformatics/base count

Given this string representing ordered DNA bases:

CGTAAAAAATTACAACGTCCTTTGGCTATCTCTTAAACTCCTGCTAAATG
CTCGTGCTTTCCAATTATGTAAGCGTTCCGAGACGGGGTGGTCGATTCTG
AGGACAAAGGTCAAGATGGAGCGCATCGAACGCAATAAGGATCATTTGAT
GGGACGTTTCGTCGACAAAGTCTTGTTTCGAGAGTAACGGCTACCGTCTT
CGATTCTGCTTATAACACTATGTTCTTATGAAATGGATGTTCTGAGTTGG
TCAGTCCCAATGTGCGGGGTTTCTTTTAGTACGTCGGGAGTGGTATTATA
TTTAATTTTTCTATATAGCGATCTGTATTTAAGCAATTCATTTAGGTTAT
CGCCGCGATGCTCGGTTCGGACCGCCAAGCATCTGGCTCCACTGCTAGTG
TCCTAAATTTGAATGGCAAACACAAATAAGATTTAGCAATTCGTGTAGAC
GACCGGGGACTTGCATGATGGGAGCAGCTTTGTTAAACTACGAACGTAAT

;Task:
:*   "Pretty print" the sequence followed by a summary of the counts of each of the bases:   ('''A''', '''C''', '''G''', and '''T''')   in the sequence
:*   print the total count of each base in the string.

Solution:
dna = <<DNA_STR
CGTAAAAAATTACAACGTCCTTTGGCTATCTCTTAAACTCCTGCTAAATG
CTCGTGCTTTCCAATTATGTAAGCGTTCCGAGACGGGGTGGTCGATTCTG
AGGACAAAGGTCAAGATGGAGCGCATCGAACGCAATAAGGATCATTTGAT
GGGACGTTTCGTCGACAAAGTCTTGTTTCGAGAGTAACGGCTACCGTCTT
CGATTCTGCTTATAACACTATGTTCTTATGAAATGGATGTTCTGAGTTGG
TCAGTCCCAATGTGCGGGGTTTCTTTTAGTACGTCGGGAGTGGTATTATA
TTTAATTTTTCTATATAGCGATCTGTATTTAAGCAATTCATTTAGGTTAT
CGCCGCGATGCTCGGTTCGGACCGCCAAGCATCTGGCTCCACTGCTAGTG
TCCTAAATTTGAATGGCAAACACAAATAAGATTTAGCAATTCGTGTAGAC
GACCGGGGACTTGCATGATGGGAGCAGCTTTGTTAAACTACGAACGTAAT
DNA_STR

chunk_size = 60
dna        = dna.delete("\n")
size       = dna.size

0.step(size, chunk_size) do |pos|
  puts "#{pos.to_s.ljust(6)} #{dna[pos, chunk_size]}"
end

puts dna.chars.tally.sort.map{|ar| ar.join(" : ") }
puts "Total : #{dna.size}"


Biorhythms

For a while in the late 70s, the pseudoscience of biorhythms was popular enough to rival astrology, with kiosks in malls that would give you your weekly printout. It was also a popular entry in "Things to Do with your Pocket Calculator" lists. You can read up on the history at Wikipedia, but the main takeaway is that unlike astrology, the math behind biorhythms is dead simple.

It's based on the number of days since your birth. The premise is that three cycles of unspecified provenance govern certain aspects of everyone's lives - specifically, how they're feeling physically, emotionally, and mentally. The best part is that not only do these cycles somehow have the same respective lengths for all humans of any age, gender, weight, genetic background, etc, but those lengths are an exact number of days. And the pattern is in each case a perfect sine curve. Absolutely miraculous!

To compute your biorhythmic profile for a given day, the first thing you need is the number of days between that day and your birth, so the answers in [[Days between dates]] are probably a good starting point. (Strictly speaking, the biorhythms start at 0 at the moment of your birth, so if you know time of day you can narrow things down further, but in general these operate at whole-day granularity.) Then take the residue of that day count modulo each of the the cycle lengths to calculate where the day falls on each of the three sinusoidal journeys.

The three cycles and their lengths are as follows:
:::{| class="wikitable"
! Cycle
! Length
|-
|Physical
| 23 days
|-
|Emotional
| 28 days
|-
|Mental
| 33 days
|}

The first half of each cycle is in "plus" territory, with a peak at the quarter-way point; the second half in "minus" territory, with a valley at the three-quarters mark. You can calculate a specific value between -1 and +1 for the ''k''th day of an ''n''-day cycle by computing '''sin( 2p''k'' / ''n'' )'''. The days where a cycle crosses the axis in either direction are called "critical" days, although with a cycle value of 0 they're also said to be the most neutral, which seems contradictory.

The task: write a subroutine, function, or program that will, given a birthdate and a target date, output the three biorhythmic values for the day. You may optionally include a text description of the position and the trend (e.g. "up and rising", "peak", "up but falling", "critical", "down and falling", "valley", "down but rising"), an indication of the date on which the next notable event (peak, valley, or crossing) falls, or even a graph of the cycles around the target date. Demonstrate the functionality for dates of your choice.

Example run of my Raku implementation:
raku br.raku 1943-03-09 1972-07-11

Solution:
require 'date'
CYCLES = {physical: 23, emotional: 28, mental: 33}

def biorhythms(date_of_birth, target_date = Date.today.to_s)
  days_alive = Date.parse(target_date) - Date.parse(date_of_birth)
  CYCLES.each do |name, num_days|
    cycle_day = days_alive % num_days
    state = case cycle_day
      when 0, num_days/2 then "neutral"
      when (1.. num_days/2) then "positive"
      when (num_days/2+1..num_days) then "negative"
    end
    puts "%-10s: cycle day %2s, %s" % [name, cycle_day.to_i, state]
  end
end

biorhythms("1943-03-09", "1972-07-11")