module e109;

import stdio;

type Turn struct {
    uint8 value;
    uint8 modifier;
}


func uint16 turn_total(Turn *this)
{
    return this.value * this.modifier;
}

// Arbitrary, but strict ordering in order to avoid double counting
func bool turn_le(Turn *this, Turn *other)
{
    return this == nil || (this.value < other.value || (
        this.value == other.value && this.modifier <= other.modifier));
}

func bool canGoOutOn(uint8 val)
{
    return (val <= 40 && val % 2 == 0) || val == 50;
}

func uint32 waysToCheckout(uint8 target, uint8 numLeft, Turn *prev)
{
    uint32 ways = canGoOutOn(target);
    if (numLeft == 1) {
        return ways;
    }

    // Account for non-bullseye things
    for (uint8 arcnum = 1; arcnum <= 20; ++arcnum) {
        for (uint8 ring = 1; ring <= 3; ++ring) {
            Turn t = { .value = arcnum, .modifier = ring }
            if (t.total() < target && prev.le(&t)) {
                ways += waysToCheckout(target - t.total(), numLeft - 1, &t);
            }
        }
    }
    // Bullseyes
    for (uint8 bullval = 25; bullval <= 50; bullval += 25) {
        Turn bull = { .value = bullval, .modifier = 1 }
        if (bull.total() < target && prev.le(&bull)) {
            ways += waysToCheckout(target - bull.total(), numLeft - 1, &bull);
        }
    }
    return ways;
}

public func int32 main(int32 argc, char*[] argv)
{
    uint32 answer = 0;
    for (uint8 target = 1; target < 100; ++target) {
        answer += waysToCheckout(target, 3, nil);
    }
    stdio.printf("%u\n", answer);
    return 0;
}