BitBlizzard

Tastes sorta like tea...

User Tools

Site Tools


universe_tree
# GLOBAL ###############################################################
rootSeed = "0123456789abcdef"
 
class Unit(float):
    def __new__(cls, base, value=1, name="baseUnit"):
        return super().__new__(cls, value)
 
    def __init__(self, base, value=1, name="m"):
        self.base = base
        self.name = name
 
    def test(self):
        return "One %s is %s %s" % (self.name, super().__str__(), self.base.name)
 
baseUnit = Unit(1,1)
 
## Constants
### Mass in grams
g = Unit(baseUnit, name="Gram")
solarMass = Unit(g, 1988920001144580000000000000000, "Solar Mass")
ug = Unit(g, 1e-6, "Microgram") # Microgram
mg = Unit(g, 0.001, "Milligram") # Milligram
kg = Unit(g, 1000, "Kilogram")
 
### Distance in meters
m   = Unit(baseUnit, name="m")
gpc = Unit(m, 3.086e+25, "gpc")
mpc = Unit(m, 3.086e+22, "mpc")
kpc = Unit(m, 3.086e+19, "kpc")
pc  = Unit(m, 3.086e+16, "pc")
ly  = Unit(m, 9.461e+15, "ly")
au  = Unit(m, 1.496e+11, "au")
km  = Unit(m, 1000, "km")
cm  = Unit(m, 0.01, "cm")
mm  = Unit(m, 0.001, "mm")
 
print("Unit class test: %s" % gpc.test())
 
### Velocity in m/s
c = 2.998e+8
 
# GENNY ################################################################
from vectors import Vector
from string import ascii_uppercase, digits
import math, curses
import random
 
rand = random.random
set_seed = random.seed
choice = random.choice
randrange = random.randrange
randint = random.randint
set_seed(rootSeed)
Random = random.Random
 
set_seed(rootSeed)
 
name_chars = ascii_uppercase+digits
 
class Vector(Vector):
    scale = m
 
    """Extends the Vector object with some more methods."""
    def __init__(self, x = 0, y = 0, z = 0, scale = m):
        self.scale = scale
        super(Vector, self).__init__(x, y, z)
 
    def midpoint(self, other):
        """Center between two vectors"""
 
        return Vector(
            (self.x + other.x) / 2,
            (self.y + other.y) / 2,
            (self.z + other.z) / 2,
        )
 
    def distanceTo(self, other):
        """Distance between two vectors."""
 
        return math.sqrt(
            (
                self.x - other.x
            ) ** 2 + (
                self.y - other.y
            ) ** 2 + (
                self.z - other.z
            ) ** 2
        ) * other.scale
 
    def invert(self):
        """Returns exact opposite of this vector, e.g. -x, -y, -z."""
 
        return Vector(-self.x, -self.y, -self.z)
 
    def __iter__(self):
        """Iterate over vector's coordinates."""
 
        yield self.x
        yield self.y
        yield self.z
 
 
class Player(Vector):
    def __init__(self, x = 0, y = 0, z = 0, name = ""):
        self.name = name
        super(Player, self).__init__(x, y, z)
 
 
class CelestialSeed(Vector):
    minChildren = 1000
    maxChildren = 2000
    ecliptic = False # Whether children are spread out in a fuzzy
    # blob (False) or in a flat-ish disk (True)
 
    def __init__(self, x, y, z, childTypes, scale = mpc):
        self.childTypes = childTypes
 
        self.scale = scale # Since we instantiate this class naked later, scale should be optionally passed
        self.seed = "%s%s%s%s" % (x,y,z,rootSeed)
 
        super(CelestialSeed, self).__init__(x, y, z, self.scale)
 
    @property
    def pos(self):
        return self.x, self.y, self.z
 
    @pos.setter
    def pos(self, pos):
        self.x, self.y, self.z = pos
 
    @property
    def numChildren(self):
        if self.maxChildren:
            rnd = Random(self.seed)
 
            numChildren = rnd.randrange(
                self.minChildren, self.maxChildren+1
            )
        else:
            numChildren = 0
 
        return numChildren
 
    @property
    def children(self):
        types = self.childTypes
        rnd = Random(self.seed)
 
        for i in range(self.numChildren):
            yield rnd.choice(types)(
                rnd.random() + self.x,
                rnd.random() + self.y,
                rnd.random() + self.z
            )
 
    def nearestChildTo(self, other):
        """WARNING: Keep calls to a minimum"""
 
        nearest = None
        nearestDistance = None
 
        for child in self.children:
            if (nearest is None
            or child.distanceTo(other) < nearest.distanceTo(other)):
                nearest = child
 
        return nearest
 
    def __getitem__(self, item):
        """WARNING: Keep calls to a minimum"""
 
        if item <= self.numChildren:
            for i, child in enumerate(self.children):
                if i == item:
                    return child
 
        raise(IndexError("Index out of range"))
 
    @property
    def name(self):
        rnd = Random(self.seed)
 
        name = '-'.join(
            ''.join(rnd.choice(name_chars) for i in range(3))
            for i in range(3)
        )
 
 
        return name
 
