import random
import time
from collections import defaultdict

def meets_criteria(numbers):
    """Check if the numbers have either 4 odd and 3 even or 3 odd and 4 even."""
    odd_count = sum(1 for num in numbers if num % 2 != 0)
    even_count = len(numbers) - odd_count
    return (odd_count == 4 and even_count == 3) or (odd_count == 3 and even_count == 4)

def has_consecutive(numbers):
    """Check if the numbers contain any consecutive numbers."""
    sorted_numbers = sorted(numbers)
    return any(sorted_numbers[i] + 1 == sorted_numbers[i + 1] for i in range(len(sorted_numbers) - 1))

# Numbers that should appear exactly once
frequency_one_numbers = {   20,  29, 31   }  # Add your desired numbers here

pool = list(range(1, 49))

def generate_valid_drawings():
    """Generate valid lottery drawings that meet the given criteria."""
    while True:
        drawings = []
        number_frequency = defaultdict(int)

        while len(drawings) < 12:
            drawing = random.sample(pool, 7)
            if meets_criteria(drawing) and not has_consecutive(drawing):
                # Check if adding this drawing will exceed the maximum frequency for any number
                temp_frequency = number_frequency.copy()
                for number in drawing:
                    temp_frequency[number] += 1
                if all(freq <= 2 for freq in temp_frequency.values()):
                    drawings.append(drawing)
                    for number in drawing:
                        number_frequency[number] += 1

        # Check if numbers in frequency_one_numbers have a frequency of 1
        # and all other numbers have a frequency of 1 or 2
        if all((number_frequency[num] == 1 if num in frequency_one_numbers else 1 <= number_frequency[num] <= 2) for num in pool):
            return drawings, number_frequency

def adjust_frequencies(drawings, number_frequency):
    """Adjust frequencies to ensure correct distribution."""
    for num in frequency_one_numbers:
        if number_frequency[num] > 1:
            # Need to remove this number from some drawings
            for drawing in drawings:
                if num in drawing and number_frequency[num] > 1:
                    drawing.remove(num)
                    replacement = next(n for n in pool if n not in frequency_one_numbers and number_frequency[n] < 2)
                    drawing.append(replacement)
                    number_frequency[num] -= 1
                    number_frequency[replacement] += 1
        elif number_frequency[num] == 0:
            # Need to add this number to a drawing
            for drawing in drawings:
                if num not in drawing:
                    to_remove = next(n for n in drawing if n not in frequency_one_numbers and number_frequency[n] > 1)
                    drawing.remove(to_remove)
                    drawing.append(num)
                    number_frequency[to_remove] -= 1
                    number_frequency[num] += 1
                    break

    return drawings

# Start the timer
start_time = time.time()

drawings, number_frequency = generate_valid_drawings()
final_drawings = adjust_frequencies(drawings, number_frequency)

# Calculate the final frequencies
final_number_frequency = defaultdict(int)
for drawing in final_drawings:
    for number in drawing:
        final_number_frequency[number] += 1

# End the timer
end_time = time.time()
elapsed_time = end_time - start_time

# Convert the elapsed time to hours, minutes, and seconds
hours, rem = divmod(elapsed_time, 3600)
minutes, seconds = divmod(rem, 60)

# Print the drawings in the requested format
print("\nDrawings:")
for i, drawing in enumerate(final_drawings):
    if i < len(final_drawings) - 1:
        print(f"{drawing},")
    else:
        print(f"{drawing}")

# Print the final frequency of each number
print("\nFinal frequency of each number:")
for number in range(1, 49):
    print(f"Number {number}: {final_number_frequency[number]} times")

# Print the elapsed time
print(f"\nElapsed time: {int(hours)} hours, {int(minutes)} minutes, and {int(seconds)} seconds")
