timgrossmann

16529337?v=4

timgrossmann
: timgrossmann

About me

Nothing here yet. Update your profile at /profiles/timgrossmann.adoc

Day 00: dart

Hello world for Advent of Code 2019

Dart

This year I want to learn a bit about Dart for future Flutter development.

int main () {
  print("Hello World!");
}

Run the solution with dart helloWorld.dart.

Day 01: rust

this documentation is autogenerated. Add a README.adoc to your solution to take over the control of this :-)

rust

input.txt
103450
107815
53774
124794
90372
98169
106910
50087
104958
71936
118379
122284
55871
91714
120685
117684
146047
60332
72034
127689
117575
101714
121018
86073
73764
100533
104443
113037
79474
123364
128367
63620
54004
124093
133256
95915
97442
64267
70823
143108
86422
118962
66129
69445
51804
56436
117587
64632
104564
67514
108782
123991
110932
122201
98816
126708
69821
66902
96993
55032
109143
67678
58009
50232
69841
101922
95832
122820
72056
102557
68727
85192
74694
142252
140332
53783
123036
88197
148727
138393
87427
65693
88448
51044
95470
97336
121463
91997
149518
66967
119301
112022
57363
128247
107454
77260
126346
97658
137578
134743
Cargo.toml
[package]
name = "fuel_consumption"
version = "0.1.0"
authors = ["Tim Grossmann <contact.timgrossmann@gmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
Cargo.lock
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "fuel_consumption"
version = "0.1.0"
src
Unresolved directive in ../../../../../../day01/rust/timgrossmann/README.adoc - include::src[]

Day 01: dart

Dart

This year I want to learn a bit about Dart for future Flutter development.

There is a sub direcotry for both parts of the challenge.

Unresolved directive in ../../../../../../day01/dart/timgrossmann/README.adoc - include::solution.dart[]

Run the solution with dart solution.dart

Day 01: python

This solution is written in Python. It is the solution for the first day of AoC: The Tyranny of the Rocket Equation

Python Fuel Calculation

def calc_fuel_con (mass):
    return int((mass / 3) - 2)

def calc_fuel_con_iter (mass):
    fuel_sum = 0
    fuel_con = int((mass / 3) - 2)

    while fuel_con > 0:
        fuel_sum += fuel_con
        fuel_con = int((fuel_con / 3) - 2)

    return fuel_sum

with open("input.txt", "r") as fd:
    masses = [int(line.strip()) for line in fd]

    fuel_consum = [calc_fuel_con(mass) for mass in masses]
    fuel_consum_iter = [calc_fuel_con_iter(mass) for mass in masses]

    print(sum(fuel_consum))
    print(sum(fuel_consum_iter))

Day 02: dart

Dart

This year I want to learn a bit about Dart for future Flutter development.

There is a sub direcotry for both parts of the challenge.

Unresolved directive in ../../../../../../day02/dart/timgrossmann/README.adoc - include::solution.dart[]

Run the solution with dart solution.dart

Day 03: dart

Dart

This year I want to learn a bit about Dart for future Flutter development.

There is a sub direcotry for both parts of the challenge.

import 'dart:io';
import 'dart:math';

import 'util/Instruction.dart';
import 'util/util.dart';
import 'util/WirePoint.dart';

int main (List<String> args) {
  File input = new File('input.txt');

  List<List<Instruction>> wires = input
    .readAsStringSync()
    .split("\n")
    .map((wire) => wire.split(","))
    .map((wire) =>
      wire.map((instruct) => parseInstruction(instruct))
      .toList())
    .toList();

  Set<WirePoint> visitedPoints = new Set<WirePoint>();
  Set<WirePoint> intersections = new Set<WirePoint>();

  // for each wire, get all the instructions
  // and get the list of points on the way to the next instruction
  // adding only the points to the intersections that are already in visitedPoints
  // (only take into account x and y and then compare wireNum to not overlap)
  for (int i = 0; i < wires.length; i++) {
    List<Instruction> wire = wires[i];
    WirePoint currPoint = new WirePoint(0, 0, i);

    for (Instruction inst in wire) {
      List<WirePoint> steps = getWirePointSteps(currPoint, inst);

      for (WirePoint step in steps) {
        WirePoint contained = visitedPoints.lookup(step);

        if (contained != null && contained.wireNum != step.wireNum) {
          WirePoint intersection = new WirePoint(step.x, step.y, step.wireNum, step.steps + contained.steps);
          intersections.add(intersection);

          // print('Intersection found: $intersection');
        }

        visitedPoints.add(step);
      }
    }
  }

  // get the element with the shortest manhatten dist from 0, 0
  // start with the minDist of 1000000 to make sure we override
  int minManDist = intersections
    .toList()
    .fold(1000000, (minDist, currIntersect)
      => min(getManhattenDistance(currIntersect.x, 0, currIntersect.y, 0), minDist));

  // get the element with the lowest number of steps
  // start with the minSteps of 1000000 to make sure we override
  int minStepDist = intersections
    .toList()
    .fold(1000000, (minSteps, currIntersect)
      => min(currIntersect.steps , minSteps));

  print('Minimum Distance: $minManDist');
  print('Minimum Steps: $minStepDist');

  return 1;
}

Run the solution with dart solution.dart

Day 04: dart

Dart

This year I want to learn a bit about Dart for future Flutter development.

There is a sub direcotry for both parts of the challenge.

import 'dart:io';

bool checkConditions (int number) {
  String numberStr = number.toString();

  // part01 solution
  // bool duplicate = false;

  Map<int, int> occur = new Map<int, int>();

  // put first value before loop since we start looping
  // at one to allow lookback without additional condition
  occur.putIfAbsent(int.parse(numberStr[0]), () => 1);

  for (int i = 1; i < numberStr.length; i++) {
    int lastNum =  int.parse(numberStr[i - 1]);
    int currNum = int.parse(numberStr[i]);

    if (currNum < lastNum) {
      return false;
    }

    // part01 solution
    /*
    if (currNum == lastNum) {
      duplicate = true;
    }
    */

    if (occur.containsKey(currNum)) {
      occur.update(currNum, (value) => ++value);
    } else {
      occur.putIfAbsent(currNum, () => 1);
    }
  }

  // part01 solution
  // return duplicate;

  return occur
    .entries
    .any((MapEntry mapEntry) => (mapEntry.value == 2));
}

int main (List<String> args) {
  File input = new File('input.txt');

  List<int> range = input
    .readAsStringSync()
    .split("-")
    .map(int.parse)
    .toList();

  List<int> passwords = new List<int>();

  for (int i = range[0]; i <= range[1]; i++) {
    if (checkConditions(i)) {
      passwords.add(i);
    }
  }

  print(passwords.length);

  return 1;
}

Run the solution with dart solution.dart

Day 05: dart

Dart

This year I want to learn a bit about Dart for future Flutter development.

There is a sub direcotry for both parts of the challenge.

import 'dart:io';

List<int> parseOpCodes(int number) {
  String operationDesc = number.toString();
  print(operationDesc);

  int opCodeLength = operationDesc.length > 1 ? 2 : 1;
  int opCode =
      int.parse(operationDesc.substring(operationDesc.length - opCodeLength));

  List<int> paramOpCodes = operationDesc
      .substring(0, operationDesc.length - opCodeLength)
      .split('')
      .map(int.parse)
      .toList()
      .reversed
      .toList();

  List<int> fillZero = List<int>.generate(3 - paramOpCodes.length, (_) => 0);

  print([opCode, ...paramOpCodes, ...fillZero]);
  return [opCode, ...paramOpCodes, ...fillZero];
}

List<int> iterateOpCodes(List<int> intCodes) {
  List<int> output = new List<int>.from(intCodes);

  for (int i = 0; i < output.length;) {
    List<int> opCodes = parseOpCodes(output[i]);

    if (opCodes[0] == 99) {
      break;
    }

    switch (opCodes[0]) {
      case 1:
        int firstInst = opCodes[1];
        int secInst = opCodes[2];

        int firstParam = firstInst == 0 ? output[output[i + 1]] : output[i + 1];
        int secParam = secInst == 0 ? output[output[i + 2]] : output[i + 2];
        int outPos = output[i + 3];

        output[outPos] = firstParam + secParam;
        i += 4;
        print('Addition called: $firstParam + $secParam to $outPos');
        break;

      case 2:
        int firstInst = opCodes[1];
        int secInst = opCodes[2];

        int firstParam = firstInst == 0 ? output[output[i + 1]] : output[i + 1];
        int secParam = secInst == 0 ? output[output[i + 2]] : output[i + 2];
        int outPos = output[i + 3];

        output[outPos] = firstParam * secParam;
        i += 4;
        print('Multiplication called: $firstParam * $secParam to $outPos');
        break;

      case 3:
        int firstParam = output[i + 1];
        print('Please enter the System ID to run the test on:');
        int userIn = int.parse(stdin.readLineSync());

        output[firstParam] = userIn;
        i += 2;
        print('Storing called: $userIn in $firstParam');
        break;

      case 4:
        int firstInst = opCodes[1];
        int firstParam = firstInst == 0 ? output[output[i + 1]] : output[i + 1];

        i += 2;
        print('Printing called: $firstParam');
        break;

      case 5:
        int firstInst = opCodes[1];
        int secInst = opCodes[2];

        int firstParam = firstInst == 0 ? output[output[i + 1]] : output[i + 1];
        int secParam = secInst == 0 ? output[output[i + 2]] : output[i + 2];
        bool doJump = firstParam != 0;

        i = doJump ? secParam : i + 3;
        print('Jump if True: $firstParam is $doJump, $secParam');
        break;

      case 6:
        int firstInst = opCodes[1];
        int secInst = opCodes[2];

        int firstParam = firstInst == 0 ? output[output[i + 1]] : output[i + 1];
        int secParam = secInst == 0 ? output[output[i + 2]] : output[i + 2];
        bool doJump = firstParam == 0;

        i = doJump ? secParam : i + 3;
        print('Jump if False: $firstParam is $doJump, $secParam');
        break;

      case 7:
        int firstInst = opCodes[1];
        int secInst = opCodes[2];

        int firstParam = firstInst == 0 ? output[output[i + 1]] : output[i + 1];
        int secParam = secInst == 0 ? output[output[i + 2]] : output[i + 2];
        int out = output[i + 3];

        output[out] = firstParam < secParam ? 1 : 0;
        print('Store 1 if less else 0: $firstParam < $secParam, ${output[out]}');
        i += 4;
        break;

      case 8:
        int firstInst = opCodes[1];
        int secInst = opCodes[2];

        int firstParam = firstInst == 0 ? output[output[i + 1]] : output[i + 1];
        int secParam = secInst == 0 ? output[output[i + 2]] : output[i + 2];
        int out = output[i + 3];

        output[out] = firstParam == secParam ? 1 : 0;
        print('Store 1 if equal else 0: $firstParam = $secParam, ${output[out]}');
        i += 4;
        break;
      default:
        throw new UnsupportedError(
            "This opcode is not yet supported! ${opCodes[0]}");
    }

    print('');
  }

  return output;
}

int main(List<String> args) {
  File input = new File('./input.txt');

  List<int> intCodes =
      input.readAsStringSync().split(",").map(int.parse).toList();

  List<int> output = iterateOpCodes(intCodes);

  print(output);

  return 1;
}

Run the solution with dart solution.dart

Day 06: dart

Dart

This year I want to learn a bit about Dart for future Flutter development.

There is a sub direcotry for both parts of the challenge.

Unresolved directive in ../../../../../../day06/dart/timgrossmann/README.adoc - include::solution.dart[]

Run the solution with dart solution.dart

Day 07: dart

Dart

This year I want to learn a bit about Dart for future Flutter development.

There is a sub direcotry for both parts of the challenge.

Unresolved directive in ../../../../../../day07/dart/timgrossmann/README.adoc - include::solution.dart[]

Run the solution with dart solution.dart

Day 08: dart

Dart

This year I want to learn a bit about Dart for future Flutter development.

There is a sub direcotry for both parts of the challenge.

import 'dart:io';

class LayerImage {
  List<List<int>> image;

  LayerImage();

  void applyLayer(List<List<int>> layer) {
    if (image == null) {
      image = layer;
      return;
    }

    for (int row = 0; row < layer.length; row++) {
      for (int val = 0; val < layer[row].length; val++) {
        if (image[row][val] == 2) {
          image[row][val] = layer[row][val];
        }
      }
    }
  }

  @override
  String toString() {
    String out = '';
    for (List<int> row in image) {
      out += '$row\n';
    }
    return out;
  }
}

class Layer {
  List<List<int>> rows;
  Map<int, int> numOccurences = {};

  Layer(this.rows) {
    numOccurences.putIfAbsent(0, () => getNumOf(0));
    numOccurences.putIfAbsent(1, () => getNumOf(1));
    numOccurences.putIfAbsent(2, () => getNumOf(2));
  }

  int getNumOf(int searchNum) {
    return rows.fold(0, (accu, row) {
      return accu +
          row.fold(0, (accu, val) => val == searchNum ? ++accu : accu);
    });
  }

  @override
  String toString() {
    return '$rows';
  }
}

List<Layer> parseInputToLayers(String input, {int width, int height}) {
  List<Layer> layers = [];
  print('$width, $height');

  List<List<int>> currLayerRows = [];
  List<int> currRow = [];
  for (int i = 0; i < input.length + 0; i++) {
    currRow.add(int.parse(input[i]));

    // create a new row
    if (currRow.length % width == 0) {
      currLayerRows.add(currRow);
      currRow = [];
    }

    // create a new layer when we reached m rows with n elememnts
    if ((i + 1) % (width * height) == 0) {
      layers.add(Layer(currLayerRows));
      currLayerRows = [];
    }
  }

  return layers;
}

int main(List<String> args) {
  String input = new File('./input.txt').readAsStringSync();
  int width = 25;
  int height = 6;

  List<Layer> layers = parseInputToLayers(input, width: width, height: height);

  // part 1
  Layer fewestZeroLayer = layers[0];
  int fewestZeroes = layers[0].numOccurences[0];

  for (Layer layer in layers) {
    if (layer.numOccurences[0] < fewestZeroes) {
      fewestZeroes = layer.numOccurences[0];
      fewestZeroLayer = layer;
    }
  }

  print(fewestZeroLayer.numOccurences[1] * fewestZeroLayer.numOccurences[2]);

  // Part2
  LayerImage layerImage = LayerImage();
  for (Layer layer in layers) {
    layerImage.applyLayer(layer.rows);
  }

  print(layerImage);

  return 1;
}

Run the solution with dart solution.dart

Day 09: dart

Dart

This year I want to learn a bit about Dart for future Flutter development.

There is a sub direcotry for both parts of the challenge.

import 'dart:io';

import './util/helper_classes.dart';
import 'util/util.dart';

int getParamWithInst(
    int inst, int index, int offset, int base, CustomList intCodes) {
  print('Inst: $inst, Index: $index, Offset: $offset, Base: $base');

  switch (inst) {
    // positioned mode
    case 0:
      return intCodes[index + offset];
      break;

    // immediate mode
    case 1:
      return index + offset;
      break;

    // positioned mode with base shift
    case 2:
      return intCodes[index + offset] + base;
      break;

    default:
      throw new UnsupportedError('Unsupported paramCode $inst');
  }
}

int iterateOpCodes(Amplifier currAmp) {
  CustomList intCodes = currAmp.instructions;

  for (int i = currAmp.pointer; i < intCodes.instructions.length;) {
    List<int> opCodes = parseOpCodes(intCodes[i]);
    // print(intCodes.instructions);

    if (opCodes[0] == 99) {
      currAmp.pointer = i;
      break;
    }

    int firstInst = opCodes[1];
    int secInst = opCodes[2];
    int thirdInst = opCodes[3];

    int firstParam =
        getParamWithInst(firstInst, i, 1, currAmp.relativeBase, intCodes);
    int secParam =
        getParamWithInst(secInst, i, 2, currAmp.relativeBase, intCodes);
    int outPos =
        getParamWithInst(thirdInst, i, 3, currAmp.relativeBase, intCodes);


    switch (opCodes[0]) {
      case 1:
        intCodes[outPos] = intCodes[firstParam] + intCodes[secParam];
        i += 4;
        print('Addition called: ${intCodes[firstParam]} + ${intCodes[secParam]} to $outPos');
        break;

      case 2:
        intCodes[outPos] = intCodes[firstParam] * intCodes[secParam];
        i += 4;
        print('Multiplication called: ${intCodes[firstParam]} * ${intCodes[secParam]} to $outPos');
        break;

      case 3:
        print('Please enter the System ID to run the test on:');
        int userIn = int.parse(stdin.readLineSync());

        intCodes[firstParam] = userIn;
        i += 2;
        print('Storing called: $userIn in ${firstParam}');
        break;

      case 4:
        i += 2;
        print('Printing called: ${intCodes[firstParam]}');
        currAmp.pointer = i;
        break;

      case 5:
        bool doJump = intCodes[firstParam] != 0;

        i = doJump ? intCodes[secParam] : i + 3;
        print('Jump if True: ${intCodes[firstParam]} is $doJump, ${intCodes[secParam]}');
        break;

      case 6:
        bool doJump = intCodes[firstParam] == 0;

        i = doJump ? intCodes[secParam] : i + 3;
        print('Jump if False: ${intCodes[firstParam]} is $doJump, ${intCodes[secParam]}');
        break;

      case 7:
        intCodes[outPos] = intCodes[firstParam] < intCodes[secParam] ? 1 : 0;
        print(
            'Store 1 if less else 0: ${intCodes[firstParam]} < ${intCodes[secParam]}, ${intCodes[outPos]} in in $outPos');
        i += 4;
        break;

      case 8:
        intCodes[outPos] = intCodes[firstParam] == intCodes[secParam] ? 1 : 0;
        print(
            'Store 1 if equal else 0: ${intCodes[firstParam]} = ${intCodes[secParam]}, ${intCodes[outPos]} in $outPos');
        i += 4;
        break;

      case 9:
        currAmp.relativeBase += intCodes[firstParam];
        print(
            'Adjusting relative base of Amplifier $currAmp by ${intCodes[firstParam]} to ${currAmp.relativeBase}');
        i += 2;
        break;

      default:
        throw new UnsupportedError(
            "This opcode is not yet supported! ${opCodes[0]}");
    }

    print('');
  }

  return -1;
}

int main(List<String> args) {
  File input = new File('./input.txt');

  List<int> intCodes =
      input.readAsStringSync().split(",").map(int.parse).toList();

  Amplifier amplifier = Amplifier(CustomList(List<int>.of(intCodes)));

  iterateOpCodes(amplifier);
  return 1;
}

Run the solution with dart solution.dart

Day 10: dart

Dart

This year I want to learn a bit about Dart for future Flutter development.

There is a sub direcotry for both parts of the challenge.

import 'dart:io';

import 'util/classes/Asteroid.dart';
import 'util/classes/Laser.dart';
import 'util/util.dart';

Asteroid getBestSightAsteroid(List<Asteroid> asteroids) {
  Asteroid bestAsteroid = asteroids[0];

  for (Asteroid asteroid in asteroids) {
    int numOfDetectedAsteroids =
        getAsteroidsInSight(asteroids, asteroid).length;

    if (numOfDetectedAsteroids > bestAsteroid.numOfVisibleAsteroids) {
      bestAsteroid = asteroid;
    }
  }

  return bestAsteroid;
}

Asteroid getAsteroidEvaporatedAt(
    List<Asteroid> asteroids, Asteroid bestBase, int evaporatedAt) {
  Set<Asteroid> toBeEvaporated = Set<Asteroid>.of(asteroids)
      .where((Asteroid asteroid) => asteroid != bestBase)
      .toSet();

  // start pointing up
  Laser laser = Laser();
  int evaporated = 0;

  while (true) {
    Map<Asteroid, double> asteroidsInDirection =
        getasteroidsInDirection(toBeEvaporated, bestBase, laser.direction);

    if (asteroidsInDirection.length > 0) {
      // print(asteroidsInDirection);

      Asteroid closestInDirection = asteroidsInDirection.keys.toList()[0];

      asteroidsInDirection.forEach((Asteroid asteroid, double distance) => {
            if (distance < asteroidsInDirection[closestInDirection])
              {closestInDirection = asteroid}
          });

      // if we reached the requested asteroid number
      if (evaporated == (evaporatedAt - 1)) {
        print('Found Asterioid for position $evaporatedAt: $closestInDirection');
        return closestInDirection;
      }

      // print('Evaporating: $closestInDirection');
      toBeEvaporated.remove(closestInDirection);
      evaporated++;
    }

    // move the laser
    laser.roateStep();
  }
}

int main(List<String> args) {
  File input = new File('./input.txt');

  List<List<String>> asteroidsMap = input
      .readAsStringSync()
      .split("\n")
      .map((String line) => line.split(''))
      .toList();

  List<Asteroid> asteroids = [];

  for (int i = 0; i < asteroidsMap.length; i++) {
    for (int j = 0; j < asteroidsMap[i].length; j++) {
      if (asteroidsMap[i][j] == '#') {
        asteroids.add(Asteroid(i, j));
      }
    }
  }

  printAsGrid(asteroidsMap);

  Asteroid bestBase = getBestSightAsteroid(asteroids);
  print('Best Base $bestBase');

  Asteroid evaporate200 = getAsteroidEvaporatedAt(asteroids, bestBase, 200);
  // print('Asteroid at 200: $evaporate200');
  print('Asteroid value: ${evaporate200.y * 100 + evaporate200.x}');

  return 1;
}

Run the solution with dart solution.dart

Day 12: dart

Dart

This year I want to learn a bit about Dart for future Flutter development.

There is a sub direcotry for both parts of the challenge.

import 'dart:io';

class Vector3 {
  int x;
  int y;
  int z;

  Vector3(this.x, this.y, this.z);

  Vector3 operator +(Vector3 o) {
    return Vector3(this.x + o.x, this.y + o.y, this.z + o.z);
  }

  @override
  String toString() {
    return '$x, $y, $z';
  }

  bool operator ==(o) {
    return (this.x == o.x) && (this.y == o.y) && (this.z == o.z);
  }

  @override
  int get hashCode => x * 1000000 + y * 10000 + z;
}

class Planet {
  Vector3 position;
  Vector3 velocity = Vector3(0, 0, 0);

  Planet(this.position);

  @override
  String toString() {
    return '(${position.x}, ${position.y}, ${position.z}) - (${velocity.x}, ${velocity.y}, ${velocity.z})';
  }

  bool operator ==(o) {
    bool positionEqual = this.position == o.position;
    bool velocityEqual = this.velocity == o.velocity;

    return (positionEqual && velocityEqual);
  }

  @override
  int get hashCode => position.hashCode * 10000 + velocity.hashCode;

  Vector3 getPlanetGravity(Planet v) {
    int x =
        (position.x > v.position.x) ? -1 : (position.x == v.position.x) ? 0 : 1;

    int y =
        (position.y > v.position.y) ? -1 : (position.y == v.position.y) ? 0 : 1;

    int z =
        (position.z > v.position.z) ? -1 : (position.z == v.position.z) ? 0 : 1;

    return Vector3(x, y, z);
  }

  int get totalEnergy {
    return (position.x.abs() + position.y.abs() + position.z.abs()) *
        (velocity.x.abs() + velocity.y.abs() + velocity.z.abs());
  }
}

/*
<x=13, y=9, z=5>
<x=8, y=14, z=-2>
<x=-5, y=4, z=11>
<x=2, y=-6, z=1>
*/
Vector3 parsePosition(String position) {
  RegExp regExp = new RegExp(
    r'.=([-]*\d+)',
    caseSensitive: false,
    multiLine: false,
  );

  List<int> values = regExp
      .allMatches(position)
      .map((match) => int.parse(match.group(1)))
      .toList();

  return Vector3(values[0], values[1], values[2]);
}

void applyGravity(List<Planet> planets) {
  for (Planet planetOut in planets) {
    for (Planet planetIn in planets) {
      if (!identical(planetOut, planetIn)) {
        Vector3 outPlanetGravity = planetOut.getPlanetGravity(planetIn);

        planetOut.velocity += outPlanetGravity;
      }
    }
  }

  for (Planet planet in planets) {
    planet.position += planet.velocity;
  }
}

int main(List<String> args) {
  File input = new File('./input.txt');

  List<Planet> planets = input
      .readAsStringSync()
      .split("\n")
      .map(parsePosition)
      .map((Vector3 position) => Planet(position))
      .toList();

  print(planets);

  for (int i = 0; i < 1000; i++) {
    applyGravity(planets);
  }

  print('Part 1');
  print(planets);
  print(planets
      .map((Planet planet) => planet.totalEnergy)
      .reduce((a, b) => a + b));
  print('');

  // re-reading for fresh planets
  planets = input
      .readAsStringSync()
      .split("\n")
      .map(parsePosition)
      .map((Vector3 position) => Planet(position))
      .toList();

  int i = 0;
  List<List<Planet>> seenStates = List<List<Planet>>();
  seenStates.add(planets);
  Map<String, int> cycles = Map<String, int>();

  print('Part 2');
  print(seenStates);

  while (true) {
    i++;
    List<Planet> nextState = List<Planet>.of(planets).map(copyPlanet).toList();

    applyGravity(nextState);

    bool isXCycle = checkCycle('x', nextState, seenStates);
    bool isYCycle = checkCycle('y', nextState, seenStates);
    bool isZCycle = checkCycle('z', nextState, seenStates);

    if (isXCycle) {
      print('Found x cycle after $i');
      cycles.putIfAbsent('x', () => i);
    }

    if (isYCycle) {
      print('Found y cycle after $i');
      cycles.putIfAbsent('y', () => i);
    }

    if (isZCycle) {
      print('Found z cycle after $i');
      cycles.putIfAbsent('z', () => i);
    }

    if (cycles.containsKey('x') &&
        cycles.containsKey('y') &&
        cycles.containsKey('z')) {
      break;
    }

    seenStates.add(nextState);
    planets = nextState;
  }

  int gdcXY = (cycles['x'] * cycles['y'] ~/ cycles['x'].gcd(cycles['y']));
  int gdcAll = (gdcXY * cycles['z'] ~/ gdcXY.gcd(cycles['z']));
  print(cycles);
  print(gdcAll);

  return 1;
}

bool checkCycle(
    String val, List<Planet> nextState, List<List<Planet>> seenStates) {
  for (List<Planet> states in seenStates) {
    int systemEquals = 0;

    for (int i = 0; i < states.length; i++) {
      Planet planet = nextState[i];
      Planet comparePlanet = states[i];

      switch (val) {
        case 'x':
          if ((planet.position.x == comparePlanet.position.x) &&
              (planet.velocity.x == comparePlanet.velocity.x)) {
            systemEquals++;
          }

          break;

        case 'y':
          if ((planet.position.y == comparePlanet.position.y) &&
              (planet.velocity.y == comparePlanet.velocity.y)) {
            systemEquals++;
          }

          break;

        case 'z':
          if ((planet.position.z == comparePlanet.position.z) &&
              (planet.velocity.z == comparePlanet.velocity.z)) {
            systemEquals++;
          }

          break;
        default:
          break;
      }
    }
    if (systemEquals == 4) {
      return true;
    }
  }

  return false;
}

Planet copyPlanet(Planet planet) {
  Vector3 pos =
      Vector3(planet.position.x, planet.position.y, planet.position.z);
  Vector3 veloc =
      Vector3(planet.velocity.x, planet.velocity.y, planet.velocity.z);

  Planet copied = Planet(pos);
  copied.velocity = veloc;

  return copied;
}

Run the solution with dart solution.dart