Skip to content

Instantly share code, notes, and snippets.

@jpelgrim
Last active December 12, 2021 00:04
Show Gist options
  • Select an option

  • Save jpelgrim/ee72b5d43fb6455a24c465121565511f to your computer and use it in GitHub Desktop.

Select an option

Save jpelgrim/ee72b5d43fb6455a24c465121565511f to your computer and use it in GitHub Desktop.

Revisions

  1. jpelgrim renamed this gist Dec 12, 2021. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. jpelgrim created this gist Dec 11, 2021.
    334 changes: 334 additions & 0 deletions aoc21_day11_part1
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,334 @@
    // Copyright 2019 the Dart project authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license
    // that can be found in the LICENSE file.
    import 'package:flutter/material.dart';

    const initialMatrix = [
    [4, 6, 5, 8, 1, 3, 7, 6, 3, 7],
    [3, 2, 7, 7, 8, 7, 4, 3, 5, 5],
    [4, 5, 2, 5, 6, 1, 1, 1, 8, 3],
    [3, 1, 2, 8, 1, 2, 5, 8, 8, 8],
    [8, 7, 3, 4, 8, 3, 2, 8, 3, 8],
    [4, 1, 7, 5, 4, 6, 3, 2, 5, 7],
    [8, 3, 2, 1, 4, 2, 3, 5, 5, 2],
    [4, 8, 3, 2, 1, 4, 5, 2, 5, 3],
    [8, 2, 8, 6, 8, 3, 4, 8, 5, 1],
    [4, 8, 8, 5, 3, 2, 3, 1, 3, 8],
    ];

    void main() {
    runApp(const Day11());
    }

    class Day11 extends StatefulWidget {
    const Day11({Key? key}) : super(key: key);

    @override
    State<StatefulWidget> createState() {
    return _Day11State();
    }
    }

    class _Day11State extends State<Day11> {

    Matrix matrix = initialMatrix;

    bool initialized = false;

    int step = 0;
    int popCount = 0;

    bool stopped = true;

    @override
    Widget build(BuildContext context) {
    return MaterialApp(
    debugShowCheckedModeBanner: false,
    theme: ThemeData.dark().copyWith(
    scaffoldBackgroundColor: Colors.black38,
    ),
    home: Scaffold(
    body: Container(
    constraints: const BoxConstraints.expand(),
    decoration: BoxDecoration(
    border: Border.all(
    color: Colors.transparent,
    ),
    ),
    child: SafeArea(
    child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
    Text(step == 0 ? '' : 'Step $step'),
    const SizedBox(height: 16.0),
    Container(
    decoration: BoxDecoration(
    border: Border.all(
    color: Colors.transparent,
    ),
    ),
    child: MatrixGrid(matrix: matrix),
    ),
    const SizedBox(height: 16.0),
    Row(mainAxisAlignment: MainAxisAlignment.center, children: [
    MaterialButton(
    child: const Icon(
    Icons.replay,
    color: Colors.white,
    size: 24.0,
    ),
    onPressed: () {
    _reset();
    }),
    MaterialButton(
    child: const Icon(
    Icons.stop,
    color: Colors.white,
    size: 24.0,
    ),
    onPressed: () {
    _stop();
    }),
    MaterialButton(
    child: const Icon(
    Icons.play_arrow,
    color: Colors.white,
    size: 24.0,
    ),
    onPressed: () {
    _go();
    }),
    MaterialButton(
    child: const Icon(
    Icons.plus_one_rounded,
    color: Colors.white,
    size: 24.0,
    ),
    onPressed: () {
    _plus1();
    })
    ]),
    const SizedBox(height: 16.0),
    Text(step == 0 ? '' : 'Number of flashes: $popCount'),
    ],
    ),
    ),
    ),
    ),
    );
    }

    void _reset() {
    setState(() {
    step = 0;
    popCount = 0;
    _initMatrix();
    });
    }

    void _stop() {
    setState(() {
    stopped = true;
    });
    }

    void _go() async {
    if (!initialized) {
    initialized = true;
    _initMatrix();
    }
    stopped = false;
    for (int i = step; i < 100; i++) {
    if (stopped) break;
    await Future.delayed(const Duration(milliseconds: 100));
    await _takeStep();
    }
    }

    void _plus1() => _takeStep();

    Future<void> _takeStep() async {
    final flashes = matrix.increaseEnergy();
    if (flashes.isNotEmpty) {
    final previousFlashes = Set<Point>.from(flashes);
    do {
    await Future.delayed(const Duration(milliseconds: 30));
    final newFlashes = matrix.flashNeighbours(previousFlashes);
    setState(() {});
    if (newFlashes.isEmpty) {
    break;
    }
    previousFlashes.clear();
    previousFlashes.addAll(newFlashes);
    flashes.addAll(newFlashes);
    } while (true);
    popCount += flashes.length;
    }
    setState(() {
    step++;
    });
    }

    void _initMatrix() {
    matrix = List.empty(growable: true);
    for (int y = 0; y < initialMatrix.length; y++) {
    List<int> row = List.empty(growable: true);
    for (int x = 0; x < initialMatrix[y].length; x++) {
    row.add(initialMatrix[y][x]);
    }
    matrix.add(row);
    }
    }
    }

    typedef Matrix = List<MatrixRow>;
    typedef MatrixRow = List<int>;

    extension MatrixExtensions on Matrix {
    Set<Point> increaseEnergy() {
    final flashed = <Point>{};
    for (int y = 0; y < length; y++) {
    for (int x = 0; x < length; x++) {
    var energy = this[y][x];
    if (energy == 9) {
    flashed.add(Point(x, y));
    this[y][x] = 0;
    } else {
    this[y][x] = energy + 1;
    }
    }
    }
    return flashed;
    }

    Iterable<Point> flashNeighbours(Iterable<Point> flashed) {
    final newFlashes = <Point>{};
    for (var point in flashed) {
    if (flash(Point(point.x - 1, point.y - 1))) {
    newFlashes.add(Point(point.x - 1, point.y - 1));
    }
    if (flash(Point(point.x, point.y - 1))) {
    newFlashes.add(Point(point.x, point.y - 1));
    }
    if (flash(Point(point.x + 1, point.y - 1))) {
    newFlashes.add(Point(point.x + 1, point.y - 1));
    }
    if (flash(Point(point.x - 1, point.y))) {
    newFlashes.add(Point(point.x - 1, point.y));
    }
    if (flash(Point(point.x + 1, point.y))) {
    newFlashes.add(Point(point.x + 1, point.y));
    }
    if (flash(Point(point.x - 1, point.y + 1))) {
    newFlashes.add(Point(point.x - 1, point.y + 1));
    }
    if (flash(Point(point.x, point.y + 1))) {
    newFlashes.add(Point(point.x, point.y + 1));
    }
    if (flash(Point(point.x + 1, point.y + 1))) {
    newFlashes.add(Point(point.x + 1, point.y + 1));
    }
    }
    return newFlashes;
    }

    bool flash(Point point) {
    if (point.x < 0 || point.x > 9 || point.y < 0 || point.y > 9) {
    // This is a non-existing point in the matrix
    return false;
    }
    var energy = this[point.y][point.x];
    if (energy == 0) {
    // This point already flashed
    return false;
    }

    if (energy == 9) {
    this[point.y][point.x] = 0;
    return true;
    } else {
    this[point.y][point.x] = energy + 1;
    }
    return false;
    }

    bool allZeroes() => sum() == 0;

    int sum() => fold<int>(0, (sum, row) => sum + row.sum());

    List<Row> toGrid() {
    final result = <Row>[];
    for (int y = 0; y < length; y++) {
    result.add(this[y].toRow());
    }
    return result;
    }
    }

    const squidColors = [
    Color.fromRGBO(255, 255, 255, 1.0),
    Color.fromRGBO(25, 25, 255, 0.5),
    Color.fromRGBO(50, 50, 255, 0.55),
    Color.fromRGBO(75, 75, 255, 0.6),
    Color.fromRGBO(100, 100, 255, 0.65),
    Color.fromRGBO(125, 125, 255, 0.7),
    Color.fromRGBO(150, 150, 255, 0.75),
    Color.fromRGBO(175, 175, 255, 0.8),
    Color.fromRGBO(200, 200, 255, 0.85),
    Color.fromRGBO(225, 225, 255, 0.9),
    ];

    const squidIcons = [
    Icons.flash_on,
    Icons.sentiment_dissatisfied_rounded,
    Icons.sentiment_neutral_rounded,
    Icons.sentiment_satisfied_rounded,
    Icons.sentiment_very_satisfied_rounded,
    ];

    extension MatrixRowExtensions on MatrixRow {
    int sum() => fold<int>(0, (sum, element) => sum + element);

    Row toRow() => Row(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
    ...map((e) {
    return Padding(
    padding: const EdgeInsets.all(3.0),
    child: Icon(
    squidIcons[e~/2],
    color: squidColors[e],
    size: 24.0,
    ),
    );
    }),
    ],
    );
    }

    class Point {
    Point(this.x, this.y);

    int x;
    int y;

    @override
    bool operator ==(Object other) =>
    other is Point && other.x == x && other.y == y;

    @override
    int get hashCode => 31 * x + y;
    }

    class MatrixGrid extends StatelessWidget {
    const MatrixGrid({Key? key, required this.matrix}) : super(key: key);

    final Matrix matrix;

    @override
    Widget build(BuildContext context) {
    return Column(
    children: [...matrix.toGrid()],
    );
    }
    }