Generate a Kolakoski sequence

22

4

Definition1

A Kolakoski sequence is a self-describing infinite sequence {kn} of alternating blocks of 1's and 2's, given by the following rules:

  • k0 = 1
  • kn = the length of the (n+1)'th block

The Task

Given a positive integer n, generate the first n elements of the Kolakoski sequence.

Details

Input will be provided as a single command line argument n. Please write a full program that will print the first n elements of the Kolakoski sequence (in order) to STDOUT, with each element separated by your favorite whitespace.

Scoring

Lets count source code bytes this time with all whitespace included. Fewest number of bytes wins. In the event of a tie, the solution with the earliest submission time wins.

The Sequence2

1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 1, 2, 2, ...


References
  1. John Smith, Ariel Scolnicov, yark. "Kolakoski sequence" (version 3). PlanetMath.org. Freely available at http://planetmath.org/KolakoskiSequence.html.
  2. The Online Encyclopedia of Integer Sequences http://oeis.org/A000002

Other resources

ardnew

Posted 2012-09-18T01:38:48.683

Reputation: 2 177

Question was closed 2018-03-06T11:43:40.270

Any particular reason n is command line arg? – CalculatorFeline – 2016-04-01T15:19:12.383

@CatsAreFluffy not originally, but i'll happily keep any requirement that adds a few irritating chars to the golf-oriented languages :) – ardnew – 2016-04-01T16:35:05.620

That's a cumbersome I/O format that makes many languages unable to participate.

– Mego – 2016-04-02T05:26:06.527

@Mego thanks for the tip. but in fairness to the current submissions, let's not go changing preferential specs on a 4 year old question – ardnew – 2016-04-02T20:01:24.707

@ardnew I'm not saying to change it. I'm just saying it's not a good idea. – Mego – 2016-04-02T20:03:10.933

11

Note: reposting this question is being discussed on meta.

– Peter Taylor – 2018-02-21T16:49:03.720

Answers

7

J - 23 char

A little late to the party, but I'd like to bust out a neat little J trick here.

1($1+2|I.)^:_~".>2{ARGV

Given input N, this verb operates by executing N&($1+2|I.) on a starting argument of 1 until it reaches a fixed point. If the item at index i in y is n, there will be n copies of i in I.y, so for instance I. 0 1 1 0 0 3 1 is 1 2 5 5 5 6. We mod the result of that by 2 and add one. Then, x $ y forces y into a list of length x, truncating it or extending it cyclically as necessary.

So here's what happens when the input is, say, 10.

   10 ($1+2|I.)^:a: 1
1 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1
1 2 1 2 1 2 1 2 1 2
1 2 2 1 2 2 1 2 2 1
1 2 2 1 1 2 1 1 2 2
1 2 2 1 1 2 1 2 2 1

We start with a row of all 1s and then "settle down" into the Kolakoski sequence. First, it turns into 1 2 1 2 1 2... as each contiguous block of ones or twos is described by length 1. Then we apply it again and it turns into 1 2 2 1 2 2 1 2 2... since the ones are described by 1 and the twos are described by 2. The we continue again and again until we see there is no change, at which point we stop and give the result.

Other "self-describing" sequences can be similarly derived in J using I. and ^:_.


Edit

Over a year ago, @ardnew asked:

what is the relationship between n and the number of those intermediate iterations required to generate the sequence of length n?

To make sure we're on the same page, I consider the calculation for n = 10 above to have taken 5 iterations.

If there are s terms settled at the i-th iteration for n, then at the (i+1)-th iteration, there will be (at least) k0 + k1 + ... + ks + 1 terms settled. The '+ 1' appears because the next term will also be correct, since it must be and is different from the term before it.