def duplicate_name_check(parent):
    names = []
    nappend = names.append
 
    for i in parent.children:
        for c in i.children:
            n = c.name
 
            if n in names:
                print(n)
            else:
                nappend(n)
 
 
class Asteroid(CelestialSeed):
    scale = m
    childMassScale = kg
    minChildren = 0
    maxChildren = 0
 
    massScale = kg
 
    def __init__(self, x, y, z):
        super(Asteroid, self).__init__(x, y, z, (Asteroid,), self.scale)
 
 
class Moon(CelestialSeed):
    scale = km
    childMassScale = kg
    minChildren = 0
    maxChildren = 5
 
    massScale = solarMass
 
    def __init__(self, x, y, z):
        super(Moon, self).__init__(x, y, z, (Asteroid,), self.scale)
 
 
class Planet(CelestialSeed):
    scale = km
    childMassScale = solarMass
    childType = Moon
    minChildren = 0
    maxChildren = 100
 
    massScale = solarMass
 
    def __init__(self, x, y, z):
        super(Planet, self).__init__(x, y, z, (Moon,), self.scale)
 
 
class Star(CelestialSeed):
    scale = au
    childMassScale = solarMass
    minChildren = 1
    maxChildren = 100
 
    massScale = solarMass
 
    def __init__(self, x, y, z):
        super(Star, self).__init__(x, y, z, (Planet,), self.scale)
 
 
class StarSeed(CelestialSeed):
    scale = pc
    childMassScale = solarMass
    minChildren = 1000
    maxChildren = 2000
 
    massScale = solarMass
 
    def __init__(self, x, y, z):
        super(StarSeed, self).__init__(x, y, z, (Star,), self.scale)
 
 
class Galaxy(CelestialSeed):
    scale = kpc
    childMassScale = solarMass
    minChildren = 1000
    maxChildren = 2000
 
    massScale = solarMass
 
    def __init__(self, x, y, z):
        super(Galaxy, self).__init__(x, y, z, (StarSeed,), self.scale)
 
 
class SeedGrid(CelestialSeed): # THIS SHOULD PLANT SEEDS NOT INHERIT
    # AKA SHOULD HAVE IT'S OWN __iter__
    scale = gpc
 
    def __init__(self, snapTo = None):
        super(SeedGrid, self).__init__(0, 0, 0, (Galaxy,), self.scale)
 
        if snapTo:
            self.snap(snapTo)
 
    @property
    def numChildren(self):
        return 8
 
    @property
    def children(self):
        """Orient base universeTree on the corners of a 1-unit cube.
        My brain is in conflict about whether or not a base grid is
        ncessary."""
 
        childTypes = self.childTypes
        #~ scale = self.scale)
 
        for z in range(-2,2,2):
            for y in range(-2, 2,2):
                for x in range(-2,2,2):
                    yield CelestialSeed(
                        (x + 1),
                        (y + 1),
                        (z + 1),
                        childTypes
                    )
 
    def snap(self, pos):
        """Move grid to the nearest self.scale relative to pos"""
        base = self.scale
 
        self.x = int( base * round(float(pos.x) / base) )
        self.y = int( base * round(float(pos.y) / base) )
        self.z = int( base * round(float(pos.z) / base) )
 
 
 
if __name__ == "__main__":
    player = Player()
 
    universeTree = SeedGrid()
    universeTree.snap(player)
 
    print(universeTree.nearestChildTo(player).nearestChildTo(player))
 
    for c in universeTree.children:
        print("Parent has num children: %s" % c.numChildren)
 
    # ~ duplicate_name_check(universeTree)
 
    nearestSeed = universeTree.nearestChildTo(player)
    nearestGalaxy = nearestSeed.nearestChildTo(player)
    nearestStarSeed = nearestGalaxy.nearestChildTo(player)
    nearestStar = nearestStarSeed.nearestChildTo(player)
 
    print(
        "Nearest seed: %s, Distance to: %s" % (
            nearestSeed, 
            player.distanceTo(nearestSeed)
        )
    )
 
    print(
        "Nearest galaxy: %s, Distance to: %s" % (
            nearestGalaxy,
            player.distanceTo(nearestGalaxy)
        )
    )
 
    print(
        "Nearest star seed: %s, Distance to: %s" % (
            nearestStarSeed,
            player.distanceTo(nearestStarSeed)
        )
    )
 
    print(
        "Nearest star: %s, Distance to: %s" % (
            nearestStar,
            player.distanceTo(nearestStar)
        )
    )
 
    branchChildrenCount = nearestSeed.numChildren + nearestGalaxy.numChildren + nearestStarSeed.numChildren + nearestStar.numChildren
    print("Num children in nearest branch: %s" % branchChildrenCount)
 
    print("Distance to nearest star: %s" % player.distanceTo(nearestStar))
 
    print("This should be False: %s" % str(1+mpc == 1.5+mpc))
universe_tree.txt · Last modified: 2019/08/13 07:33 by admin