Решение ребуса: гол * гол = футбол

1 минут

Попросили меня решить ребус вида гол * гол = футбол. Написал решение на C. Зачем это здесь? Просто я давно ничего не постил в блог, надо немного освежить содержимое. Ну и это может быть полезным для тех, кто ещё только изучает C :). Код прокомментирован на русском языке.

Обновлено 20.09.2025: исправлено решение на C и добавлено решение на Rust.

Решение на C:

/*

    Решение маски abc * abc = defbc (ребус: гол * гол = футбол)

*/

#include <stdio.h>
#include <math.h>

#define SIZE_A  3
#define SIZE_B  6

int main()
{
    int num = 0, i, j, n, a[SIZE_A], b[SIZE_B];

    for (n = 100; n <= 999; n++) {
        num = n;

        // записываем цифры числа num в массив
        a[0] = num % 10;
        a[1] = num / 10 % 10;
        a[2] = num / 100 % 10;

        // проверяем эквивалентность цифр в числе a
        if (a[0] == a[1] || a[0] == a[2] || a[1] == a[2]) {
            continue;
        }

        num *= num;

        if (num > 999999) {
            continue;
        }
        // записываем цифры числа num в массив
        b[0] = num % 10;
        b[1] = num / 10 % 10;

        // проверяем идентичность двух последних цифр в числе
        if (b[0] != a[0] || b[1] != a[1]) {
            continue;
        }
        b[2] = num / 100 % 10;
        b[3] = num / 1000 % 10;
        b[4] = num / 10000 % 10;
        b[5] = num / 100000 % 10;

        // проверяем эквивалентность цифр в числе b
        for (i = 0; i < SIZE_B; i++) {
            for (j = i+1; j < SIZE_B; j++) {
                // если нашлись какие-нибудь одинаковые значения, то прерываем цикл
                if (b[i] == b[j]) {
                    num = 0;
                    break;
                }
            }
        }

        // проверяем эквивалентность цифр в числах a и b
        for (i = 0; i < SIZE_A; i++) {
            for (j = 0; j < SIZE_B; j++) {
                // игнорируем значения, которые должны быть равными
                if ((i == 0 && j == 0) || (i == 1 && j == 1)) {
                    continue;
                }

                // если нашлись какие-нибудь одинаковые значения, то прерываем цикл
                if (a[i] == b[j]) {
                    num = 0;
                    break;
                }
            }
        }

        // вывод результата
        if (num != 0) {
            num = sqrt(num);
            printf("%d * %d = %d\n", num, num, num*num);
        }
    }
    return 0;
}

Решение на Rust:

use std::collections::HashSet;

const VALUE_DIGITS: u32 = 3;
const VALUE_FROM: u32 = (10_u32).pow(VALUE_DIGITS - 1);
const VALUE_TO: u32 = (10_u32).pow(VALUE_DIGITS);

const RESULT_DIGITS: u32 = 6;
const RESULT_FROM: u32 = (10_u32).pow(RESULT_DIGITS - 1);
const RESULT_TO: u32 = (10_u32).pow(RESULT_DIGITS);

fn main() {
    for value in VALUE_FROM..VALUE_TO {
        if is_valid_gol_value(value) {
            println!("{} * {} = {}", value, value, value * value);
        }
    }
}

fn is_valid_gol_value(value: u32) -> bool {
    let result = value * value;
    if !(RESULT_FROM..RESULT_TO).contains(&result) {
        return false;
    }

    let value_arr = make_digits_vec(value, VALUE_DIGITS);
    if !is_only_uniq_values(&value_arr) {
        return false;
    }

    let result_arr = make_digits_vec(result, RESULT_DIGITS);
    if !is_only_uniq_values(&result_arr) {
        return false;
    }

    let value_index = value_arr.len() - 2;
    let result_index = result_arr.len() - 2;

    if !value_arr[value_index..].eq(&result_arr[result_index..]) {
        return false;
    }

    value_arr[..value_index]
        .iter()
        .any(|v| !result_arr[..result_index].contains(v))
}

fn make_digits_vec(value: u32, digits: u32) -> Vec<u32> {
    (0..digits)
        .rev()
        .map(|v| value / 10_u32.pow(v) % 10)
        .collect()
}

fn is_only_uniq_values(arr: &[u32]) -> bool {
    arr.iter().collect::<HashSet<_>>().len() == arr.len()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn valid_values() {
        assert_eq!(is_valid_gol_value(425), true);
    }

    #[test]
    fn invalid_values() {
        let mut errors = 0;

        for i in 0..9999 {
            if i != 425 && is_valid_gol_value(i) {
                println!("error value: {}", i);

                errors += 1;
            }
        }

        assert_eq!(errors, 0);
    }
}