So if K(s) is the sequence of partial sums of kn, then we can lower bound the number of iterations for n by the least a such that (1+K)a(1) ≥ n. I don't how to prove we don't accidentally do a bit better (by picking up more correct terms than we expected in some iteration), but according to the numbers, we don't:

   k =: ($ 1 + 2 | I.)^:_&1               NB. Kolakoski seq
   pk =: +/\ @: k                         NB. partial sums ("K")
   ((1 + pk 2000) {~ <:) ::_:^:(i.20) 1   NB. iterating 1+K, say, 20 times
1 2 4 7 11 18 28 43 65 99 150 226 340 511 768 1153 1728 2590 _ _
   NB. compare with observed number of settled terms up to 2000:
   +/"1 }. (k <./\ . ="1 ($1+2|I.)^:a:&1) 2000
1 2 4 7 11 18 28 43 65 99 150 226 340 511 768 1153 1728 2000

The underscores are index errors (:: _:), telling us 20 iterations is too much for the first 2000 terms of kn to handle.

algorithmshark

Posted 2012-09-18T01:38:48.683

Reputation: 8 144

@ardnew Long overdue, but I took at look at how the iterations thing acts. – algorithmshark – 2016-02-10T22:14:50.947

what is the relationship between n and the number of those intermediate iterations required to generate the sequence of length n? – ardnew – 2014-05-04T22:47:13.677

5

Ruby (73 characters)

s=[1,2,2];n=2;ARGV[0].to_i.times{puts s[n-2];s[n].times{s+=[1+n%2]};n+=1}

r.e.s.

Posted 2012-09-18T01:38:48.683

Reputation: 2 872

3

Python (87 chars)

My code turned out to be basically the same as scleaver's solution even though I wrote it independently. It saves a few characters by not shifting the index i by 1.

import sys
n=int(sys.argv[1])
l=[1,2,2]
for i in range(2,n):l+=[1+i%2]*l[i]
print l[:n]

xnor

Posted 2012-09-18T01:38:48.683

Reputation: 115 687

3

Perl, 41 39 bytes

A trivial modification of the classic TPR(0,3) solution:

perl -E 'say$_=($.+=!--$.[$.])%2+1for@.=(0)x pop' 20

Ton Hospel

Posted 2012-09-18T01:38:48.683

Reputation: 14 114

3

GolfScript (48 chars)

You can't test this online because the online GS shell doesn't take command-line arguments, but:

;"#{ARGV[-1]}"~[1 2.]2{.2$=[1$2%)]*@\+\)}3$*;<n*

This takes input from stdin instead and works

~[1 2.]2{.2$=[1$2%)]*@\+\)}3$*;<n*

Peter Taylor

Posted 2012-09-18T01:38:48.683

Reputation: 41 901

2Your 48-char version does work if you change ARVG to ARGV ;o). E.g., golfscript.rb kola.gs 10. – r.e.s. – 2012-09-19T14:48:45.837

3

Python 93

Adapted from my solution to Calculate the nth term of Golomb's self-describing sequence:

import sys;n=int(sys.argv[1]);a=[1,2,2];
for i in range(3,n):a+=[~i%2+1]*a[i-1]
print a[:n]

Still trying to figure out how to do this with list comprehension which I just learned about today, but I'm running into problems with self-reference.

EDIT: Instead of breaking if list was too long, just printed the appropriate slice.

EDIT: Now pulling arg from command line

scleaver

Posted 2012-09-18T01:38:48.683

Reputation: 507

n is never set prior to being referenced (either hard coded or read in from user). The code fails to run successfully. – chucksmash – 2012-09-19T16:54:12.067

It's required to use command-line input of what you call n, which will add some characters; however, you can save some by indenting only one space.) That's a very nice approach! Here's a 69-char Ruby version: s=[1,2,2];n=3;ARGV[0].to_i.times{puts s[n-3];s+=[~n%2+1]*s[n-1];n+=1}. – r.e.s. – 2012-09-19T17:04:46.720

Reading from command line the way I did it (is there a better way?) would add 28 characters to this code for a total of 93 characters. Still cool and still kills my noob attempt but 65 chars, it ain't. – chucksmash – 2012-09-19T17:26:34.800

