The Bear's Den

Enter at your own risk

Self-Generating Games

Task 1: Kolakoski Sequence

Submitted by: Mohammad Sajid Anwar


You are given an integer, $int > 3.

Write a script to generate the Kolakoski Sequence of given length $int and return the count of 1 in the generated sequence. Please follow the wikipedia page for more informations.

Example 1

Input: $int = 4
Output: 2

(1)(22)(11)(2) => 1221

Example 2

Input: $int = 5
Output: 3

(1)(22)(11)(2)(1) => 12211

Example 3

Input: $int = 6
Output: 3

(1)(22)(11)(2)(1)(22) => 122112

Example 4

Input: $int = 7
Output: 4

(1)(22)(11)(2)(1)(22)(1) => 1221121

Example 5

Input: $int = 8
Output: 4

(1)(22)(11)(2)(1)(22)(1)(22) => 12211212

Solution

One way to generate the Kolakosi sequence of \(n\) runs follows this procedure:

The generated sequence is split into two parts:

To augment the sequence by one run,

Afterwards, the generated ones need to be counted, which is a nice subtlety as the leading one is not generated and thus does not count.

A level of caching may be added:
The sequence of \(k \le n\) runs can easily be extracted from the longer sequence, as the length of the \(k\)-runs sequence is the sum over the first \(k\) elements. Once a sequence is generated, it can be used to process all shorter sequences. The longest generated sequence will be kept.

If the cached sequence has a head as least as long as \(k\), it may be used unaltered. Otherwise as many runs need to be added as the head is shorter than \(k\).

The procedure is applicable to any non-negative number \(k\) of runs.

J

Creating a class Kolakosi.

A Kolokosi sub-sequence is stored as an array of the boxed head and the boxed tail.

The verb run adds one additional run to the cached sequence.

The verb count counts the generated 1’s in x runs from a sufficiently large sub-sequence y

The method ones augments the cached sequence as needed by calling run the required number of times and then returns the number of generated ones in the specified number of runs.

