OgloTheNerd's Website (fultiples>generation_algorithm.html)

Fultiples - Algorithm For Generating Boards

Syntax In This Document

Expression Syntax:
Syntax Description
X..Y Range that includes X and excludes Y.
X..=Y Range that includes both X and Y.
[X, Y, Z, ...] Array of values.

Parameters

You will see these in code comments above certain variables in the algorithm.

Variable Name Good Default Value Description
PRIMES [2, 3, 7] Chosen prime numbers/alphabet. (Always must contain 2 and 3 as values in the alphabet!)
SCALE_RANGE 2..20 Range for generating a random scalar for each cell. (The minimum cannot be 0!)
BOARD_SIZE_COLS 10 Number of columns in the board.
BOARD_SIZE_ROWS 10 Number of rows in the board.

Constant Expressions

Constant Name Constant Value Description
WILD_CARDS [1, 2, 3] Wild numbers.
WILD_CHANCE 3 Chance (percentage) that a wild number is chosen.

Algorithm

This example implementation of the algorithm is written in Python. If you do not know Python, don’t worry, the syntax is quite simple, and there are code comments to make it easier to understand.

#### Constants ####

WILD_CARDS = [1, 2, 3]
WILD_CHANCE = 3 # Chance of there being a wild card on the board. (Out of 100.)

###################

# Libraries Used
import random

# Position class.
class Position:
    def __init__(self, col, row):
        self.col = col
        self.row = row

# Simple function that checks if a number is prime or not.
def is_prime(prime):
    # NOTE: Ranges in Python are inclusive of start and exclusive of end.
    # Example: 'range(5, 17)' = [5, 6, ..., 15, 16]
    for i in range(2, prime):
        if (prime % i) == 0:
            return False

    return True

# Simple function to see if a number is a factor or multiple of another number.
def is_factor_or_multiple_of(number, of_number):
    if number == of_number:
        return True
    elif number > of_number:
        return (number % of_number) == 0
    else:
        return (of_number % number) == 0

def all_primes_in_range(all_range):
    primes = []

    for i in all_range:
        if is_prime(i):
            primes.append(i)

    return primes

def get_excluded_primes(primes, scale_range):
    all_primes = all_primes_in_range(scale_range)

    excluded_primes = []

    for prime in all_primes:
        if prime not in primes:
            excluded_primes.append(prime)

    return excluded_primes

def get_valid_scalars(primes, excluded_primes, scale_range):
    valid_scalars = []

    for i in scale_range:
        is_valid = False

        for prime in primes:
            if is_factor_or_multiple_of(i, prime):
                is_valid = True

        for prime in excluded_primes:
            if is_factor_or_multiple_of(i, prime):
                is_valid = False

        if is_valid:
            valid_scalars.append(i)

    return valid_scalars

# Simple function that has a chance of returning 'True'
# where the chance is a number out of 100.
def prob_of_true(percentage):
    prob = percentage * 0.01

    return random.random() < prob

def choose_random(items):
    return random.choice(items)

# This function generates a board and then returns it.
# In this case, a board is just a Python dictionary.
def generate_board(primes, scale_range, cols, rows):
    board = {} # A dictionary is just a type that maps keys to values.

    wild_card_index = 0
    wild_card_chosen_times = 0

    excluded_primes = get_excluded_primes(primes, scale_range)

    valid_scalars = get_valid_scalars(primes, excluded_primes, scale_range)

    # Iterating through every cell in the board...
    for col in range(cols):
        for row in range(rows):
            # Cell position.
            position = Position(col, row)

            chosen_prime = choose_random(primes)
            scalar = choose_random(valid_scalars)

            cell_value = chosen_prime * scalar

            if prob_of_true(WILD_CHANCE * len(WILD_CARDS)):
                if wild_card_chosen_times >= 3:
                    wild_card_chosen_times = 0
                    wild_card_index += 1

                if wild_card_index >= len(WILD_CARDS):
                    wild_card_index = 0

                wild_card = WILD_CARDS[wild_card_index]

                wild_card_chosen_times += 1

                cell_value = wild_card

            # Setting the cell value on the board.
            board[(position.col, position.row)] = cell_value

    # Returning the board out of the function.
    return board

# Main (entry) function for this example program.
def main():
    # Parameter: PRIMES
    primes = [2, 3]

    print("Enter prime numbers to use. To stop adding primes, simply press enter with nothing in the input.")

    while True:
        user_in = input("Enter Prime: ")

        if user_in == "":
            break

        prime = int(user_in)

        if is_prime(prime) == False:
            print("Not a valid prime number! Discarding...")
        else:
            primes.append(prime)

    # Parameter: SCALE_RANGE
    scale_range = range(2, int(input("Enter Maximum Scalar: ")) + 1)

    # Parameters: BOARD_SIZE_COLS, BOARD_SIZE_ROWS
    size_cols = int(input("Board Column Count (Recommended: 10): "))
    size_rows = int(input("Board Row Count (Recommended: 10): "))

    board = generate_board(primes, scale_range, size_cols, size_rows)

    print(f"\nPrimes: {primes}\n")

    for row in range(size_rows):
        for col in range(size_cols):
            position = Position(col, row)

            cell = board[(position.col, position.row)]

            print(f"{cell}", end = ' ')

        print("")

if __name__ == "__main__":
    main()