Advertisement
Vermiculus

Untitled

Apr 4th, 2012
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 20.18 KB | None | 0 0
  1. def d(m, s):
  2.     raw_input(m.format(s))
  3.  
  4. def statement_contains(s, l):
  5.     """Checks to see if s (a list of words) contains an element in l"""
  6.     ####### {v : v \in s AND v \in l} != {}
  7.     return [v for v in s if v in l] != []
  8.  
  9. class Kitchen:
  10.     """A facility for interpreting the esoteric language 'Chef'."""
  11.     class Error(Exception):
  12.         def __init__(self, title, message):
  13.             self.title = title
  14.             self.message = message
  15.    
  16.     def __init__(self, recipe="", master=None):
  17.         """Constructor
  18.        
  19.         Initializes lists for mixing bowls and baking dishes and
  20.             begins evaluating the recipe (taken in as a string).
  21.         """
  22.         import Bowl
  23.        
  24.         self.food = list()
  25.         with open('food.txt', 'r') as f:
  26.             for line in f:
  27.                 self.food.append(line[:-1])
  28.        
  29.         if master is None:
  30.             from collections import deque
  31.             self.ingredients = dict()   # contains a dictionary of ingredients
  32.             self.mixing_bowls = list()  # list of mixing bowls, stack-style
  33.             self.baking_dishes = list() # list of baking dishes, stack-style
  34.             self.stdin = deque()        # Our very own stdin! So we *could* take in more than one character at a time from what the user sees
  35.             self.stdout = deque()       # Well, if we have an stdin, might as well have an stdout. May make life easier.
  36.             self.history = list()       # Contains a list (stack) of (func, arg) tuples, most-recent last. Useful for looping.
  37.        
  38.         #handles a copy constructor
  39.         elif hasattr(master, 'ingredients') and hasattr(master, 'mixing_bowls') and hasattr(master, 'baking_dishes') and hasattr(master, 'stdin') and hasattr(master, 'stdout') and hasattr(master, 'history'):
  40.             self.ingredients = master.ingredients
  41.             self.mixing_bowls = master.mixing_bowls
  42.             self.baking_dishes = master.baking_dishes
  43.             self.stdin = master.stdin
  44.             self.stdout = master.stdout
  45.            
  46.             #self.history       = master.history
  47.             # This statement may interfere with correct looping.
  48.            
  49.             # Note that how we are storing the history right now allows me to say things like this:
  50.            
  51.             # >>> self.history.append(self.take, ['pizza', 'from', 'refrigerator'])
  52.             # >>> last_cmd = self.history[-1]
  53.             # (self.take, ['pizza', 'from', 'refrigerator'])
  54.             # >>> last_cmd[0](last_cmd[1])
  55.             # (does that last command again)
  56.            
  57.  
  58.     class Dish:
  59.         """One baking dish allowing for the basic operations."""
  60.        
  61.         def __init__(self):
  62.             self.items = list()
  63.        
  64.         def pour(self, other):
  65.             """Pours this baking dish into another."""
  66.             pass
  67.    
  68.     def do(self, s):
  69.         """Does an arbitrary operation from a valid Chef string
  70.        
  71.         The command must be the first word, case sensitive.
  72.         If the command does not exist, None is returned.
  73.         The rest of the string is passed to the desired function as a list.
  74.         """
  75.        
  76.         def isVerbStatement(li):
  77.             return len(li) == 3 and li[1] == "the" and li[2] in [v + "." for v in self.ingredients]
  78.        
  79.         t = s.split()
  80.         try:
  81.             if s == "Ingredients.":
  82.                 self._do_ingredients()
  83.             elif len(t) < 2:
  84.                 raise Kitchen.Error("Syntax Error", "Commands must have at least two tokens.")
  85.             elif hasattr(self, t[0]):
  86.                 return getattr(self, t[0])(t[1:])
  87.             elif isVerbStatement(t): # the word may be a verb
  88.                 print "Verbing!"
  89.                 print "Verb:", t[0]
  90.             else:
  91.                 print "No such attribute"
  92.            
  93.         except Kitchen.Error as (title, message):
  94.             import sys
  95.             sys.excepthook(*sys.exc_info())
  96.            
  97.             print ""
  98.             print "{t}: {m}\a".format(t=title, m=message)
  99.             return False
  100.    
  101.     def _do_ingredients(self):
  102.         s = raw_input()
  103.         measures = {"ml":"wet", "l":"wet", "dash":"wet", "dashes":"wet", "g":"dry", "kg":"dry", "pinch":"dry", "pinches":"dry", "cup":None, "cups":None, "teaspoon":None, "teaspoons":None, "tablespoon":None, "tablespoons":None, None:None}
  104.         types = {"heaped":"dry", "level":"dry"}
  105.         while s != "":
  106.             s = self._get_ingredient(s, measures, types)
  107.             self.ingredients[s[0]] = (s[1], s[2])
  108.             s = raw_input()
  109.        
  110.     def __repr__(self):
  111.         return "  Ingridients: {ing}\n Mixing Bowls: {mb}\nBaking Dishes: {bd}\n Input Buffer: {ip}\nOutput Buffer: {op}".format(ing=str(self.ingredients), mb=str(self.mixing_bowls), bd=str(self.baking_dishes), ip=str(self.stdin), op=str(self.stdout))
  112.    
  113.     # Have this function declare a multidimensional array of strings according to differing degrees of messiness
  114.     # so it can be called
  115.     # ...   return arr[len(mixing_bowls) // 5][len(baking_dishes) // 5]
  116.     # or something like that.
  117.     def __str__(self):
  118.         return "You see a mess of utensils; you have a lot of work yet to do."
  119.    
  120.     def _get_bowl(self, s):
  121.         """Returns the mixing bowl specified by this string.
  122.        
  123.         This method searches the string provided for the mixing bowl needed:
  124.         >>> getDish("Pour the 3rd mixing bowl into the 2nd baking dish.")
  125.         3
  126.        
  127.         If no ordinal for a mixing bowl is specified, it defaults to 1:
  128.         >>> getDish("Put zucchinis into the mixing bowl.")
  129.         1
  130.        
  131.         If there is no mention of any mixing bowls, this function returns None:
  132.         >>> getDish("I've got poop for brains.")
  133.         None
  134.         """
  135.         pass
  136.         return 0
  137.    
  138.     def _get_dish(self, s):
  139.         """Returns the baking dish specified by this string.
  140.        
  141.         This method searches the string provided for the baking dish needed:
  142.         >>> getDish("Pour the 3rd mixing bowl into the 2nd baking dish")
  143.         2
  144.        
  145.         If no ordinal for a baking dish is specified, it defaults to 1:
  146.         >>> getDish("Pour the 3rd mixing bowl into the baking dish")
  147.         1
  148.        
  149.         If there is no mention of any baking dishes, this function returns None:
  150.         >>> getDish("I've got poop for brains.")
  151.         None
  152.         """
  153.         pass
  154.         return 0
  155.    
  156.     def _get_ingredient(self, item, measures, types):
  157.         """Takes exactly one string, a dictionary of valid measures, and a dictionary of valid measure-types and returns (name, value, type)"""
  158.         name = type = value = explicit_type = None
  159.         s = item.split()
  160.         if len(s) < 1:
  161.             raise Kitchen.Error("Ingredient Error", "Blank line encountered.")
  162.         if s[0].isdigit():
  163.             value = int(s[0])
  164.             if statement_contains(s[1:], measures):
  165.                 if s[1] in types:
  166.                     type = types[s[1]]
  167.                     name = s[2:]
  168.                 elif s[1] in measures:
  169.                     type = measures[s[1]]
  170.                     name = s[2:]
  171.                 else:
  172.                     raise Kitchen.Error("Ingredient Error", "Illegal value or ingredient encountered.")
  173.             else:
  174.                 name = s[1:]
  175.         elif s[0] in measures:
  176.             type = measures[s[0]]
  177.             name = s[1:]
  178.             if name == []:
  179.                 raise Kitchen.Error("Ingredient Error", "Must specifiy an ingredient name.")   
  180.             elif s[0] in types:
  181.                 if s[1] in measures:
  182.                     type = types[type]
  183.                     name = s[2:]
  184.                     if name == []:
  185.                         raise Kitchen.Error("Ingredient Error", "Must specifiy an ingredient name.")
  186.             else:
  187.                 raise Kitchen.Error("Ingredient Error", "Must specifiy measure for type.")
  188.         else:
  189.             name = s
  190.         name = ' '.join(name)
  191.         return (name, value, type)
  192.    
  193.     def _get_ingredients(self, l):
  194.         """Takes a list l of ingredient-statements and populates the ingredients."""
  195.        
  196.         if len(l) < 1:
  197.             raise Kitchen.Error("Ingredient Error", "Must have at least one ingredient.")
  198.        
  199.         measures = {"ml":"wet", "l":"wet", "dash":"wet", "dashes":"wet", "g":"dry", "kg":"dry", "pinch":"dry", "pinches":"dry", "cup":None, "cups":None, "teaspoon":None, "teaspoons":None, "tablespoon":None, "tablespoons":None, None:None}
  200.         types = {"heaped":"dry", "level":"dry"}
  201.        
  202.         for item in l:
  203.             ing = self._get_ingredient(item, measures, types)
  204.             self.ingredients[ing[0]] = (ing[1], ing[2])
  205.  
  206.    
  207.     def Take(self, s):
  208.         """Take (ingredient) from refrigerator.
  209.        
  210.         This reads a numeric value from STDIN into
  211.             the ingredient named, overwriting any
  212.             previous value.
  213.         """
  214.        
  215.         def isFood(s):
  216.             return not s.isdigit()
  217.        
  218.         ingredient_name = ' '.join(s[:-2])
  219.        
  220.         if not isFood(ingredient_name):
  221.             raise Kitchen.Error("Name Error", "You can't eat {}".format(ingredient_name))
  222.             return False
  223.         elif s[-1] != "refrigerator." or s[-2] != "from":
  224.             raise Kitchen.Error("Syntax Error", "Take <ingredient> from refrigerator.")
  225.             return False
  226.        
  227.         elif len(self.stdin) is 0:
  228.             _in = raw_input("Press enter after input: ")
  229.             if _in.isdigit(): # if the entire input can be parsed as a single number
  230.                 self.stdin.append(int(_in)) # append that number to the buffer
  231.                 self.ingredients[ingredient_name] = self.stdin.popleft()
  232.             else:
  233.                 for char in _in: # otherwise, append the integer value of each character entered to the buffer.
  234.                     self.stdin.append(ord(char))
  235.                 self.ingredients[ingredient_name] = self.stdin.popleft()
  236.        
  237.         else:
  238.             self.ingredients[ingredient_name] = self.stdin.popleft()
  239.        
  240.         self.history.append((self.take, s))
  241.        
  242.         return True
  243.    
  244.     def Put(self, s):
  245.         """Put (ingredient) into the [nth] mixing bowl.
  246.        
  247.         This puts the ingredient into the nth mixing bowl.
  248.         """
  249.         pass
  250.         return True
  251.    
  252.     def Fold(self, s):
  253.         """Fold (ingredient) into [nth] mixing bowl.
  254.        
  255.         This removes the top value from the nth mixing bowl and places it in the ingredient.
  256.         """
  257.         pass
  258.         return False
  259.    
  260.     def Add(self, s):
  261.         """Two uses.
  262.        
  263.        
  264.         Add (ingredient) [to [nth] mixing bowl].
  265.             This adds the value of ingredient to the
  266.             value of the ingredient on top of the
  267.             nth mixing bowl and stores the result
  268.             in the nth mixing bowl.
  269.        
  270.         Add dry ingredients [to [nth] mixing bowl].
  271.             This adds the values of all the dry ingredients
  272.             together and places the result into the
  273.             nth mixing bowl.
  274.         """
  275.         pass
  276.         return False
  277.    
  278.     def Remove(self, s):
  279.         """Remove ingredient [from [nth] mixing bowl].
  280.        
  281.         This subtracts the value of ingredient from
  282.             the value of the ingredient on top of the
  283.             nth mixing bowl and stores the result in
  284.             the nth mixing bowl.
  285.         """
  286.         pass
  287.         return False
  288.    
  289.     def Combine(self, s):
  290.         """Combine ingredient [into [nth] mixing bowl].
  291.        
  292.         This multiplies the value of ingredient by
  293.             the value of the ingredient on top of
  294.             the nth mixing bowl and stores the result
  295.             in the nth mixing bowl.
  296.         """
  297.         pass
  298.         return False
  299.    
  300.     def Divide(self, s):
  301.         """Divide ingredient [into [nth] mixing bowl].
  302.        
  303.         This divides the value of ingredient into
  304.             the value of the ingredient on top of
  305.             the nth mixing bowl and stores the result
  306.             in the nth mixing bowl.
  307.         """
  308.         pass
  309.         return False
  310.    
  311.     def Liquefy(self, s):
  312.         """Two uses.
  313.        
  314.        
  315.         Liquefy | Liquify ingredient.
  316.             This turns the ingredient into a liquid,
  317.             i.e. a Unicode character for output purposes.
  318.            
  319.             (Note: The original specification used
  320.             the word "Liquify", which is a spelling
  321.             error. "Liquify" is deprecated.
  322.             Use "Liquefy" in all new code.)
  323.        
  324.         Liquefy | Liquify contents of the [nth] mixing bowl.
  325.             This turns all the ingredients in the nth mixing bowl
  326.             into a liquid, i.e. a Unicode characters for
  327.             output purposes.
  328.         """
  329.         pass
  330.         return False
  331.    
  332.     def Stir(self, s):
  333.         """Two uses.
  334.        
  335.        
  336.         Stir [the [nth] mixing bowl] for number minutes.
  337.             This "rolls" the top number ingredients
  338.             in the nth mixing bowl, such that the
  339.             top ingredient goes down that number of
  340.             ingredients and all ingredients above it
  341.             rise one place. If there are not that many
  342.             ingredients in the bowl, the top ingredient
  343.             goes to tbe bottom of the bowl and all
  344.             the others rise one place.
  345.        
  346.         Stir ingredient into the [nth] mixing bowl.
  347.             This rolls the number of ingredients
  348.             in the nth mixing bowl equal to
  349.             the value of ingredient, such that
  350.             the top ingredient goes down that number
  351.             of ingredients and all ingredients above
  352.             it rise one place. If there are not that
  353.             many ingredients in the bowl, the top
  354.             ingredient goes to tbe bottom of the bowl
  355.             and all the others rise one place.
  356.         """
  357.         pass
  358.         return False
  359.    
  360.     def Mix(self, s):
  361.         """Mix [the [nth] mixing bowl] well.
  362.        
  363.         This randomises the order of the
  364.             ingredients in the nth mixing bowl.
  365.         """
  366.         pass
  367.         return False
  368.    
  369.     def Clean(self, s):
  370.         """Clean [nth] mixing bowl.
  371.        
  372.         This removes all the ingredients
  373.             from the nth mixing bowl.
  374.         """
  375.         if len(s) > 3 or s[1] != 'mixing' or s[2] != 'bowl.':
  376.             return False
  377.        
  378.         num = self._get_dish(' '.join(s))
  379.         if num == None:
  380.             return False
  381.        
  382.         self.mixing_bowls[num] = list()
  383.         return True
  384.    
  385.     def Pour(self, s):
  386.         """Pour contents of the [nth] mixing bowl into the [pth] baking dish.
  387.        
  388.         This copies all the ingredients from
  389.             the nth mixing bowl to the
  390.             pth baking dish, retaining the order
  391.             and putting them on top of anything
  392.             already in the baking dish.
  393.         """
  394.         pass
  395.         return False
  396.    
  397.     def Set(self, s):
  398.         """Set aside.
  399.        
  400.         This causes execution of the innermost
  401.             loop in which it occurs to end
  402.             immediately and execution
  403.             to continue at the statement after
  404.             the "until".
  405.         """
  406.         pass
  407.         return False
  408.    
  409.     def Serve(self, s):
  410.         """Two uses.
  411.        
  412.        
  413.         Serve with auxiliary-recipe.
  414.             This invokes a sous-chef to immediately
  415.             prepare the named auxiliary-recipe.
  416.             The calling chef waits until the sous-chef
  417.             is finished before continuing.
  418.            
  419.             See the section on auxiliary recipes below.
  420.        
  421.         Serves number-of-diners.
  422.             This statement writes to STDOUT the contents
  423.             of the first number-of-diners baking dishes.
  424.             It begins with the 1st baking dish,
  425.             removing values from the top one by one and
  426.             printing them until the dish is empty,
  427.             then progresses to the next dish, until all
  428.             the dishes have been printed.
  429.            
  430.             The serves statement is optional, but is
  431.             required if the recipe is to output anything!
  432.         """
  433.         pass
  434.         return False
  435.    
  436.     def Refrigerate(self, s):
  437.         """Refrigerate [for number hours].
  438.        
  439.         This causes execution of the recipe
  440.             in which it appears to end immediately.
  441.             If in an auxiliary recipe, the auxiliary
  442.             recipe ends and the sous-chef's first
  443.             mixing bowl is passed back to the calling
  444.             chef as normal. If a number of hours is
  445.             specified, the recipe will print out its
  446.             first number baking dishes before ending.
  447.         """
  448.         pass
  449.         return False
  450.    
  451.     def _verb_(self, s):
  452.         """Takes care of VERB until VERBED.
  453.         Not a clue on how to do this yet.
  454.        
  455.         IDEA!
  456.          -- Create a new kitchen
  457.          -- keep reading in commands until verbed
  458.          -- pass commands to a new kitchen
  459.          -- once we reach 'until verbed', execute the history again
  460.          -- keep executing until condition is zero
  461.         """
  462.  
  463.         pass
  464.  
  465. def read_recipe(filepath):
  466.     """Loads the given *.chef file and does initial parsing.
  467.    
  468. This method will parse the given filename
  469.  
  470. See http://docs.python.org/library/doctest.html#module-doctest
  471. So much awesome.
  472.  
  473. Example output:
  474. >>> print read_recipe("/hw.chef")
  475. ["Hello World Souffle", "This recipe prints the immortal words "Hello world!", in a basically brute force way. It also makes a lot of food for one person.", "72 g haricot beans
  476. 101 eggs
  477. 108 g lard
  478. 111 cups oil
  479. 32 zucchinis
  480. 119 ml water
  481. 114 g red salmon
  482. 100 g dijon mustard
  483. 33 potatoes", "Put potatoes into the mixing bowl. Put dijon mustard into the mixing bowl. Put lard into the mixing bowl. Put red salmon into the mixing bowl. Put oil into the mixing bowl. Put water into the mixing bowl. Put zucchinis into the mixing bowl. Put oil into the mixing bowl. Put lard into the mixing bowl. Put lard into the mixing bowl. Put eggs into the mixing bowl. Put haricot beans into the mixing bowl. Liquefy contents of the mixing bowl. Pour contents of the mixing bowl into the baking dish.
  484.  
  485. Serves 1."]
  486.     """
  487.     pass
  488.  
  489. # takes the instruction string from earlier and splits it into statements
  490. def preheat(method):
  491.     """Takes all of the statements (as a single string) under Method and begins the parsing process.
  492.    
  493. This method returns a list of simple tuples where the first element is the command
  494. and the second element is the source string. The output of this method is intended
  495. for calling Mom.
  496.     """
  497.     pass
  498.  
  499. def gather(ingredients):
  500.     """Return a dictionary of ingredients from the given string.
  501.    
  502. The dictionary returned will contain the ingredient as a string
  503. mapped to a tuple, where the first element indicates if it is dry or wet
  504. and the second element denotes its numeric value.
  505.  
  506. Example:
  507.     {'apple':('dry', 96), 'oil':('wet', 59), etc.}
  508.     """
  509.     pass
  510.  
  511. # Because we all know her handwriting is horrid.
  512. # we may be able to make this fun by using advanced features of functions in Python
  513. def callMom(method):
  514.     """Takes a list of command-string tuples and returns a list of pure command-tuples.
  515.    
  516. Following is a list of commands and descriptions, following the pattern
  517. (<command>,  <arguments>)   - execute <command> with <arguments>
  518. where the default value of ## is exactly 1 (signifying the mixing bowl index
  519. and where # is a plain number
  520.  
  521. For overloaded commands, use hasattr() for type checking
  522.  
  523. ('take',     'ingredient')                 - get one character from the user and place its numeric value into ingredient
  524. ('put',      'ingredient', ##)             - push the ingredient onto the ##th mixing bowl
  525. ('fold',     'ingredient', ##)             - pop the ##th mixing bowl into the ingredient
  526. ('add',      'ingredient', ##)             - peek at the ##th mixing bowl and add (numerically) ingredient to it
  527. ('remove',   'ingredient', ##)             - peek at the ##th mixing bowl and subtract (numerically) ingredient from it
  528. ('combine',  'ingredient', ##)             - peek at the ##th mixing bowl and multiply (numerically) ingredient with it
  529. ('divide',   'ingredient', ##)             - peek at the ##th mixing bowl and divide (numerically) ingredient from it
  530. ('add', ##)                                - takes all of the dry ingredients and places the sum into the #th mixing bowl
  531. ('liquefy',  'ingredient')                 - transform the ingredient into its Unicode equivalent
  532. ('liquefy',   ##)                          - transform the contents of the ##th mixing bowl into their Unicode equivalents
  533. ('stir',      ##,           #)             -
  534. ('stir',     'ingredient',  ##)            -
  535. ('mix',        ##)                         - randomize the order of the ##th mixing bowl
  536. ('clean',      ##)                         - pop the ##th mixing bowl until empty
  537. ('loop',      'verb',      'ingredient')   - See after.
  538. ('next',      'verb',      'ingredient')   - See after.
  539. ('exit')                                   - Continues execution after the next 'next'
  540. ('serve',     'recipe')                    - Invokes the execution of another recipe
  541. ('fridge')                                 - Ends execution immediately and returns the first mixing bowl
  542. ('fridge, #)                               - Print out the first # baking dishes before calling ('fridge')
  543.  
  544. ('serves', #)                              - Pops and prints each baking dish in succession. This is the last command.
  545.  
  546. Note that everything that follows the 'serve' command is an auxiliary recipe.
  547.  
  548. Looping:
  549.   With the 'loop' command, if the ingredient is non-zero, continue execution until reaching the 'next' command. If the ingredient is zero, continue execution after a matching 'next'.
  550.   At the 'next' command, if an ingredient is given (defaulting to the ingredient given by 'loop'), continue execution at the previous 'loop' if the given ingredient is non-zero. If the ingredient is zero, simply continue.
  551.  
  552. The output of this method is intended for cooking.
  553.     """
  554.    
  555.     pass
  556.  
  557. def loadVerbs(path):
  558.     """Return a list verbs and their past-tense form read from a file with the given path.
  559.        
  560. The return will be a list of tuples containing two strings:
  561. the first being the infinite stem, the second being the simple past.
  562.  
  563. Example:
  564.    [("sift","sifted"),("boil","boiled"), ...]
  565.     """
  566.     pass
  567.  
  568. def loadFoods(path):
  569.     """ Returns a simple list of foods read from a file with the given path."""
  570.     pass
  571.  
  572. # executes a list of commands
  573. def cook(ingredients, method):
  574.     """Execute the list of commands given using the ingredients provided.
  575.    
  576. Execute the given list of commands in the format given by calling Mom.
  577. It is an error if a given command does not exist.
  578.     """
  579.    
  580.     ###################################################
  581.    
  582.     # iterate through the commands with complete control over position
  583.     #   (python's for-each loop does not give you any control)
  584.     cmd_index = 0
  585.     while cmd_index < len(method):
  586.         cmd_index += 1
  587.         pass
  588.    
  589.     pass
  590.  
  591.  
  592.  
  593. ########################################
  594.  
  595.  
  596. print statement_contains("hello world".split(), ["hello", "poop"])
  597.  
  598. hat = 'c= '
  599.  
  600. kills = ["quit", "exit", "stop", "kill", "term"]
  601.  
  602. k = Kitchen()
  603.  
  604. cmd = raw_input(hat)
  605. while cmd[:4] not in kills: # checks the first four letters
  606.     k.do(cmd)
  607.     print repr(k)
  608.     cmd = raw_input(hat)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement