game/stars.py

134 lines
3.8 KiB
Python

# -*- 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 <http://www.gnu.org/licenses/>.
#
'''
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 random import randint, expovariate, seed, getrandbits, gauss
from poisson import poisson
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 generate_list_of_u64_for_ids(n):
'''
Return a sorted list of n random 64-bit integers
(suitable for SQLite rowid columns.)
See https://www.sqlite.org/lang_createtable.html#rowid
'''
result = set()
safety = 10
while n > 0:
canidate = getrandbits(63)
while canidate in result:
if not safety:
raise RuntimeError('this should not happen')
safety -= 1
canidate = getrandbits(63)
result.add(canidate)
n -= 1
return sorted(result)
TABLES = [
'create table stars (id INTEGER PRIMARY KEY, x INTEGER, y INTEGER, radius INTEGER)',
('''\
create table planets (
id INTEGER PRIMARY KEY,
ordo INTEGER,''' # The order from the star, counting from 1.
# I use "ordo" instead of "order" because "order" is a keyword
# in SQL (or at least it caused a syntax error in SQLite.)
'''star INTEGER,
FOREIGN KEY(star) REFERENCES stars(id)
)'''),
]
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 values (?, ?, ?, ?)', values)
star_id = values[0]
generate_planets_for_star(c, star_id)
c.close()
conn.commit()
def iter_stars(conn):
c = conn.cursor()
c.execute('select x, y, radius from stars')
yield from c.fetchall()
c.close()
# Procedural Generation of solar system data
def generate_stars(width, height, minimum_distance_between_stars):
# we could just call getrandbits(64) here for ID and hope for the best.
# it's a large domain (u64) so collisions are unlikely(!).
coords = list(poisson(width, height, minimum_distance_between_stars))
ids = generate_list_of_u64_for_ids(len(coords))
for star_id, (x, y) in zip(ids, coords):
yield star_id, x, y, round(1 + expovariate(1))
def how_many_planets():
n = round(gauss(5, 5))
while n < 0:
n = round(gauss(5, 5))
return n
def generate_planets_for_star(c, star_id):
for ordo in range(1, how_many_planets() + 1):
c.execute('insert into planets(ordo, star) values (?, ?)', (ordo, star_id))
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',
]