coclass 'Kolakosi'
create =: 3 : 'sequence =: (1, 2); 2'
destroy =: codestroy
run =: ((, {.@]) ; }.@] , {.@] # >:@(2&|)@#@[)&>/
count =: +/@(1&(e.~))@(3&}.)@([ (+/@{. {. ]) ;@])
ones =: 3 : 0
    sequence =: run^:(0&>.@(y&-)@#@>@{.@]) sequence
    y count sequence
)

cocurrent 'base'
K =: 0 conew 'Kolakosi'
echo ones__K 6

For visualization, here are the intermediate results from calling run several times on the initial sequence, resulting in 6 runs:

  run^:(<5) 1 2; 2
head tail
1 2 2
1 2 2 1 1
1 2 2 1 1 2
1 2 2 1 1 2 1
1 2 2 1 1 2 1 2 2

See the full solution.

Perl

The Perl solution was derived from its J counterpart, got the caching added, which in turn was adapted into the J solution.

use strict;
use warnings;
use List::Util 'sum0';

sub kolakosi ($k) {
    state $head = [1, 2];
    state $tail = [2];
    state $run = sub {
        push @$tail, (@$head % 2 + 1) x $tail->[0];
        push @$head, shift @$tail;
    };
    $run->() for @$head .. $k - 1;
    my $len = sum0 $head->@[0 .. $k - 1];
    scalar grep $_ == 1, (@$head, @$tail)[3 .. $len - 1];
}

See the full solution to task 1.

Task 2: Who Wins

Submitted by: Simon Green


It’s NFL playoff time. Since the 2020 season, seven teams from each of the league’s two conferences (AFC and NFC) qualify for the playoffs based on regular season winning percentage, with a tie-breaking procedure if required. The top team in each conference receives a first-round bye, automatically advancing to the second round.

The following games are played. Some times the games are played in a different order. To make things easier, assume the order is always as below.

Example 1

NFC Conference 2024/5. Teams were Detroit, Philadelphia, Tampa Bay,
Los Angeles Rams, Minnesota, Washington and Green Bay.
Philadelphia - seeded second - won.

Input: $results = "HAHAHH"
Output: "Team 2 defeated Team 6"

In Week 1, Team 2 (home) won against Team 7, Team 6 (away) defeated Team 3 and
Team 4 (home) were victorious over Team 5. This means the second week match ups
are Team 1 at home to Team 6, and Team 2 hosted Team 4.

In week 2, Team 6 (away) won against Team 1, while Team 2 (home) beat Team 4.
The final week was Team 2 hosting Team 6

Example 2

AFC Conference 2024/5. Teams were Kansas City, Buffalo, Baltimore, Houston,
Los Angeles Charges, Pittsburgh and Denver.
Kansas City - seeded first - won.

Input: $results = "HHHHHH"
Output: "Team 1 defeated Team 2"

Example 3

AFC Conference 2021/2. Teams were Tennessee, Kansas City, Buffalo, Cincinnati,
Las Vegas, New England and Pittsburgh.
Cincinnati - seeded fourth - won.

Input: $results = "HHHAHA"
Output: "Team 4 defeated Team 2"

Example 4

NFC Conference 2021/2. Teams were Green Bay, Tampa Bay, Dallas, Los Angeles Rams,
Arizona, San Francisco and Philadelphia.
The Rams - seeded fourth - won.

Input: $results = "HAHAAH"
Output: "Team 4 defeated Team 6"

Example 5

NFC Conference 2020/1. Teams were Green Bay, New Orleans, Seattle, Washington,
Tampa Bay, Los Angeles Rams and Chicago.
Tampa Bay - seeded fifth - won.

Input: $results = "HAAHAA"
Output: "Team 5 defeated Team 1"

Solution

This was a difficult one. Not so much in implementing a solution, but in understanding the procedure. Tried some interpretations until the examples were reproduced.

The solution is basically a chain of index and sort operations on a matrix containing the setup for week 1.

Using the results as indices into the starting matrix produces the winners of week 1, which are then sorted and arranged into the matrix for week 2. Indexing and sorting again reveals the finalists on which the final result can be applied.

To unify the process, team 1 is set as a participant in week 1 playing against itself and therefore always reaching week 2. Accordingly, a dummy result is prepended to the results.

Perl

Here indexND is used extract elements from a matrix into an array and index1d to arrange an array as a matrix.

use strict;
use warnings;
use PDL;
use PDL::NiceSlice;

sub who_wins {
    my $result = long 0, split //, shift =~ tr/HA/01/r;
    state $week1 = long [1, 1], [2, 7], [3, 6], [4, 5];
    state $iweek2 = long [0, 3], [1, 2];
    my $s1 = cat(sequence(4), $result(0:3))->xchg(0, 1);
    my $s2 = cat(sequence(2), $result(4:5))->xchg(0, 1);
    my $s3 = $result(6) ? indx(1, 0) : indx(0, 1);

    $week1->xchg(0, 1)->indexND($s1)->qsort->index1d($iweek2)->xchg(0, 1)
        ->indexND($s2)->qsort->index1d($s3);
}

See the full solution to task 2.

J

The verb { (“From”) can be used for all kinds of index operations.

require 'format/printf'

WhoWins =: 3 : 0
    result =. 0, y e. 'A'
    week1 =. (1, 1), (2, 7), (3, 6) ,: 4, 5
    iweek2 =. 0 3,: 1 2
    s1 =. ;/ (i.4) ,. (i.4) { result
    s2 =. ;/ (i.2) ,. (4 + i.2) { result
    s3 =. 6 { result
    |.^:s3 /:~ s2 { iweek2 { /:~ s1 { week1
)

'Team %d defeated Team %d' printf WhoWins 'HAHAHH'

The dissected processing of example 1:

dissect

See the full solution to task 2.