huginn - język programowania bez psikusów, tak prosty że każde dziecko może go opanować.

git clone https://codestation.org/repo/huginn.git
git clone https://github.com/AmokHuginnsson/huginn.git
git clone https://bitbucket.org/huginn/huginn.git
Sample of real life application of Huginn language.
Some of those samples are inspired by Rosetta Code project,
other are inspired by list of popular problems found on esolang page.
Solution for 100 doors problem.
#! /bin/sh exec huginn --no-argv -E "${0}" #! huginn import Algorithms as algo; main() { doorCount = 100; doors = [].resize( doorCount, false ); for ( pass : algo.range( doorCount ) ) { i = 0; step = pass + 1; while ( i < doorCount ) { doors[i] = ! doors[i]; i += step; } } for ( i : algo.range( doorCount ) ) { if ( doors[i] ) { print( "door {} is open\n".format( i ) ); } } return ( 0 ); }
Implementaion of a 24 game.
#! /bin/sh exec huginn --no-argv -E "${0}" #! huginn import Algorithms as algo; import Mathematics as math; import RegularExpressions as re; make_game( rndGen_ ) { board = ""; for ( i : algo.range( 4 ) ) { board += ( " " + string( character( rndGen_.next() + integer( '1' ) ) ) ); } return ( board.strip() ); } main() { rndGen = math.Randomizer( math.Randomizer.DISTRIBUTION.DISCRETE, 0, 8 ); no = 0; dd = re.compile( "\\d\\d" ); while ( true ) { no += 1; board = make_game( rndGen ); line = repl( "Your four digits: {}\nExpression {}: ".format( board, no ) ); if ( line == none ) { print( "\n" ); break; } line = line.strip(); try { if ( line == "q" ) { break; } if ( ( pos = line.find_other_than( "{}+-*/() ".format( board ) ) ) >= 0 ) { print( "Invalid input found at: {}, `{}`\n".format( pos, line ) ); continue; } if ( dd.match( line ).matched() ) { print( "Digit concatenation is forbidden.\n" ); continue; } res = real( line ); if ( res == 24.0 ) { print( "Thats right!\n" ); } else { print( "Bad answer!\n" ); } } catch ( Exception e ) { print( "Not an expression: {}\n".format( e.what() ) ); } } return ( 0 ); }
Test how your terminal handles 256 color palette.
#! /bin/sh exec huginn --no-argv -E "${0}" #! huginn /* * Based on: * Author: Todd Larason <jtl@molehill.org> * $XFree86: xc/programs/xterm/vttests/256colors2.pl,v 1.2 2002/03/26 01:46:43 dickey Exp $ * * use the resources for colors 0-15 - usually more-or-less a * reproduction of the standard ANSI colors, but possibly more * pleasing shades */ import Algorithms as algo; main() { // colors 16-231 are a 6x6x6 color cube for ( red, green, blue : algo.product( algo.range( 6 ), algo.range( 6 ), algo.range( 6 ) ) ) { print( "\x1b]4;{};rgb:{:02x}/{:02x}/{:02x}\x1b\\".format( 16 + ( red * 36 ) + ( green * 6 ) + blue, ( red > 0 ? ( red * 40 + 55) : 0 ), ( green > 0 ? ( green * 40 + 55 ) : 0 ), ( blue > 0 ? ( blue * 40 + 55 ) : 0 ) ) ); } // colors 232-255 are a grayscale ramp, intentionally leaving out // black and white for ( gray : algo.range( 24 ) ) { level = ( gray * 10 ) + 8; print( "\x1b]4;{};rgb:{:02x}/{:02x}/{:02x}\x1b\\".format( 232 + gray, level, level, level ) ); } // display the colors // first the system ones: print( "System colors:\n" ); for ( color : algo.range( 8 ) ) { print( "\x1b[48;5;{}m ".format( color ) ); } print( "\x1b[0m\n" ); for ( color : algo.range( 8, 16 ) ) { print( "\x1b[48;5;{}m ".format( color ) ); } print( "\x1b[0m\n\n" ); // now the color cube print( "Color cube, 6x6x6:\n" ); for ( green : algo.range( 6 ) ) { for ( red : algo.range( 6 ) ) { for ( blue : algo.range( 6 ) ) { color = 16 + ( red * 36 ) + ( green * 6 ) + blue; print( "\x1b[48;5;{}m ".format( color ) ); } print( "\x1b[0m " ); } print( "\n" ); } // now the grayscale ramp print( "Grayscale ramp:\n" ); for ( color : algo.range( 232, 256 ) ) { print( "\x1b[48;5;{}m ".format( color ) ); } print( "\x1b[0m\n" ); return ( 0 ); }
Print the text of the "99 bottles of beer" song.
#! /bin/sh exec huginn --no-argv -E "${0}" "${@}" #! huginn import Algorithms as algo; main() { x = "{} bottle{} of beer on the wall,\n" "{} bottle{} of beer.\n" "Take one down, pass it around,\n" "{} bottle{} of beer on the wall.\n\n"; for ( n : algo.range( 99, 0, -1 ) ) { bot = n > 0 ? n : "No"; plu = n != 1 ? "s" : ""; print( x.format( bot, plu, bot, plu, n > 1 ? n - 1 : "No", n != 2 ? "s" : "" ) ); } print( "No bottles of beer on the wall,\n" "No bottles of beer.\n" "Go to the store, buy some more,\n" "99 bottles of beer on the wall.\n" ); return ( 0 ); }
Following sample is implementation of a trie based solver for popular board game named Boggle.
#! /bin/sh exec huginn --rapid-start -E "${0}" "${@}" #! huginn /* * BENCH_INVOKE_CMD:./solve.hgn dict.txt * BENCH_VERSION_CMD:echo '(HEAD)' */ import Algorithms as algo; import Mathematics as math; import FileSystem as fs; class DictionaryNode { _finished = false; _next = lookup(); add_suffix( suffix_ ) { if ( size( suffix_ ) == 0 ) { _finished = true; } else { char = suffix_[0]; if ( char ∉ _next ) { _next[char] = DictionaryNode(); } _next[char].add_suffix( suffix_[1:] ); } } get( char_ ) { return ( _next.get( char_, none ) ); } print_all( prefix_ = "" ) { if ( _finished ) { print( prefix_ + "\n" ); } for ( char : _next ) { _next[char].print_all( prefix_ + string( char ) ); } } } class Cube { _letter = none; _visited = false; _neighbors = []; constructor( letter_ ) { _letter = letter_; } } class Board { _cubes = none; _size = 0; constructor( letters_ ) { len = integer( math.square_root( real( size( letters_ ) ) ) ); if ( len * len != size( letters_ ) ) { throw Exception( "Bad board definition!" ); } _size = len; _cubes = []; for ( l : letters_ ) { _cubes.push( Cube( l ) ); } deltas = [ ( -1, -1 ), ( -1, 0 ), ( -1, 1 ), ( 0, -1 ), ( 0, 1 ), ( 1, -1 ), ( 1, 0 ), ( 1, 1 ) ]; for ( x : algo.range( len ) ) { for ( y : algo.range( len ) ) { for ( d : deltas ) { nx = x + d[0]; ny = y + d[1]; if ( ( nx >= 0 ) && ( nx < len ) && ( ny >= 0 ) && ( ny < len ) ) { get_cube( x, y )._neighbors.push( observe( get_cube( nx, ny ) ) ); } } } } } get_cube( x_, y_ ) { return ( _cubes[y_ * _size + x_] ); } solve( dictionary_ ) { result = set(); for ( cube : _cubes ) { solve_recursive( result, "", cube, dictionary_ ); } return ( algo.sorted( result, size ) ); } solve_recursive( result, prefix_, cube_, dictNode_ ) { nextNode = dictNode_.get( cube_._letter ); if ( nextNode == none ) { return; } cube_._visited = true; newPrefix = prefix_ + string( cube_._letter ); if ( nextNode._finished && ( size( newPrefix ) >= 3 ) ) { result.insert( newPrefix ); } for ( n : cube_._neighbors ) { neighbor = use( n ); if ( ! neighbor._visited ) { solve_recursive( result, newPrefix, neighbor, nextNode ); } } cube_._visited = false; } } main( argv_ ) { dictionaryRoot = DictionaryNode(); dictFile = fs.open( argv_[1], fs.OPEN_MODE.READ ); for ( line : dictFile ) { dictionaryRoot.add_suffix( line.strip() ); } // dictionaryRoot.print_all(); print( "[ OK ] Ready\n" ); letters = ""; while ( ( line = input() ) != none ) { line = line.strip(); if ( ( size( letters ) > 0 ) && ( size( line ) == 0 ) ) { print( "[ OK ] Solving\n" ); try { board = Board( letters ); for ( word : board.solve( dictionaryRoot ) ) { print( "(" + string( size( word ) ) + ") " + word + "\n" ); } print( "[ OK ] Solved\n" ); } catch ( Exception e ) { print( e.message() + "\n" ); } letters = ""; } else { letters += line; } } return ( 0 ); } /* vim: set ft=huginn: */
Implementaion of a console Calendar.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import DateTime as dt; import Algorithms as algo; import Text as text; class Calendar { _monthNames_ = none; _dayNames_ = none; constructor() { t = dt.now(); _monthNames_ = algo.materialize( algo.map( algo.range( 1, 13 ), @[t]( m ) { dt.format( "%B", t.set_date( 1, m, 1 ) ); } ), tuple ); _dayNames_ = algo.materialize( algo.map( algo.range( 1, 8 ), @[t]( d ) { dt.format( "%a", t.set_date( 1, 1, d ) )[:2]; } ), tuple ); } print_year( year_, cols_ ) { t = dt.now(); print( "{:^66d}\n".format( year_ ) ); for ( rm : algo.range( 12 / cols_ ) ) { m = rm * cols_; print( text.repeat( "{:^22s}", cols_ ).format( _monthNames_[m:m + cols_]... ) + "\n" ); day = []; daysInMonth = []; for ( mc : algo.range( cols_ ) ) { print( " {} {} {} {} {} {} {} ".format( _dayNames_... ) ); t.set_date( year_, m + mc + 1, 1 ); day.push( - t.get_day_of_week() + 1 ); daysInMonth.push( t.get_days_in_month() ); } print( "\n" ); haveDay = true; while ( haveDay ) { haveDay = false; for ( mc : algo.range( cols_ ) ) { for ( d : algo.range( 7 ) ) { if ( ( day[mc] > 0 ) && ( day[mc] <= daysInMonth[mc] ) ) { print( " {:2d}".format( day[mc] ) ); haveDay = true; } else { print( " " ); } day[mc] += 1; } print( " " ); } print( "\n" ); } } } } main( argv_ ) { cal = Calendar(); cols = size( argv_ ) > 2 ? integer( argv_[2] ) : 3; if ( 12 % cols != 0 ) { cols = 3; } cal.print_year( size( argv_ ) > 1 ? integer( argv_[1] ) : dt.now().get_year(), cols ); } // # vim: set ft=huginn
Convert degrees to Compass points.
#! /bin/sh exec huginn --no-argv -E "${0}" "${@}" #! huginn import Algorithms as algo; import Text as text; class Compass { _majors = none; _quarter1 = none; _quarter2 = none; constructor() { _majors = algo.materialize( text.split( "north east south west", " " ), tuple ); _majors += _majors; _quarter1 = text.split( "N,N by E,N-NE,NE by N,NE,NE by E,E-NE,E by N", "," ); _quarter2 = algo.materialize( algo.map( _quarter1, @( s ){ copy( s ).replace( "NE", "EN" ); } ), list ); } degrees_to_compass_point( d ) { d = d % 360. + 360. / 64.; majorindex, minor = ( integer( d ) / 90, d % 90. ); minorindex = integer( minor * 4. ) / 45; p1, p2 = _majors[majorindex: majorindex + 2]; q = none; if ( p1 ∈ { "north", "south" } ) { q = _quarter1; } else { q = _quarter2; } return ( text.capitalize( copy( q[minorindex] ).replace( "N", p1 ).replace( "E", p2 ) ) ); } } main() { print( " # | Angle | Compass point\n" "---+---------|-------------------\n" ); c = Compass(); for ( i : algo.range( 33 ) ) { d = real( i ) * 11.25; m = i % 3; if ( m == 1 ) { d += 5.62; } else if ( m == 2 ) { d -= 5.62; } n = i % 32 + 1; print( "{:2d} | {:6.2f}° | {}\n".format( n, d, c.degrees_to_compass_point( d ) ) ); } }
Implementaion of Deadfish interpreter.
#! /bin/sh exec huginn --no-argv -E "${0}" "${@}" #! huginn main() { accumulator = 0; print( ">> " ); while ( ( line = input() ) != none ) { for ( c : line.strip() ) { if ( ( accumulator == -1 ) || ( accumulator == 256 ) ) { /* now, that's just a crazy talk */ accumulator = 0; } switch ( c ) { case ( 'i' ): { accumulator += 1; } break; case ( 'd' ): { accumulator -= 1; } break; case ( 's' ): { accumulator *= accumulator; } break; case ( 'o' ): { print( "{}\n".format( accumulator ) ); } break; default: { print( "Unrecognized command.\n" ); } } } print( ">> " ); } print( "\n" ); return ( accumulator ); }
Calculate a Digital root of a number.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn main( argv_ ) { if ( size( argv_ ) < 2 ) { throw Exception( "usage: digital-root {NUM}" ); } n = argv_[1]; if ( ( size( n ) == 0 ) || ( n.find_other_than( "0123456789" ) >= 0 ) ) { throw Exception( "{} is not a number".format( n ) ); } shift = integer( '0' ) + 1; acc = 0; for ( d : n ) { acc = 1 + ( acc + integer( d ) - shift ) % 9; } print( "{}\n".format( acc ) ); return ( 0 ); }
Showcase an implementation of Dijkstra algorithm.
#! /bin/sh exec huginn --no-argv -E "${0}" #! huginn import Algorithms as algo; import Mathematics as math; import Text as text; class Edge { _to = none; _name = none; _cost = none; constructor( to_, name_, cost_ ) { _to = to_; _name = name_; _cost = real( cost_ ); } to_string() { return ( "{}<{}>".format( _name, _cost ) ); } } class Path { _id = none; _from = none; _cost = none; _names = none; constructor( toName_, ids_, names_ ) { _id = ids_[toName_]; _names = names_; _cost = math.INFINITY; } less( other_ ) { return ( _cost < other_._cost ); } update( from_, cost_ ) { _from = from_; _cost = cost_; } to_string() { return ( "{} via {} at cost {}".format( _names[_id], _from != none ? _names[_from] : none, _cost ) ); } } class Graph { _neighbours = []; _ids = {}; _names = []; add_node( name_ ) { if ( name_ ∉ _ids ) { _ids[name_] = size( _names ); _names.push( name_ ); } } add_edge( from_, to_, cost_ ) { assert( ( from_ ∈ _ids ) && ( to_ ∈ _ids ) ); from = _ids[from_]; to = _ids[to_]; if ( from >= size( _neighbours ) ) { _neighbours.resize( from + 1, [] ); } _neighbours[from].push( Edge( to, to_, cost_ ) ); } shortest_paths( from_ ) { assert( from_ ∈ _ids ); from = _ids[from_]; paths = algo.materialize( algo.map( _names, @[_ids, _names]( name ) { Path( name, _ids, _names ); } ), list ); paths[from].update( none, 0.0 ); todo = algo.sorted( paths, @(x){-x._cost;} ); while ( size( todo ) > 0 ) { node = todo[-1]._id; todo.pop(); if ( node >= size( _neighbours ) ) { continue; } neighbours = _neighbours[node]; for ( n : neighbours ) { newCost = n._cost + paths[node]._cost; if ( newCost < paths[n._to]._cost ) { paths[n._to].update( node, newCost ); } } todo = algo.sorted( todo, @(x){-x._cost;} ); } return ( paths ); } path( paths_, to_ ) { assert( to_ ∈ _ids ); to = _ids[to_]; p = [to_]; while ( paths_[to]._from != none ) { to = paths_[to]._from; p.push( _names[to] ); } return ( algo.materialize( algo.reversed( p ), list ) ); } to_string() { s = ""; for ( i, n : algo.enumerate( _neighbours ) ) { s += "{} -> {}\n".format( _names[i], n ); } } } main() { g = Graph(); confStr = input(); if ( confStr == none ) { return ( 1 ); } conf = algo.materialize( algo.map( text.split( confStr ), integer ), tuple ); assert( size( conf ) == 2 ); for ( _ : algo.range( conf[0] ) ) { line = input(); if ( line == none ) { return ( 1 ); } g.add_node( line.strip() ); } for ( _ : algo.range( conf[1] ) ) { line = input(); if ( line == none ) { return ( 1 ); } g.add_edge( algo.materialize( text.split( line.strip() ), tuple )... ); } print( string( g ) ); paths = g.shortest_paths( "a" ); for ( p : paths ) { print( "{}\n".format( p ) ); } print( "{}\n".format( g.path( paths, "e" ) ) ); print( "{}\n".format( g.path( paths, "f" ) ) ); }
Calculate n! for an arbitrary n, or output the sequence (1!, 2!, 3!,...), where n! = 1*2*...*n.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import Algorithms as algo; main( argv_ ) { if ( size( argv_ ) < 2 ) { print( "Not enough arguments," " you have to specify a number\n" ); return ( 1 ); } n = integer( argv_[1] ); if ( n < 0 ) { print( "you must specify non-negative number\n" ); return ( 2 ); } for ( n : algo.range( 0, n + 1 ) ) { print( "{}! = {}\n".format( n, number( n )! ) ); } return ( 0 ); }
Output the Fibonacci numbers (1, 1, 2, 3, 5, 8, 13...) using either recursion or iteration.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import Algorithms as algo; import Mathematics as math; fib( n_ ) { a = number( 0 ); b = number( 1 ); for ( _ : algo.range( math.max( n_ - 1, 0 ) ) ) { a, b = ( b, a + b ); } if ( n_ == 0 ) { b = 0; } return ( b ); } main( argv_ ) { if ( size( argv_ ) < 2 ) { print( "Not enough arguments," " you have to specify a number\n" ); return ( 1 ); } n = integer( argv_[1] ); if ( n < 0 ) { print( "you must specify non-negative number\n" ); return ( 2 ); } for ( n : algo.range( 0, n + 1 ) ) { print( "fib({}) = {}\n".format( n, fib( n ) ) ); } return ( 0 ); }
Solution for Fizz Buzz problem.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import Algorithms as algo; main( argv_ ) { if ( size( argv_ ) < 2 ) { throw Exception( "usage: fizzbuzz {NUM}" ); } top = integer( argv_[1] ); for ( i : algo.range( 1, top + 1 ) ) { by3 = ( i % 3 ) == 0; by5 = ( i % 5 ) == 0; if ( by3 ) { print( "fizz" ); } if ( by5 ) { print( "buzz" ); } if ( ! ( by3 || by5 ) ) { print( i ); } print( "\n" ); } return ( 0 ); }
Print "Hello, world!".
#! /bin/sh exec huginn --no-argv -E "${0}" "${@}" #! huginn main() { print( "Hello World!\n" ); return ( 0 ); }
Print word histogram of stream read from standard input.
#! /bin/sh exec huginn -E --no-argv "${0}" "${@}" #! huginn import Algorithms as algo; import Text as text; main() { hist = {}; while ( ( line = input() ) != none ) { for ( w : text.split( line.strip().to_lower(), " " ) ) { v = hist.ensure( w, 0 ); v += 1; } } hist = algo.sorted( hist.values(), @(_){ -_[1]; } ); for ( h : hist ) { print( "{:6d} {}\n".format( h[1], h[0] ) ); } return ( 0 ); }
An implementation of a K-means++ algorithm.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import Algorithms as algo; import Mathematics as math; import OperatingSystem as os; class Color { r = 0.; g = 0.; b = 0.; } class Point { x = 0.; y = 0.; group = -1; } k_means_initial_centroids( points_, clusterCount_ ) { centroids = []; discreteRng = math.Randomizer( math.Randomizer.DISTRIBUTION.DISCRETE, 0, size( points_ ) - 1 ); uniformRng = math.Randomizer( math.Randomizer.DISTRIBUTION.UNIFORM, 0.0, 1.0 ); centroids.push( copy( points_[discreteRng.next()] ) ); for ( i : algo.range( clusterCount_ - 1 ) ) { distances = []; sum = 0.0; for ( p : points_ ) { shortestDist = math.INFINITY; for ( c : centroids ) { dx = c.x - p.x; dy = c.y - p.y; d = dx * dx + dy * dy; if ( d < shortestDist ) { shortestDist = d; } } distances.push( ( shortestDist, p ) ); sum += shortestDist; } sum *= uniformRng.next(); for ( d : distances ) { sum -= d[0]; if ( sum <= 0.0 ) { centroids.push( copy( d[1] ) ); break; } } } for ( i, c : algo.enumerate( centroids ) ) { c.group = i; } return ( centroids ); } k_means( points_, clusterCount_, maxError_ = 0.001, maxIter_ = 100 ) { centroids = k_means_initial_centroids( points_, clusterCount_ ); pointCount = real( size( points_ ) ); for ( iter : algo.range( maxIter_ ) ) { updated = 0.0; for ( p : points_ ) { shortestDist = math.INFINITY; g = 0; for ( c : centroids ) { dx = c.x - p.x; dy = c.y - p.y; dist = dx * dx + dy * dy; if ( dist < shortestDist ) { shortestDist = dist; g = c.group; } } if ( p.group != g ) { p.group = g; updated += 1.0; } } for ( c : centroids ) { n = 0; c.x = 0.; c.y = 0.; for ( p : points_ ) { if ( p.group == c.group ) { c.x += p.x; c.y += p.y; n += 1; } } if ( n > 0 ) { c.x /= real( n ); c.y /= real( n ); } } err = updated / pointCount; os.stderr().write_line( "err = {}\n".format( err ) ); if ( err < maxError_ ) { os.stderr().write_line( "done in {} iterations\n".format( iter ) ); break; } } return ( centroids ); } gen_points( numPoints_ ) { phiGen = math.Randomizer( math.Randomizer.DISTRIBUTION.UNIFORM, 0., 2. * math.pi( real ) ); rGen = math.Randomizer( math.Randomizer.DISTRIBUTION.TRIANGLE, 0., 1., 1. ); points = []; for ( i : algo.range( numPoints_ ) ) { phi = phiGen.next(); r = rGen.next(); points.push( Point( r * math.cosinus( phi ), r * math.sinus( phi ) ) ); } return ( points ); } import ProgramOptions as po; main( argv_ ) { poh = po.Handler( "k-means++", "k-means++ clustering algorithm demo" ); poh.add_option( name: "numPoints,N", requirement: po.VALUE_REQUIREMENT.REQUIRED, help: "number of points", conversion: integer, valueName: "num", defaultValue: 30000 ); poh.add_option( name: "numClusters,C", requirement: po.VALUE_REQUIREMENT.REQUIRED, help: "number of custers", conversion: integer, valueName: "num", defaultValue: 7 ); poh.add_option( name: "maxIterations,I", requirement: po.VALUE_REQUIREMENT.REQUIRED, help: "maximum number of iterations for the algorithm to run", conversion: integer, valueName: "num", defaultValue: 100 ); poh.add_option( name: "maxInvalidRatio,R", requirement: po.VALUE_REQUIREMENT.REQUIRED, help: "maximum ratio of points that are still assigned to invalid centroids", conversion: real, valueName: "num", defaultValue: 0.001 ); poh.add_option( name: "help,H", requirement: po.VALUE_REQUIREMENT.NONE, help: "show help information and stop" ); poh.add_option( name: "verbose,v", requirement: po.VALUE_REQUIREMENT.NONE, help: "show more info about program execution" ); parsed = poh.command_line( argv_ ); if ( parsed == none ) { return ( 1 ); } if ( parsed.options["help"] ) { print( poh.help_string() + "\n" ); return ( 0 ); } if ( parsed.options["verbose"] ) { os.stderr().write_line( string( parsed ) + "\n" ); } points = gen_points( parsed.options["numPoints"] ); print_eps( points, k_means( points, parsed.options["numClusters"], parsed.options["maxInvalidRatio"], parsed.options["maxIterations"] ) ); } print_eps( points, cluster_centers, W = 400, H = 400 ) { colors = []; for ( i : algo.range( size( cluster_centers ) ) ) { ii = real( i ); colors.push( Color( ( 3. * ( ii + 1. ) % 11. ) / 11.0, ( 7. * ii % 11. ) / 11.0, ( 9. * ii % 11. ) / 11.0 ) ); } max_x = max_y = - math.INFINITY; min_x = min_y = math.INFINITY; for ( p : points ) { if ( max_x < p.x ) { max_x = p.x; } if ( min_x > p.x ) { min_x = p.x; } if ( max_y < p.y ) { max_y = p.y; } if ( min_y > p.y ) { min_y = p.y; } } scale = math.min( real( W ) / ( max_x - min_x ), real( H ) / ( max_y - min_y ) ); cx = ( max_x + min_x ) / 2.; cy = ( max_y + min_y ) / 2.; print( "%!PS-Adobe-3.0\n%%BoundingBox: -5 -5 {} {}\n".format( W + 10, H + 10 ) ); print( "/l {rlineto} def /m {rmoveto} def\n" "/c { .25 sub exch .25 sub exch .5 0 360 arc fill } def\n" "/s { moveto -2 0 m 2 2 l 2 -2 l -2 -2 l closepath " " gsave 1 setgray fill grestore gsave 3 setlinewidth" " 1 setgray stroke grestore 0 setgray stroke }def\n" ); for ( i, cc : algo.enumerate( cluster_centers ) ) { print( "{} {} {} setrgbcolor\n".format( colors[i].r, colors[i].g, colors[i].b ) ); for ( p : points ) { if ( p.group != i ) { continue; } print( "{:.3f} {:.3f} c\n".format( ( p.x - cx ) * scale + real( W ) / 2., ( p.y - cy ) * scale + real( H ) / 2. ) ); } print("\n0 setgray {} {} s\n".format( ( cc.x - cx ) * scale + real( W ) / 2., ( cc.y - cy ) * scale + real( H ) / 2. ) ); } print( "\n%%%%EOF\n" ); }
Print a Mandelbrot set on the console.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import Algorithms as algo; import Mathematics as math; import Terminal as term; mandelbrot( x, y ) { c = math.Complex( x, y ); z = math.Complex( 0., 0. ); s = -1; for ( i : algo.range( 50 ) ) { z = z * z + c; if ( | z | > 2. ) { s = i; break; } } return ( s ); } main( argv_ ) { imgSize = term_size( argv_ ); yRad = 1.2; yScale = 2. * yRad / real( imgSize[0] ); xScale = 3.3 / real( imgSize[1] ); glyphTab = [ ".", ":", "-", "+", "+" ].resize( 12, "*" ).resize( 26, "%" ).resize( 50, "@" ).push( " " ); for ( y : algo.range( imgSize[0] ) ) { line = ""; for ( x : algo.range( imgSize[1] ) ) { line += glyphTab[ mandelbrot( xScale * real( x ) - 2.3, yScale * real( y ) - yRad ) ]; } print( line + "\n" ); } return ( 0 ); } term_size( argv_ ) { lines = 25; columns = 80; if ( size( argv_ ) == 3 ) { lines = integer( argv_[1] ); columns = integer( argv_[2] ); } else { lines = term.lines(); columns = term.columns(); if ( ( lines % 2 ) == 0 ) { lines -= 1; } } lines -= 1; columns -= 1; return ( ( lines, columns ) ); }
Automatically set proper -vf=....:expand with mplayer video player.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import Algorithms as algo; import Mathematics as math; import RegularExpressions as re; import Text as text; import OperatingSystem as os; import FileSystem as fs; import Shell as shell; path( item_ ) { return ( "/usr/bin/" + item_ ); } grep( stream_, pattern_ ) { pattern = re.compile( pattern_ ); stream = algo.filter( algo.map( stream_, string.strip ), @[pattern]( line ) { pattern.match( line ).matched(); } ); return ( stream ); } get_clip_info( path_ ) { mplayer = shell.spawn( path( "mplayer" ), ["-vo", "null", "-ao", "null", "-frames", "0", "-identify", path_] ); info = algo.materialize( algo.map( grep( mplayer.out(), "\\bID_VIDEO_(HEIGHT|WIDTH)|\\ID_SUBTITLE" ), @( line ) { d = text.split( line[3:].to_lower().replace( "video_", "" ), "=" ); return ( ( d[0], integer( d[1] ) ) ); } ), lookup ); mplayer.wait( 1 ); return ( info ); } get_screen_info() { xrandr = shell.spawn( "xrandr", ["--current"] ); resPattern = "\\d+x\\d+[+]\\d+[+]\\d+"; pattern = re.compile( resPattern ); screens = algo.materialize( algo.map( grep( xrandr.out(), "\\bconnected\\b(\\s+primary)?\\s+" + resPattern ), @[pattern]( line ) { algo.materialize( algo.map( text.split( pattern.groups( line )[0].replace( "x", "+" ), "+" ), integer ), tuple ); } ), list ); xrandr.wait( 1 ); for ( s : screens ) { x = s[2]; x += s[0]; } screens.sort( @( s ) { s[2]; } ); return ( screens ); } get_active_window_id() { xprop = shell.spawn( "xprop", ["-root", "_NET_ACTIVE_WINDOW"] ); id = text.split( xprop.out().read_line().strip(), " " )[-1]; xprop.wait( 1 ); return ( id ); } get_current_screen( screens_, id_ ) { xwininfo = shell.spawn( "xwininfo", ["-id", id_] ); info = algo.materialize( algo.map( grep( xwininfo.out(), "Absolute upper-left" ), @( line ) { integer( text.split( line, ":" )[-1].strip() ); } ), tuple ); xwininfo.wait( 1 ); current = none; for ( s : screens_ ) { if ( info[0] < s[2] ) { current = s[:2]; break; } } return ( current ); } calc_expand( width_, height_, xRes_, yRes_ ) { expand = 0; clipAspectRatio = real( width_ ) / real( height_ ); screenAspectRatio = real( xRes_ ) / real( yRes_ ); if ( clipAspectRatio > screenAspectRatio ) { scaledHeight = ( width_ * yRes_ ) / xRes_; expand = | height_ - scaledHeight |; } return ( expand ); } run_orig( argv_ ) { os.exec( path( "mplayer" ), algo.materialize( argv_[1:], tuple )... ); } main( argv_ ) { if ( size( argv_ ) != 2 ) { run_orig( argv_ ); } clip = argv_[1]; info = get_clip_info( clip ); if ( ( "width" ∉ info ) || ( "height" ∉ info ) ) { run_orig( argv_ ); } haveSubtitles = "subtitle_id" ∈ info; dotIdx = clip.find_last( "." ); if ( dotIdx >= 0 ) { base = clip[:dotIdx]; for ( ext : [ ".txt", ".srt" ] ) { if ( fs.exists( base + ext ) ) { haveSubtitles = true; break; } } } if ( ! haveSubtitles ) { run_orig( argv_ ); } width = info["width"]; height = info["height"]; screens = get_screen_info(); id = get_active_window_id(); current = get_current_screen( screens, id ); print( "height = {}, width = {}, screen = {}\n".format( height, width, current ) ); expand = math.min( calc_expand( width, height, current... ), height / 7 ); args = ( path( "mplayer" ), "-vf", "pp", "-vf-add", "expand=0:-{}:0:0:1".format( expand ), "-vf-add", "harddup", clip ); print( "{}\n".format( text.join( args, " " ) ) ); os.exec( args... ); return ( 0 ); } /* vim: set ft=huginn */
Soution for Narcissist problem.
#! /bin/sh exec huginn --no-argv -E "${0}" #! huginn main() { c = "#! /bin/sh{1}~" "exec huginn --no-argv -E {3}${{0}}{3}{1}#! huginn{1}{1}~" "main() {{{1}{2}c = {3}{0}{3};{1}~" "{2}s = {3}{3};{1}~" "{2}while ( ( line = input() ) != none ) {{{1}~" "{2}{2}s += line;{1}~" "{2}}}{1}~" "{2}self = copy( c ).replace( {3}{5}{3}, {3}{3} )~" ".format({1}{2}{2}c.replace( {3}{5}{3}, ~" "{3}{5}{4}{3}{4}n{4}t{4}t{4}{3}{3} ), ~" "{3}{4}n{3}, {3}{4}t{3}, {3}{4}{3}{3}, {3}{4}{4}{3}, ~" "{3}{5}{3}{1}{2});{1}~" "{2}print( s == self ? {3}1{4}n{3} : {3}0{4}n{3} );{1}}}{1}{1}"; s = ""; while ( ( line = input() ) != none ) { s += line; } self = copy( c ).replace( "~", "" ).format( c.replace( "~", "~\"\n\t\t\"" ), "\n", "\t", "\"", "\\", "~" ); print( s == self ? "1\n" : "0\n" ); }
Soution for Ordered words problem.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import Algorithms as algo; import Mathematics as math; import Network as net; import Text as text; main( argv_ ) { url = size( argv_ ) > 1 ? argv_[1] : "http://wiki.puzzlers.org/pub/wordlists/unixdict.txt"; words = algo.materialize( algo.map( net.get( url ).stream, string.strip ), list ); ordered = algo.materialize( algo.filter( words, @( word ){ word == ∑( algo.map( algo.sorted( word ), string ) ); } ), list ); maxLen = algo.reduce( ordered, @( x, y ){ math.max( x, size( y ) ); }, 0 ); maxOrderedWords = algo.materialize( algo.filter( ordered, @[maxLen]( word ){ size( word ) == maxLen; } ), list ); print( "{}\n".format( text.join( algo.sorted( maxOrderedWords ), " " ) ) ); return ( 0 ); }
Program that can be read in reverse and still have exactly the same meaning (Palindrome).
#! /bin/sh exec huginn --no-argv -E "${0}" #! huginn main() { print( "Hello World!\n" ); return ( 0 ); } //*/ /*// } ;) 0 ( nruter ;) "n\!dlroW olleH" (tnirp { )(niam nniguh !# "}0{$" E- vgra-on-- nniguh cexe hs/nib/ !#
Soution for Parametrized SQL statement problem.
#! /bin/sh exec huginn -E --no-argv "${0}" #! huginn import Database as db; import Algorithms as algo; import FileSystem as fs; main() { dbPath = "/tmp/parametrized-sql.sqlite"; fs.remove( dbPath ); fs.open( dbPath, fs.OPEN_MODE.WRITE ); conn = db.connect( "sqlite3:///" + dbPath ); // Setup... conn.query( "CREATE TABLE Players (\n" "\tname VARCHAR(64),\n" "\tscore FLOAT,\n" "\tactive INTEGER,\n" "\tno VARCHAR(8)\n" ");" ).execute(); conn.query( "INSERT INTO Players VALUES ( 'name', 0, 'false', 99 );" ).execute(); conn.query( "INSERT INTO Players VALUES ( 'name', 0, 'false', 100 );" ).execute(); // Demonstrate parameterized SQL... parametrizedQuery = conn.query( "UPDATE Players SET name=?, score=?, active=? WHERE no=?" ); for ( i, v : algo.enumerate( ( "Smith, Steve", 42, true, 99 ) ) ) { parametrizedQuery.bind( i + 1, string( v ) ); } parametrizedQuery.execute(); // and show the results... for ( record : conn.query( "SELECT * FROM Players;" ).execute() ) { print( "{}\n".format( record ) ); } return ( 0 ); }
Check (multiplicative) persistence of a number.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import Algorithms as algo; import Operators as oper; to_digit( char_ ) { return ( number( integer( char_ ) - integer( '0' ) ) ); } persistence( num_ ) { n = 0; while ( true ) { s = string( num_ ); if ( size( s ) == 1 ) { print( "{}\nnumber of steps = {}\n".format( s, n ) ); break; } n += 1; print( "{}\n".format( num_ ) ); num_ = algo.reduce( algo.map( s, to_digit ), oper.multiply, $1 ); } return ( n ); } main( argv_ ) { persistence( number( argv_[1] ) ); return ( 0 ); }
Try to find largest persistent number in given range.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import Algorithms as algo; import Text as text; import Operators as oper; import Progress as progress; to_digit( char_ ) { return ( number( integer( char_ ) - integer( '0' ) ) ); } persistence( num_ ) { n = 0; while ( true ) { s = string( num_ ); if ( size( s ) == 1 ) { break; } n += 1; num_ = algo.reduce( algo.map( s, to_digit ), oper.multiply, $1 ); } return ( n ); } main( argv_ ) { limit = integer( argv_[1] ); digits = ( ( $2, 3 ), ( $3, 2 ), ( $7, limit ), ( $8, limit ), ( $9, limit ) ); parts = []; best = 1; for ( i, digit : algo.enumerate( digits ) ) { part = []; for ( repeat : algo.range( digit[1] ) ) { part.push( digit[0] ^ number( repeat ) ); } parts.push( part ); } for ( trialDesc : progress.bar( algo.product( algo.range( 3 ), algo.range( 2 ), algo.range( limit ), algo.range( limit ), algo.range( limit ) ) ) ) { n = $1; for ( i, count : algo.enumerate( trialDesc ) ) { n *= parts[i][count]; } current = persistence( n ); if ( current > best ) { best = current; s = ""; for ( digit, count : algo.zip( digits, trialDesc ) ) { s += text.repeat( string( digit[0] ), count ); } print( "\n{} - {}\n".format( s, best + 1 ) ); } } return ( 0 ); }
Calculate π to an arbitrary precision.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import Mathematics as math; main( argv_ ) { if ( size( argv_ ) >= 2 ) { prec = integer( argv_[1] ); print( "pi = {}\n".format( math.pi( number, prec ) ) ); } else { print( "you must specify a positive number\n" ); } return ( 0 ); }
Output program's own source code.
#! /bin/sh exec huginn --no-argv -E "${0}" #! huginn main() { c = "#! /bin/sh{1}~" "exec huginn --no-argv -E {3}${{0}}{3}{1}#! huginn{1}{1}~" "main() {{{1}{2}c = {3}{0}{3};{1}{2}print({1}~" "{2}{2}copy( c ).replace( {3}{5}{3}, {3}{3} )~" ".format({1}{2}{2}{2}c.replace( {3}{5}{3}, ~" "{3}{5}{4}{3}{4}n{4}t{4}t{4}{3}{3} ), ~" "{3}{4}n{3}, {3}{4}t{3}, {3}{4}{3}{3}, {3}{4}{4}{3}, ~" "{3}{5}{3}{1}{2}{2}){1}{2});{1}}}{1}{1}"; print( copy( c ).replace( "~", "" ).format( c.replace( "~", "~\"\n\t\t\"" ), "\n", "\t", "\"", "\\", "~" ) ); }
Apply the ROT13 cipher to the input text.
#! /bin/sh exec huginn --no-argv -E "${0}" "${@}" #! huginn import Algorithms as algo; rot13char( c ) { if ( c.is_alpha() ) { x = integer( c ); m = integer( c.is_upper() ? 'A' : 'a' ); x -= m; x += 13; x %= 26; x += m; c = character( x ); } return ( c ); } rot13( s ) { return ( algo.reduce( algo.map( algo.map( s, rot13char ), string ), @( r, c ) { r + c; } ) ); } main() { while ( ( line = input() ) != none ) { print( rot13( line.strip() ) + "\n" ); } }
Implementation of minimalistic Scheme interpreter.
#! /bin/sh exec huginn -E "${0}" "${@}" #! huginn import Algorithms as algo; import Mathematics as math; import Operators as op; import Text as text; import FileSystem as fs; class Env { _data = {}; _outer = none; constructor( params_ = (), args_ = (), outer_ = none ) { for ( i : algo.range( math.min( size( params_ ), size( args_ ) ) ) ) { _data[params_[i]] = args_[i]; } _outer = outer_; } update( dct_ ) { _data.update( dct_ ); } set_kv( k, v ) { _data[k] = v; } find( var_ ) { return ( var_ ∈ _data ? _data : _outer.find( var_ ) ); } } cc( x, y ) { tx = type( x ); if ( tx == boolean ) { x = x ? 1 : 0; tx = integer; } ty = type( y ); return ( ( ty == real ) && ( tx == integer ) ? real( x ) : x ); } standard_env() { env = Env(); bc = type( @[env](){} ); fr = type( type ); env.update( { "+": @( x, y ){ cc( x, y ) + cc( y, x ); }, "-": @( x, y ){ cc( x, y ) - cc( y, x ); }, "*": @( x, y ){ cc( x, y ) * cc( y, x ); }, "/": @( x, y ){ cc( x, y ) / cc( y, x ); }, ">": @( x, y ){ cc( x, y ) > cc( y, x ); }, "<": @( x, y ){ cc( x, y ) < cc( y, x ); }, ">=": @( x, y ){ cc( x, y ) >= cc( y, x ); }, "<=": @( x, y ){ cc( x, y ) <= cc( y, x ); }, "=": @( x, y ){ cc( x, y ) == cc( y, x ); }, "pow": @( x, y ){ real( x ) ^ real( y ); }, "abs": op.modulus, "append": @( x, y ){ cc( x, y ) + cc( y, x ); }, "apply": @( x, y ){ x( y... ); }, "begin": @( x... ){ x[-1]; }, "car": @( x ) { x[0]; }, "cdr": @( x ) { x[1:]; }, "cons": @( x, y ){ [x] + y; }, "eq?": @( x, y ){ cc( x, y ) == cc( y, x ); }, "equal?": @( x, y ){ cc( x, y ) == cc( y, x ); }, "length": @( x ) { size( x ); }, "list": @( x... ){ algo.materialize( x, list ); }, "list?": @( x ) { type( x ) == list; }, "map": @( x, y ){ algo.materialize( algo.map( y, x ), list ); }, "max": math.max, "min": math.min, "not": op.not, "null?": @( x ) { x == []; }, "number?": @( x ) { t = type( x ); ( t == real ) || ( t == integer ); }, "procedure?": @[bc, fr]( x ) { t = type( x ); t == bc || t == fr; }, "round": @( x ) { type( x ) == real ? math.round( x ) : x; }, "symbol?": @( x ) { type( x ) == string; }, "sqrt": @( x ) { math.square_root( real( x ) ); }, "sin": @( x ) { math.sinus( real( x ) ); }, "cos": @( x ) { math.cosinus( real( x ) ); }, "pi": math.pi( real ), "π": math.pi( real ) } ); return ( env ); } to_bool( v ) { switch ( type( v ) ) { case ( integer ): { return ( v != 0 ); } case ( list ): {} case ( string ): { return ( size( v ) > 0 ); } } return ( v ); } eval( x, env ) { if ( type( x ) == string ) { return ( env.find( x )[x] ); } else if ( type( x ) != list ) { return ( x ); } h = x[0]; his = type( h ) == string; if ( his ) { switch ( h ) { case ( "quote" ): { return ( x[1] ); } case ( "if" ): { test = x[1]; conseq = x[2]; alt = x[3]; exp = to_bool( eval( test, env ) ) ? conseq : alt; return ( eval( exp, env ) ); } case ( "lambda" ): { return ( @[_params: x[1], _body: x[2], _env: env] ( args_... ) { eval( _body, Env( _params, args_, _env ) ); } ); } case ( "define" ): { env.set_kv( x[1], eval( x[2], env ) ); return ( none ); } case ( "set!" ): { env.find( x[1] )[ x[1] ] = eval( x[2], env ); return ( none ); } } } proc = eval( h, env ); args = algo.materialize( algo.map( x[1:], @[env]( _ ){ eval( _, env ); } ), tuple ); return ( proc( args... ) ); } atom( token ) { a = token; try { return ( token.find( "." ) >= 0 ? real( token ) : integer( token ) ); } catch ( Exception e ) { } return ( a ); } parse( tokens ) { if ( size( tokens ) == 0 ) { throw Exception( "unexpected EOF" ); } token = tokens[0]; tokens.pop_front(); if ( token == "(" ) { exprs = []; while ( tokens[0] != ")" ) { exprs.push( parse( tokens ) ); } tokens.pop_front(); return ( exprs ); } else if ( token == ")" ) { throw Exception( "unexpected )" ); } else { return ( atom( token ) ); } } is_quoted( token_ ) { isQuoted = false; l = size( token_ ); if ( l >= 2 ) { h = token_[0]; isQuoted = ( h == token_[-1] ) && ( ( h == '"' ) || ( h == '\'' ) ); } return ( isQuoted ); } split_quotes( str_ ) { tokens = deque(); singleQuoteCount = 0; doubleQuoteCount = 0; escaped = false; token = ""; white = " \t\r\n\v\f\a\b"; for ( c : str_ ) { if ( escaped ) { token += string( c ); escaped = false; continue; } paren = ( c == '(' ) || ( c == ')' ); if ( ( white.find( string( c ) ) >= 0 ) || paren ) { inQuotes = ( ( doubleQuoteCount % 2 ) != 0 ) || ( ( singleQuoteCount % 2 ) != 0 ); if ( ! inQuotes ) { if ( size( token ) != 0 ) { t = copy( token ).replace( "\\ ", " " ).replace( "\\\t", "\t" ); comented = false; if ( ! is_quoted( t ) ) { comentPos = t.find( ";" ); if ( comentPos >= 0 ) { t = t[:comentPos]; comented = true; } } if ( size( t ) > 0 ) { tokens.push( t ); } token.clear(); if ( comented ) { break; } } if ( paren ) { tokens.push( string( c ) ); } continue; } } token += string( c ); if ( c == '\\' ) { escaped = true; } else if ( ( c == '"' ) && ( ( singleQuoteCount % 2 ) == 0 ) ) { doubleQuoteCount += 1; } else if ( ( c == '\'' ) && ( ( doubleQuoteCount % 2 ) == 0 ) ) { singleQuoteCount += 1; } } if ( size( token ) != 0 ) { tokens.push( token.replace( "\\ ", " " ).replace( "\\\t", "\t" ) ); } if ( ( ( doubleQuoteCount % 2 ) != 0 ) || ( ( singleQuoteCount % 2 ) != 0 ) ) { throw Exception( "Unterminated quotes" ); } return ( tokens ); } interpret( lineFeed, env ) { while ( ( line = lineFeed() ) != none ) { t = split_quotes( line ); if ( size( t ) == 0 ) { continue; } e = parse( t ); /* print( "{}\n".format( e ) ); */ r = eval( e, env ); if ( r != none ) { print( "{}\n".format( scm_to_string( r ) ) ); } } } scm_to_string( e ) { if ( type( e ) == list ) { e = "({})".format( text.join( algo.materialize( algo.map( e, string ), list ), " " ) ); } return ( e ); } main( argv_ ) { env = standard_env(); if ( size( argv_ ) > 1 ) { for ( a : argv_[1:] ) { f = fs.open( a, fs.OPEN_MODE.READ ); interpret( @[f](){ f.read_line(); }, env ); } } else { interpret( input, env ); } return ( 0 ); }