p0090_s0.py

problem 90 · 44 lines

#!/usr/bin/env python3.14
# -*- coding: utf-8 -*-
""" Solution to Euler Problem 90: Cube Digit Pairs [Level 9]. """
from __future__ import annotations

import itertools

from solver.runners import runner


@runner.main
def solve(*args: str) -> str:
    """Brute-force over all unordered pairs of the C(10,6)=210 six-digit cubes; O(210^2 * 9)."""
    squares: list[tuple[int, int]] = [(int((i_sq := f"{i * i:02d}")[0]), int(i_sq[1])) for i in range(1, 10)]

    def can_display(cube_digits: tuple[int, ...], digit: int) -> bool:
        """True if the cube shows the digit, treating 6 and 9 as interchangeable via the flip rule."""
        return digit in cube_digits or (digit in [6, 9] and (6 in cube_digits or 9 in cube_digits))

    def can_pair_display_all(cube1: tuple[int, ...], cube2: tuple[int, ...]) -> bool:
        """True if every square's two digits can be shown, with either cube supplying the tens digit."""
        for first_digit, second_digit in squares:
            if not (
                can_display(cube1, first_digit)
                and can_display(cube2, second_digit)
                or (can_display(cube1, second_digit) and can_display(cube2, first_digit))
            ):
                return False
        return True

    all_cubes: list[tuple[int, ...]] = list(itertools.combinations(range(10), 6))
    cube_count: int = len(all_cubes)
    valid_arrangements: int = 0
    # Triangular iteration (j from i) counts each unordered pair once and admits self-pairs.
    for i in range(cube_count):
        for j in range(i, cube_count):
            if can_pair_display_all(all_cubes[i], all_cubes[j]):
                valid_arrangements += 1
    return str(valid_arrangements)


if __name__ == "__main__":
    raise SystemExit(solve())