text: import { readInput } from "@util";
  
  export async function main() {
    const inputPath = `${__dirname}/input`;
    let wires = await readInput(inputPath, "\n");
  
    wires = wires.map(wire =>
      wire.split`,`.map(path => ({
        direction: path.charAt(0),
        length: Number(path.substring(1, path.length))
      }))
    );
  
    const matrix = new Matrix();
  
    wires.forEach(wire => {
      wire.forEach(path => {
        switch (path.direction) {
          case DIRECTION.UP:
            matrix.goUp(path.length);
            break;
  
          case DIRECTION.DOWN:
            matrix.goDown(path.length);
            break;
  
          case DIRECTION.RIGHT:
            matrix.goRight(path.length);
            break;
  
          case DIRECTION.LEFT:
            matrix.goLeft(path.length);
            break;
  
          default:
            throw new Error(`Unexpected path ${path}`);
        }
      });
  
      matrix.newState();
    });
  
    /* Part 1 */
    // console.log(matrix.minDistance);
  
    console.log(matrix.minCrossedStep);
  }
  
  const DIRECTION = {
    UP: "U",
    DOWN: "D",
    RIGHT: "R",
    LEFT: "L"
  };
  
  class Matrix {
    _id = "0";
    _count = 0;
    _current = {
      x: 0,
      y: 0
    };
    _data = {};
    _visited = {};
  
    /* Part 1 */
    // minDistance = Number.MAX_SAFE_INTEGER;
  
    minCrossedStep = Number.MAX_SAFE_INTEGER;
  
    initValue(x, y) {
      if (!this._data[x]) {
        this._data[x] = {};
        this._visited[x] = {};
      }
  
      if (!this._data[x][y]) {
        this._data[x][y] = 0;
        this._visited[x][y] = "";
      }
    }
  
    getValue(x, y) {
      this.initValue(x, y);
      return this._data[x][y];
    }
  
    setValue(x, y, value) {
      this.initValue(x, y);
      this._data[x][y] = value;
      this._visited[x][y] += this._id;
  
      /* Part 1 */
      // const distance = Math.abs(x) + Math.abs(y);
      // if (this.isCrossed(x, y) && distance < this.minDistance) {
      //   this.minDistance = distance;
      // }
  
      if (this.isCrossed(x, y) && this._data[x][y] < this.minCrossedStep) {
        this.minCrossedStep = this._data[x][y];
      }
    }
  
    isCrossed(x, y) {
      this.initValue(x, y);
      return this._visited[x][y].length > 1;
    }
  
    addValue(x, y, value) {
      this.initValue(x, y);
      this.setValue(x, y, this._data[x][y] + value);
    }
  
    newState() {
      this._id++;
      this._count = 0;
      this._current = {
        x: 0,
        y: 0
      };
    }
  
    isVisited(x, y) {
      this.initValue(x, y);
      return this._visited[x][y].indexOf(this._id) >= 0;
    }
  
    goUp(n) {
      for (let i = this._current.y + 1; i <= this._current.y + n; i++) {
        const x = this._current.x;
        const y = i;
        const value = ++this._count;
  
        if (!this.isVisited(x, y)) {
          this.addValue(x, y, value);
        }
      }
      this._current.y += n;
    }
  
    goDown(n) {
      for (let i = this._current.y - 1; i >= this._current.y - n; i--) {
        const x = this._current.x;
        const y = i;
        const value = ++this._count;
  
        if (!this.isVisited(x, y)) {
          this.addValue(x, y, value);
        }
      }
      this._current.y -= n;
    }
  
    goRight(n) {
      for (let i = this._current.x + 1; i <= this._current.x + n; i++) {
        const x = i;
        const y = this._current.y;
        const value = ++this._count;
  
        if (!this.isVisited(x, y)) {
          this.addValue(x, y, value);
        }
      }
      this._current.x += n;
    }
  
    goLeft(n) {
      for (let i = this._current.x - 1; i >= this._current.x - n; i--) {
        const x = i;
        const y = this._current.y;
        const value = ++this._count;
  
        if (!this.isVisited(x, y)) {
          this.addValue(x, y, value);
        }
      }
      this._current.x -= n;
    }
  }
  