DEV Community

Discussion on: Daily Challenge #79 - Connect Four

Collapse
 
willsmart profile image
willsmart • Edited

One in TypeScript that tracks "groups" of connected pieces so all it needs to do is check for when a group grows to 4 pieces
I feel the code ended up overly complex for the problem, but at least it prints the board prettily ¯_(ツ)_/¯

const pieces_position_list = [
  "C_Yellow",
  "E_Red",
  "G_Yellow",
  "B_Red",
  "D_Yellow",
  "B_Red",
  "B_Yellow",
  "G_Red",
  "C_Yellow",
  "C_Red",
  "D_Yellow",
  "F_Red",
  "E_Yellow",
  "A_Red",
  "A_Yellow",
  "G_Red",
  "A_Yellow",
  "F_Red",
  "F_Yellow",
  "D_Red",
  "B_Yellow",
  "E_Red",
  "D_Yellow",
  "A_Red",
  "G_Yellow",
  "D_Red",
  "D_Yellow",
  "C_Red",
];

type Group = { count: number; overriddenBy?: Group };

type Piece = {
  color: string;
  groups: { [groupKey: string]: Group };
};

type Neighbour = {
  x: number;
  y: number;
  groupKey: string;
};

const preceedingNeighbours: Neighbour[] = [
  {
    x: -1,
    y: 0,
    groupKey: "-",
  },
  {
    x: -1,
    y: -1,
    groupKey: "\\",
  },
  {
    x: 0,
    y: -1,
    groupKey: "|",
  },
  {
    x: 1,
    y: -1,
    groupKey: "/",
  },
];

function whoIsWinner(piecesPositionList: string[]): string {
  const columns: Piece[][] = [];

  return (
    piecesPositionList.find(pieceString =>
      addPiece(pieceString.charCodeAt(0) - "A".charCodeAt(0), pieceString.substring(2))
    ) || "__Draw"
  ).substring(2);

  function addPieceToGroup(group: Group | undefined): number {
    if (group === undefined) return 0;
    if (group.overriddenBy !== undefined) return addPieceToGroup(group.overriddenBy);
    else group.count++;
    return group.count;
  }

  function pieceAt(columnIndex: number, rowIndex: number): Piece | undefined {
    return columns[columnIndex] ? columns[columnIndex][rowIndex] : undefined;
  }

  function addPiece(columnIndex: number, color: string) {
    const column = columns[columnIndex] || (columns[columnIndex] = []),
      rowIndex = column.length,
      piece: Piece = {
        color,
        groups: {},
      };
    column.push(piece);
    for (const { x, y, groupKey } of preceedingNeighbours) {
      const preceedingNeighbour = pieceAt(columnIndex + x, rowIndex + y);
      const proceedingNeighbour = pieceAt(columnIndex - x, rowIndex - y);
      const preceedingNeighbourGroup =
        preceedingNeighbour && preceedingNeighbour.color === color && preceedingNeighbour.groups[groupKey];
      let proceedingNeighbourGroup =
        proceedingNeighbour && proceedingNeighbour.color === color && proceedingNeighbour.groups[groupKey];

      const group = (piece.groups[groupKey] = preceedingNeighbourGroup ||
        proceedingNeighbourGroup || {
          count: 0,
          overriddenBy: undefined,
        });
      if (preceedingNeighbourGroup && proceedingNeighbourGroup) {
        // If we have groups on both sides, merge the proceeding one (eg the one to the right) into the preceeding one
        // This is done by setting the proceeding group's `overriddenBy` reference
        while (proceedingNeighbourGroup.overriddenBy) proceedingNeighbourGroup = proceedingNeighbourGroup.overriddenBy;
        group.count += proceedingNeighbourGroup.count;
        proceedingNeighbourGroup.overriddenBy = group;
      }

      if (group && addPieceToGroup(group) >= 4) {
        logBoard();
        return color;
      }
    }
    return undefined;
  }

  function logBoard(): void {
    const rowDivider = "-".repeat(1 + 7 * 9) + "\n";
    let s = rowDivider;
    for (let rowIndex = 5; rowIndex >= 0; rowIndex--) {
      for (let columnIndex = 0; columnIndex < 7; columnIndex++) {
        const piece = pieceAt(columnIndex, rowIndex);
        if (!piece) s += "|        ";
        else
          s += `| ${piece.color.substring(0, 1)} ${["-", "\\", "|", "/"].reduce(
            (acc, groupKey) => acc + groupCountString(piece.groups[groupKey]),
            ""
          )} `;
      }
      s += "|\n" + rowDivider;
    }
    console.log(s);

    function groupCountString(group: Group): string {
      if (group === undefined) return " ";
      if (group.overriddenBy !== undefined) return groupCountString(group.overriddenBy);
      else return String(group.count);
    }
  }
}

console.log(whoIsWinner(pieces_position_list));

->

----------------------------------------------------------------
|        |        |        |        |        |        |        |
----------------------------------------------------------------
|        |        |        |        |        |        |        |
----------------------------------------------------------------
| R 1111 | Y 1221 |        | Y 1111 |        |        | Y 14   |
----------------------------------------------------------------
| Y 2221 | Y 2223 | R 3311 | R 3111 | R 3112 | Y 1411 | R 1321 |
----------------------------------------------------------------
| Y 1221 | R 1321 | Y 3123 | Y 3221 | Y 3411 | R 2322 | R 2221 |
----------------------------------------------------------------
| R 2311 | R 2121 | Y 2221 | Y 2423 | R 2311 | R 2221 | Y 1111 |
----------------------------------------------------------------

Yellow