# -*- coding: utf-8 -*- # # Copyright © 2024 Simon Forman # # This file is part of game # # game is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # game is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with game. If not see . # ''' A field of stars. Each has planets. Each planet has...? Keep it simple. Stars have what qualities? - Cosmetic - color - brightness - size - Game stats - age? - ? 🌑 🌒 🌓 🌔 🌕 🌖 🌗 🌘 ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓ ''' from math import log10 from random import ( expovariate, gauss, lognormvariate, randint, random, seed, ) from poisson import poisson from wordlist import generate_name ROMAN_NUMBERS = [ None, # no zero, but this aligns entries and their indicies 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', ] seed(23) MINIMUM_DISTANCE_BETWEEN_STARS = 160 # The old standard 4:3 ratio screen of 1024 x 768 pixels, # let's have 10 x 10 of those. WIDTH, HEIGHT = 10240, 7680 # Database stuff. SQL, etc. def init_db(conn): print('Generating star data.') c = conn.cursor() for values in generate_stars(WIDTH, HEIGHT, MINIMUM_DISTANCE_BETWEEN_STARS): c.execute('insert into stars(x, y, radius, name) values (?, ?, ?, ?)', values) generate_planets_for_star(c) c.close() conn.commit() def iter_stars(conn): c = conn.cursor() c.execute('select x, y, radius, name from stars') yield from c.fetchall() c.close() def get_planets_for_star_named(conn, name): c = conn.cursor() c.execute( '''\ select planets.ordo, planets.bio_capacity, planets.industrial_capacity from planets join stars on stars.id = planets.star and stars.name = ? order by planets.ordo limit 29 ''', # Limit because we only have 29 Roman numbers. (name,) ) # TODO: move the display-related code to ui module? for ordo, bio_capacity, industrial_capacity in c.fetchall(): assert bio_capacity >= 0 assert industrial_capacity >= 0 b = round(log10(bio_capacity), 1) if bio_capacity else 0 i = round(log10(industrial_capacity), 1) if industrial_capacity else 0 yield f'{name}-{ROMAN_NUMBERS[ordo]}', b, i c.close() # Procedural Generation of solar system data def generate_stars(width, height, minimum_distance_between_stars): unique_names = set() for x, y in poisson(width, height, minimum_distance_between_stars): name = generate_name() while name in unique_names: name = generate_name() # I did get a name collision early on! unique_names.add(name) yield x, y, round(1 + expovariate(1)), name def how_many_planets(): ''' Return a non-negative integer, the number of planets a star should have. ''' n = round(gauss(5, 5)) while n < 0: n = round(gauss(5, 5)) return n def has_life(): # Ten percent chance of life return random() < 0.1 def generate_planets_for_star(c): # Only call this just after creating a star. star_id = c.lastrowid for ordo in range(1, how_many_planets() + 1): bio_capacity = round(lognormvariate(10, 5)) bio = bio_capacity if has_life() else 0 c.execute( 'insert into planets' '(ordo, star, bio_capacity, bio, industrial_capacity)' ' values (?, ?, ?, ?, ?)', ( ordo, star_id, bio_capacity, bio, round(lognormvariate(10, 5)), ), )