Yeah, it's the import sys and the lengthy sys.argv that really kills it. thanks for the tips. – scleaver – 2012-09-19T17:45:35.633

2

Haskell 157 144

Haskell is kind of verbose so I expect this will be significantly longer than the shortest answer, but here it is.

import System
a=1:2:drop 2(concat.zipWith replicate a.cycle$[1,2])
main=do args<-getArgs;putStr$concatMap((' ':).show)$take(read$args!!0::Int)a

Edit:

Implemented FUZxxl's suggestions and also a few other small fixes.

Matt

Posted 2012-09-18T01:38:48.683

Reputation: 1 395

Try to separate the statements in the do block with semicolons instead of newlines. That might help. Ans: (\b->' ':show b) is equal to ((' ':).show). Additionally, you might want to factor out a into a global variable to get rid of the phony let. – FUZxxl – 2012-09-19T20:10:08.673

1

Brain-Flak, 128 bytes

(({}<((())<>)>)<{({}[()]<{{({}[()])<>(({}))<>}{}<>(()()()[{}])<>}<>{({}<>)<>}(())<>>)}>){({}[()]<({}<>)<>>)}{}{{}}<>{({}<>)<>}<>

Try it online!

Post Rock Garf Hunter

Posted 2012-09-18T01:38:48.683

Reputation: 55 382

1

Python (118 characters)

Takes n as a command line argument. Could trim four more characters if the printing of first n requirement is relaxed to first n or n + 1. I can't think of any more fat to trim...will be interested to see what a more experienced Python golfer could do

import sys
k,b=[1,2,2],1
n=int(sys.argv[1])
while len(k)<n:k.extend([2,1][b%2]for z in range(k[b+1]));b+=1
print k[:n]

chucksmash

Posted 2012-09-18T01:38:48.683

Reputation: 119

1

Perl, 59 chars

say"@{[map{push@a,(2-$_%2)x($b=$a[$_-1]||$_);$b}1..shift]}"

As usual, run with Perl 5.10+ and the -M5.010 switch to enable the say feature.

Ilmari Karonen

Posted 2012-09-18T01:38:48.683

Reputation: 19 513

perl5.24.1 -M5.010 -E 'say"@{[map{push@a,(2-$%2)x($b=$a[$-1]||$);$b}1..shift]}"' ; produces no digits ; perl5.24.1 -E 'print "@{[map{push@a,(2-$%2)x($b=$a[$_-1]||$_);$b}1..shift]}"' ; also does nothing – Alexx Roche – 2017-07-24T13:23:34.340

1@AlexxRoche: You need to give the number of elements you want as a command line parameter, e.g. perl -E 'print "@{[map{push@a,(2-$_%2)x($b=$a[$_-1]||$_);$b}1..shift]}"' 50 for the first 50 elements. If you omit the length, the code defaults to printing zero elements. – Ilmari Karonen – 2017-07-24T15:09:11.930

0

Javascript (414 Characters)

function range(n,e,t){if("undefined"==typeof e&&(e=n,n=0),"undefined"==typeof t&&(t=1),t>0&&n>=e||0>t&&e>=n)return[];for(var i=[],r=n;t>0?e>r:r>e;r+=t)i.push(r);return i}function kolakoskiGen(n){var e=[1,2,2],t=parseInt(n),r=range(2,t);for(i in r)if(-1!=r.indexOf(parseInt(i))){var f=[1+i%2];f.length=f.length*e[i],f[f.length-1]=f[0],2==f.length?(e[e.length]=f[0],e[e.length]=f[1]):e[e.length]=f[0]}console.log(e)}

Could probably be more Efficient

Shubshub

Posted 2012-09-18T01:38:48.683

Reputation: 31

3

Hi Shubshub, welcome to the site! Since this is a [tag:code-golf] challenge, all answers are expected to attempt to make the code as short as possible. You should look through this page giving tips on how to golf your code, and then [edit] this post to include your new shorter code.

– James – 2016-04-28T04:24:29.903