Advertisement
Guest User

Untitled

a guest
Aug 7th, 2010
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.81 KB | None | 0 0
  1. #!/usr/bin/env python2.6
  2. # -*- coding: utf-8 -*-
  3.  
  4. """
  5. Simulation for the Feudalism Problem: http://i.t4z.com.ar/4n5
  6. """
  7.  
  8. __author__ = 'Santiago Coffey'
  9. __email__ = 'scoffey@alu.itba.edu.ar'
  10. __version__ = '0.1'
  11. __license__ = 'GNU General Public License 3'
  12. __docformat__ = 'restructuredtext en'
  13.  
  14. import logging
  15. import optparse
  16. import sys
  17.  
  18. logger = logging.getLogger(__name__)
  19.  
  20. class SimulationInputError(ValueError):
  21.     """ Exception for invalid simulation input """
  22.  
  23. class Simulation(object):
  24.     """ ABC for a simulation """
  25.  
  26.     iteration = 0
  27.  
  28.     def run(self, input_stream, output_stream):
  29.         """ Runs the simulation loop """
  30.         output = self.simulate("0 0")
  31.         output_stream.write(output + '\n')
  32.         output_stream.flush()
  33.         while True:
  34.             line = input_stream.readline()
  35.             if not line:
  36.                 logger.debug('End of simulation (%d iterations run)', \
  37.                         self.iteration)
  38.                 break
  39.             try:
  40.                 line = line.rstrip('\n')
  41.                 output = self.simulate(line)
  42.                 output_stream.write(output + '\n')
  43.                 output_stream.flush()
  44.                 self.iteration += 1
  45.             except SimulationInputError:
  46.                 logger.error('Invalid input: %s', line)
  47.             except Exception, e:
  48.                 logger.exception('Simulation error: %s', e)
  49.         return self.iteration
  50.  
  51.     def simulate(self, data):
  52.         """ Performs an iteration of the simulation """
  53.         raise NotImplementedError('Abstract method')
  54.  
  55. class BaseFeudalSimulation(Simulation):
  56.     """ Simulation of the Feudalism problem:  """
  57.  
  58.     CASTLES_ANNUAL_WEALTH = [700, 300]
  59.  
  60.     castle = None
  61.  
  62.     def simulate(self, data):
  63.         """ Performs an iteration of the simulation """
  64.         try:
  65.             population = map(int, data.strip().split(' '))
  66.         except Exception:
  67.             raise SimulationInputError()
  68.         logger.debug('Year %d population: %r', self.iteration, population)
  69.         last_castle_name = self.get_castle_name(self.castle)
  70.         self.castle = self.find_target_castle(population)
  71.         next_castle_name = self.get_castle_name(self.castle)
  72.         logger.debug('Moving from castle %s to %s', \
  73.                 last_castle_name, next_castle_name)
  74.         return next_castle_name
  75.  
  76.     def find_target_castle(self, population):
  77.         """ Finds the castle that pays best given the last population stats """
  78.         salaries = []
  79.         ws = self.CASTLES_ANNUAL_WEALTH
  80.         for i, w, p in zip(range(len(ws)), ws, population):
  81.             salary = self._compute_castle_salary(i, w, p)
  82.             logger.debug('Salary at castle %s is %s', \
  83.                     self.get_castle_name(i), salary)
  84.             salaries.append(salary)
  85.         return self._compute_target_castle(salaries)
  86.  
  87.     def _compute_castle_salary(self, i, w, p):
  88.         """ Computes current castle salary without further forecasts """
  89.         return w / float(p or 1)
  90.  
  91.     def _compute_target_castle(self, salaries):
  92.         """ Computes which castle pays best """
  93.         return salaries.index(max(salaries))
  94.  
  95.     def get_castle_name(self, castle):
  96.         """ Converts a castle index (int) to a castle name (str) """
  97.         return '(none)' if castle is None else chr(ord('A') + castle)
  98.  
  99. class FeudalSimulation(BaseFeudalSimulation):
  100.     """ Extends BaseFeudalSimulation by considering the salary drop
  101.        due to own move """
  102.  
  103.     def _compute_castle_salary(self, i, w, p):
  104.         """ Computes castle salary considering own move """
  105.         p += (0 if i == self.castle else 1)
  106.         return w / float(p or 1)
  107.  
  108. class PreventiveFeudalSimulation(FeudalSimulation):
  109.     """ Extends FeudalSimulation by giving a weight to the predictable move """
  110.  
  111.     PREVENTIVE_FACTOR = 2
  112.  
  113.     def _compute_castle_salary(self, i, w, p):
  114.         """ Computes castle salary giving weight to the predictable move """
  115.         p += (0 if i == self.castle else 1) * self.PREVENTIVE_FACTOR
  116.         return w / float(p or 1)
  117.  
  118. class ReallyPreventiveFeudalSimulation(PreventiveFeudalSimulation):
  119.     """ Same as PreventiveFeudalSimulation with a higher weight """
  120.  
  121.     PREVENTIVE_FACTOR = 4
  122.  
  123. class RunnerUpFeudalSimulation(FeudalSimulation):
  124.     """ Extends FeudalSimulation by selecting the second castle that
  125.        pays best """
  126.  
  127.     def _compute_target_castle(self, salaries):
  128.         """ Computes the second castle that pays best """
  129.         target = salaries.index(max(salaries))
  130.         salaries[target] = 0
  131.         return salaries.index(max(salaries))
  132.  
  133. def parse_options(args):
  134.     """ Parses program args into options """
  135.     parser = optparse.OptionParser('usage: %prog [options] ' \
  136.             '[castles annual wealth values]')
  137.     parser.add_option('-i', '--input', dest='input', \
  138.             help='input filename')
  139.     parser.add_option('-o', '--output', dest='output', \
  140.             help='output filename')
  141.     parser.add_option('-s', '--strategy', dest='strategy', \
  142.             help='strategy number (0-4)', type='int', default=0)
  143.     parser.add_option('-v', '--verbose', action='store_true', \
  144.             help='log debug info (via stderr)', default=False)
  145.     return parser.parse_args(list(args))
  146.  
  147. def make_simulation(*args):
  148.     """ Validates options and sets up the simulation """
  149.     STRATEGIES = [
  150.         BaseFeudalSimulation(),         # ignores population changes
  151.         FeudalSimulation(),             # considers population changes
  152.         PreventiveFeudalSimulation(),   # prevents predictable move
  153.         ReallyPreventiveFeudalSimulation(), # idem, more preventive
  154.         RunnerUpFeudalSimulation(),     # chooses second best castle
  155.     ]
  156.     (options, args) = parse_options(args)
  157.     if options.verbose:
  158.         logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
  159.     else:
  160.         logging.basicConfig(stream=sys.stderr, level=logging.INFO)
  161.     if 0 < len(args) < 2:
  162.         logger.warn('Invalid arguments for castles annual wealth: ' \
  163.                 'Expected at least 2 integer values: %r', args)
  164.     if len(args) < 2:
  165.         args = [700, 300]
  166.     if not (0 <= options.strategy < len(STRATEGIES)):
  167.         logger.warn('Invalid strategy number: %s', options.strategy)
  168.         options.strategy = 0
  169.     input = open(options.input) if options.input else sys.stdin
  170.     output = open(options.output, 'w') if options.output else sys.stdout
  171.     simulation = STRATEGIES[options.strategy]
  172.     simulation.CASTLES_ANNUAL_WEALTH = map(int, args)
  173.     return (simulation, input, output)
  174.  
  175. def main(program, *args):
  176.     """ Main program """
  177.     simulation, input, output = make_simulation(*args)
  178.     with input as input_stream:
  179.         with output as output_stream:
  180.             simulation.run(input_stream, output_stream)
  181.  
  182. if __name__ == '__main__':
  183.     main(*sys.argv)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement