changeset 17:10d3db1f1e08

Set up initial research and rework breakthroughs.
author Jeremy Thurgood <firxen@gmail.com>
date Sun, 06 May 2012 17:39:37 +0200
parents af1bfeb648cb
children 0849ab5304cf
files gamelib/lab.py gamelib/products.py gamelib/research.py gamelib/tests/test_lab.py
diffstat 4 files changed, 132 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/gamelib/lab.py	Sun May 06 17:12:40 2012 +0200
+++ b/gamelib/lab.py	Sun May 06 17:39:37 2012 +0200
@@ -1,23 +1,64 @@
 # -*- test-case-name: gamelib.tests.test_lab -*-
 
+from random import random, choice
+
 from gamelib import research, products
 
 
 class Lab(object):
+    BASIC_RESEARCH_SUCCESS_RATE = 0.05
+    BASIC_RESEARCH_SUCCESS_MULTIPLIER = 2
+
     def __init__(self):
         self.science = []
         self.new_research = research.ResearchArea.__subclasses__()
         self.new_products = products.Product.__subclasses__()
+        self._choose_initial_science()
+
+    def _choose_initial_science(self):
+        # We always get all starting products.
+        for product in self.new_products[:]:
+            if product.STARTING_PRODUCT:
+                self._gain_science(product())
+
+        # We get three random sciences with no prerequisites.
+        new_science = []
+        for _ in range(3):
+            science = choice(self.find_new_research())()
+            self._gain_science(science)
+            new_science.append(science)
+
+        # Add a point to each of our sciences, and see if we get products.
+        self.spend_points(new_science, 0)
+
+    def _gain_science(self, science):
+        self.science.append(science)
+        if isinstance(science, research.ResearchArea):
+            self.new_research.remove(type(science))
+        elif isinstance(science, products.Product):
+            self.new_products.remove(type(science))
 
     def spend_points(self, things, basic_research):
-        new_stuff = []
+        breakthroughs = []
+
+        # First, allocate the points.
         for thing in things:
             assert thing in self.science
-            thing.spend_points(1)
+            assert thing.can_spend(self)
+            thing.spend_point()
+
+        # Next, check for product breakthroughs and upgrades
+        for thing in things:
             if isinstance(thing, research.ResearchArea):
-                new_stuff.extend(self.find_new_product(thing)[:1])
-        new_stuff.extend(self.try_basic_research(basic_research)[:1])
-        return new_stuff
+                breakthroughs.extend(self.apply_area_research(thing))
+
+        # Finally, check for research breakthroughs.
+        breakthroughs.extend(self.apply_basic_research(basic_research))
+
+        # Now that we have our breakthroughs, apply them.
+        print breakthroughs
+
+        return breakthroughs
 
     def _get_science(self, science_class):
         for science in self.science:
@@ -25,25 +66,54 @@
                 return science
         return None
 
-    def _meet_requirements(self, science_class):
+    def meet_requirements(self, science_class, extra=0):
+        total_points = 0
+        base_points = 0
         for science, level in science_class.PREREQUISITES:
             my_science = self._get_science(science)
             if my_science is None:
                 return False
             if my_science.points < level:
                 return False
-        return True
+            base_points += level
+            total_points += my_science.points
+        return total_points - base_points >= extra
 
     def find_new_products(self, research_area):
         available_products = []
         for product_class in self.new_products:
-            if self._meet_requirements(product_class):
+            if self.meet_requirements(product_class):
                 available_products.append(product_class)
         return available_products
 
-    def find_new_research(self, basic_research):
+    def find_new_research(self):
         available_research = []
         for research_class in self.new_research:
-            if self._meet_requirements(research_class):
+            if self.meet_requirements(research_class):
                 available_research.append(research_class)
         return available_research
+
+    def apply_area_research(self, research):
+        options = self.find_new_products(research)
+        breakthroughs = [product for product in options
+                         if random() < product.ACQUISITION_CHANCE]
+        if breakthroughs:
+            breakthrough = choice(breakthroughs)()
+            self._gain_science(breakthrough)
+            breakthroughs = [breakthrough]
+        return breakthroughs
+
+    def apply_basic_research(self, basic_research):
+        if basic_research <= 1:
+            return []
+
+        options = self.find_new_research()
+        success_chance = self.BASIC_RESEARCH_SUCCESS_RATE * (
+            self.BASIC_RESEARCH_SUCCESS_MULTIPLIER ** basic_research)
+        breakthroughs = [research for research in options
+                         if random() < success_chance]
+        if breakthroughs:
+            breakthrough = choice(breakthroughs)(1)
+            self._gain_science(breakthrough)
+            breakthroughs = [breakthrough]
+        return breakthroughs
--- a/gamelib/products.py	Sun May 06 17:12:40 2012 +0200
+++ b/gamelib/products.py	Sun May 06 17:39:37 2012 +0200
@@ -6,27 +6,50 @@
     PREREQUISITES = ()
     ACQUISITION_CHANCE = 0.8
     COST = 0
+    UPGRADE_REQUIREMENT = 1
+    STARTING_PRODUCT = False
 
-    def __init__(self):
-        self.points = 0
+    def __init__(self, points=0):
+        self.points = points
 
-    def spend_points(self, points):
-        self.points += points
+    def spend_point(self):
+        self.points += 1
+
+    def can_spend(self, lab):
+        extra = self.UPGRADE_REQUIREMENT * self.points + 1
+        return lab.meet_requirements(self, extra)
 
 
 class MachineGun(Product):
     NAME = "Machine gun"
     COST = 100
+    STARTING_PRODUCT = True
+
+    def __init__(self):
+        self.points = 1
+
+    def spend_point(self):
+        raise NotImplementedError()
+
+    def can_spend(self, lab):
+        return False
 
 
-class TeslaGun(Product):
-    NAME = "Tesla gun"
+class LightningGun(Product):
+    NAME = "Lightning gun"
     PREREQUISITES = (
         (research.Tesla, 1),
         )
     COST = 300
 
 
+class TeslaTank(Product):
+    NAME = "Tesla tank"
+    PREREQUISITES = (
+        (research.Tesla, 3),
+        )
+
+
 class DoomsdayVirus(Product):
     NAME = "Doomsday virus"
     PREREQUISITES = (
--- a/gamelib/research.py	Sun May 06 17:12:40 2012 +0200
+++ b/gamelib/research.py	Sun May 06 17:39:37 2012 +0200
@@ -2,11 +2,14 @@
     NAME = None
     PREREQUISITES = ()
 
-    def __init__(self):
-        self.points = 0
+    def __init__(self, points=0):
+        self.points = points
 
-    def spend_points(self, points):
-        self.points += points
+    def spend_point(self):
+        self.points += 1
+
+    def can_spend(self, lab):
+        return True
 
 
 class Tesla(ResearchArea):
--- a/gamelib/tests/test_lab.py	Sun May 06 17:12:40 2012 +0200
+++ b/gamelib/tests/test_lab.py	Sun May 06 17:39:37 2012 +0200
@@ -9,11 +9,23 @@
         self.lab = Lab()
 
     def test_find_new_products(self):
+        # Set up the appropriate research.
+        if research.Tesla in self.lab.new_research:
+            self.lab._gain_science(research.Tesla(1))
+        self.lab._get_science(research.Tesla).points += 2
+        # Check breakthrough options.
         new_products = self.lab.find_new_products(None)
-        self.assertTrue(products.MachineGun in new_products)
+        self.assertTrue(products.TeslaTank in new_products)
         self.assertTrue(products.DoomsdayVirus not in new_products)
 
     def test_find_new_research(self):
-        new_research = self.lab.find_new_research(None)
-        self.assertTrue(research.Tesla in new_research)
-        self.assertTrue(research.Space not in new_research)
+        # Set up the appropriate research.
+        if research.Robotics in self.lab.new_research:
+            self.lab._gain_science(research.Robotics(1))
+        if research.Rocketry in self.lab.new_research:
+            self.lab._gain_science(research.Rocketry(1))
+        self.lab._get_science(research.Rocketry).points += 1
+        # Check breakthrough options.
+        new_research = self.lab.find_new_research()
+        self.assertTrue(research.Space in new_research)
+        self.assertTrue(research.ArtificialIntelligence not in new_research)