import 'package:aoc2020/model/point.dart'; import 'package:tuple/tuple.dart'; enum Direction { N, NE, E, SE, S, SW, W, NW } class Dir { static int get dirs => Direction.values.length; static int get dirStep => 360 ~/ dirs; static List get dirEnum => Direction.values; static List get dir => Direction.values.map((dir) => dir.toString().substring(dir.toString().indexOf('.') + 1)).toList(); static String string(Direction dir) => dir.toString().substring(dir.toString().indexOf('.') + 1); static Direction stringToEnum(String str) => dirEnum[dir.indexOf(str)]; } class Pos { static final Pos _singleton = Pos._internal(); Point _loc; Point _waypoint; Direction _dir; Map moveOffset = { Direction.N: Point(-1, 0), Direction.NE: Point(-1, 1), Direction.E: Point(0, 1), Direction.SE: Point(1, 1), Direction.S: Point(1, 0), Direction.SW: Point(1, -1), Direction.W: Point(0, -1), Direction.NW: Point(-1, -1), }; // factory Pos({Point loc, Direction dir}) { // _singleton.loc = loc; // _singleton.dir = dir; // return _singleton; // } factory Pos() { return _singleton; } // singleton's constructor Pos._internal() { reset(); } void reset() { _loc = Point(0, 0); _waypoint = Point(-1, 10); // relative to _loc _dir = Direction.E; } int get ns => _loc.item1; int get ew => _loc.item2; void move(Tuple2 _move) { var _direction = (_move.item1 == 'F') ? _dir : Dir.stringToEnum(_move.item1); _loc += (moveOffset[_direction] * _move.item2); } void moveSec2(Tuple2 _move) { if (_move.item1 == 'F') { _loc += (_waypoint * _move.item2); } else { _waypoint += (moveOffset[Dir.stringToEnum(_move.item1)] * _move.item2); } } void rotate(Tuple2 _rotate) { switch (_rotate.item1) { case 'L': left(deg: _rotate.item2); break; case 'R': right(deg: _rotate.item2); break; default: print('ERROR'); } } void rotateSec2(Tuple2 _rotate) { var _deg = _rotate.item2 % 360; if (_rotate.item1 == 'L') _deg = 360 - _deg; switch (_deg) { case 90: _waypoint = Point(_waypoint.item2, -_waypoint.item1); break; case 180: _waypoint = Point(-_waypoint.item1, -_waypoint.item2); break; case 270: _waypoint = Point(-_waypoint.item2, _waypoint.item1); break; } } void _rotateDeg(int deg) { var count = (deg ~/ Dir.dirStep) % Dir.dirs; var _newDirIndex = Dir.dirEnum.indexOf(_dir) + count; _newDirIndex = _newDirIndex < 0 ? Dir.dirs - count : _newDirIndex; _newDirIndex %= Dir.dirs; _dir = Dir.dirEnum[_newDirIndex]; } void left({int deg = 90}) => _rotateDeg(-deg); void right({int deg = 90}) => _rotateDeg(deg); @override String toString() => '{$_loc:$_dir} $_waypoint'; }