Task: Kolakoski sequence



C#: using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KolakoskiSequence {
    class Crutch {
        public readonly int len;
        public int[] s;
        public int i;

        public Crutch(int len) {
            this.len = len;
            s = new int[len];
            i = 0;
        }

        public void Repeat(int count) {
            for (int j = 0; j < count; j++) {
                if (++i == len) return;
                s[i] = s[i - 1];
            }
        }
    }

    static class Extension {
        public static int NextInCycle(this int[] self, int index) {
            return self[index % self.Length];
        }

        public static int[] Kolakoski(this int[] self, int len) {
            Crutch c = new Crutch(len);

            int k = 0;
            while (c.i < len) {
                c.s[c.i] = self.NextInCycle(k);
                if (c.s[k] > 1) {
                    c.Repeat(c.s[k] - 1);
                }
                if (++c.i == len) return c.s;
                k++;
            }
            return c.s;
        }

        public static bool PossibleKolakoski(this int[] self) {
            int[] rle = new int[self.Length];
            int prev = self[0];
            int count = 1;
            int pos = 0;
            for (int i = 1; i < self.Length; i++) {
                if (self[i] == prev) {
                    count++;
                }
                else {
                    rle[pos++] = count;
                    count = 1;
                    prev = self[i];
                }
            }
            
            for (int i = 0; i < pos; i++) {
                if (rle[i] != self[i]) {
                    return false;
                }
            }
            return true;
        }

        public static string AsString(this int[] self) {
            StringBuilder sb = new StringBuilder("[");
            int count = 0;
            foreach (var item in self) {
                if (count > 0) {
                    sb.Append(", ");
                }
                sb.Append(item);
                count++;
            }
            return sb.Append("]").ToString();
        }
    }

    class Program {
        static void Main(string[] args) {
            int[][] ias = {
                new int[]{1, 2},
                new int[]{2, 1},
                new int[]{1, 3, 1, 2},
                new int[]{1, 3, 2, 1}
            };
            int[] lens = { 20, 20, 30, 30 };

            for (int i = 0; i < ias.Length; i++) {
                int len = lens[i];
                int[] kol = ias[i].Kolakoski(len);

                Console.WriteLine("First {0} members of the sequence by {1}: ", len, ias[i].AsString());
                Console.WriteLine(kol.AsString());
                Console.WriteLine("Possible Kolakoski sequence? {0}", kol.PossibleKolakoski());
                Console.WriteLine();
            }
        }
    }
}






VB: Imports System.Runtime.CompilerServices
Imports System.Text

Module Module1

    Class Crutch
        Public ReadOnly len As Integer
        Public s() As Integer
        Public i As Integer

        Public Sub New(len As Integer)
            Me.len = len
            s = New Integer(len - 1) {}
            i = 0
        End Sub

        Public Sub Repeat(count As Integer)
            For j = 1 To count
                i += 1
                If i = len Then
                    Return
                End If
                s(i) = s(i - 1)
            Next
        End Sub
    End Class

    <Extension()>
    Public Function NextInCycle(self As Integer(), index As Integer) As Integer
        Return self(index Mod self.Length)
    End Function

    <Extension()>
    Public Function Kolakoski(self As Integer(), len As Integer) As Integer()
        Dim c As New Crutch(len)

        Dim k = 0
        While c.i < len
            c.s(c.i) = self.NextInCycle(k)
            If c.s(k) > 1 Then
                c.Repeat(c.s(k) - 1)
            End If
            c.i += 1
            If c.i = len Then
                Return c.s
            End If
            k += 1
        End While

        Return c.s
    End Function

    <Extension()>
    Public Function PossibleKolakoski(self As Integer()) As Boolean
        Dim rle(self.Length) As Integer
        Dim prev = self(0)
        Dim count = 1
        Dim pos = 0
        For i = 2 To self.Length
            If self(i - 1) = prev Then
                count += 1
            Else
                rle(pos) = count
                pos += 1

                count = 1
                prev = self(i - 1)
            End If
        Next
        REM no point adding final 
        For i = 1 To pos
            If rle(i - 1) <> self(i - 1) Then
                Return False
            End If
        Next
        Return True
    End Function

    <Extension()>
    Public Function AsString(self As Integer()) As String
        Dim sb As New StringBuilder("[")
        Dim it = self.GetEnumerator()
        If it.MoveNext Then
            sb.Append(it.Current)
        End If
        While it.MoveNext
            sb.Append(", ")
            sb.Append(it.Current)
        End While
        Return sb.Append("]").ToString
    End Function

    Sub Main()
        Dim ias()() As Integer = {New Integer() {1, 2}, New Integer() {2, 1}, New Integer() {1, 3, 1, 2}, New Integer() {1, 3, 2, 1}}
        Dim lens() As Integer = {20, 20, 30, 30}

        For i = 1 To ias.Length
            Dim len = lens(i - 1)
            Dim kol = ias(i - 1).Kolakoski(len)

            Console.WriteLine("First {0} members of the sequence by {1}: ", len, ias(i - 1).AsString)
            Console.WriteLine(kol.AsString)
            Console.WriteLine("Possible Kolakoski sequence? {0}", kol.PossibleKolakoski)
            Console.WriteLine()
        Next
    End Sub

End Module