The challenge

You’re already almost 1.5km (almost a mile) below the surface of the ocean, already so deep that you can’t see any sunlight. What you can see, however, is a giant squid that has attached itself to the outside of your submarine.

Maybe it wants to play bingo?

Bingo is played on a set of boards each consisting of a 5x5 grid of numbers. Numbers are chosen at random, and the chosen number is marked on all boards on which it appears. (Numbers may not appear on all boards.) If all numbers in any row or any column of a board are marked, that board wins. (Diagonals don’t count.)

[…]

To guarantee victory against the giant squid, figure out which board will win first. What will your final score be if you choose that board?

You can read the challenge more in depth, here.

Part 1

Full solution

auto input = [stdin.byLineCopy().array].map!(a => [                         // input
    a.front.splitter(",").map!(to!long).array,                              // parse numbers
    a[1..$].map!`a.splitter(" ").filter!"!a.empty".map!(to!long)`           // parse cards
    .joiner.array]).front;
immutable ncards = input[1].length / 25;                                    // calc number of cards
foreach(pos, i; input[0]) foreach(c; 0..ncards) {                           // for each number & card
    foreach(n; 0..25) if(input[1][c*25 + n] == i) input[1][c*25 + n] = -1;  // set matching numbers
    auto e = evenChunks(input[1][c*25..c*25+25],5).array;                   // construct card RoR
    foreach(el; zip(e, e.dup.transposed)) if(findSkip(el[0], repeat(-1L,5)) // find row
            || findSkip(el[1], repeat(-1L,5))) {                            // find column
        writeln(input[1][c*25..c*25+25].filter!"a != -1".sum * i);          // calculate result
        return;                                                             // hang
    }
}

Part 2

On the other hand, it might be wise to try a different strategy: let the giant squid win.

You aren’t sure how many bingo boards a giant squid could play at once, so rather than waste time counting its arms, the safe thing to do is to figure out which board will win last and choose that one. That way, no matter which boards it picks, it will win for sure.

[…]

Figure out which board will win last. Once it wins, what would its final score be?

Full solution

auto input = [stdin.byLineCopy().array].map!(a => [                         // input
    a.front.splitter(",").map!(to!long).array,                              // parse numbers
    a[1..$].map!`a.splitter(" ").filter!"!a.empty".map!(to!long)`           // parse cards
    .joiner.array]).front;
immutable ncards = input[1].length / 25;                                    // calc number of cards
bool[] winners = new bool[ncards];
foreach(pos, i; input[0]) foreach(c; 0..ncards) {                           // for each number & card
    foreach(n; 0..25) if(input[1][c*25 + n] == i) input[1][c*25 + n] = -1;  // set matching numbers
    auto e = evenChunks(input[1][c*25..c*25+25],5).array;                   // construct card RoR
    foreach(el; zip(e, e.dup.transposed)) if(findSkip(el[0], repeat(-1L,5)) // find row
            || findSkip(el[1], repeat(-1L,5))) {                            // find column
        winners[c] = true; if(winners.all) {                                // fill winners list & check
            writeln(input[1][c*25..c*25+25].filter!"a != -1".sum * i);      // calculate result
            return;                                                         // hang
        }
    }
}