# CSC 15 OOP Lab ############################################################################# ## Part I: ## I'm a gas station owner and I've hired you to program for me. Each # gas station sells only one type of gas: regular unleaded. # Each station will have an initial supply of 1000 gallons of gas. # Each station also has a manager, who will be fired if sales aren't good. # I want a computer to keep track of the sales and supply situation at each # gas station. I want to be able to run the following code AS IS. YOU # ARE NOT ALLOWED TO CHANGE IT. Get to work nerd! # Create station objects with manager's name and initial price per gallon: st1 = gasstation("john makeabuck",2.29) st2 = gasstation("jane gouger",2.59) st1.sellgas(10.5) # station1 just sold 10.5 gallons of gas st2.sellgas(20) # station2 just sold 20 gallons of gas st1.sellgas(3000) # should print not enough gas, no sale. st1.sellgas(11) print st1.totalsales() # prints the dollar amount of total sales. (2.29*21.5) print st1.currentsupply() # prints gallons of gas left in supply. st1.resupply() # reset gas supply to 1000 gallons st2.sale() # decrease price by 10% (do the math carefully nerd!) st2.gouge() # double the price before natural disasters st1.newmanager("mike manageron") # fire john, hire mike if st1.moresales(st2): print "station1 has better sales than station2" ## Now write the class to make this work. Think first: what variables # will each object contain? ##### #Part Ib: keeping track of prices: # After a change in gas price, I would also like to be able to restore the # price of gas to its previous value. For example, if the current price # for st2 is 3.00, then I want to be able to to run the following code: st2.sale() # price is now 2.70 st2.gouge() # price is now 5.40 st2.gouge() # price is now 10.80 st2.rollback() # price should now be 5.40 st2.rollback() # price should now be 2.70 st2.rollback() # price should now be 3.00 st2.rollback() # if there's no previous price, then price stays the same # That is, each call to rollback should cancel the previous sale or # gouging. To do this, you should use a list and .append to keep track # of prices. You should treat the list as a "stack". Think of the right # end of the list as the "top of stack" (tos). The following built-in call # *removes* the last element from the right-end of the stack, and returns it: # A.pop() # you can also use A.pop(i) to remove the ith indexed element # so for example, A = [] A.append(2) A.append(4) x = A.pop() # x is 4, and A is now [2] y = A.pop() # y is 2 and A should now be [] again. ############################## Part II ##################################### For this assignment you are to take a program that draws a single stick figure and make it object oriented. You can just edit the basic program given to you, or adopt the code you wrote for lab 2. Each figure needs to have the following attributes: x,y : center or 'chest' coordinate scale : size color armfactor : -1, 0, or 1 determine position of arms, default -1 mouthfactor : -1 or 1 for smile or frown, default -1 Your class needs to support at least the following methods: .behappy() .besad() .armsdown() .armsout() .armsup() .resize(ds) # grown or shrink figure by ds (scale += ds) .move(dx,dy) # change x,y position by dx,dy (x +=dx and y+=dy) .changecolor(c) # change color to color c .orient(angle,origin) # counterclockwise rotate about point origin .center() # returns center coordinates (chest point) as (x,y) .draw(brush,gc) # draw using brush into graphical context You may need to define additional methods to suppor the above methods (e.g., 'calcpoints'). You need to define a class called 'stickfigure' (above the function 'mydraw') Replace 'mydraw' with the following version, which must work with your class. Study the following code and comments closely: it will tell you how to define your class. def mydraw(brush,gc): gc.set_foreground(black) #clear background brush.draw_rectangle(gc,True,0,0,width,height) i = 0 # loop counter # each stick figure is defined by x,y of center, scale and color fig1 = stickfigure(width-164,height/2,64,white) fig2 = stickfigure(400,300,128,yellow) fig2.armsdown() # default is arms up fig1.besad() # default is be happy (change mouth to frown) fig1.draw(brush,gc) # draw initial figures fig2.draw(brush,gc) da = 0 # rotation angle (incremented in loop) dx,dy = randint(-5,5),randint(-5,5) # fig1 movement vector somecolors = [red,green,blue,yellow,white] while i<1000: gc.set_foreground(black) #clear background brush.draw_rectangle(gc,True,0,0,width,height) fig2.changecolor(somecolors[i%len(somecolors)]) if (i%3) == 0: fig1.armsup() # point arms up if (i%3) == 1: fig1.armsout() # arms should be strait if (i%3) == 2: fig1.armsdown() # arms down if i>500: fig1.behappy() fig2.resize(-2) # decrease size by 2 fig1.move(dx,dy) # change x,y of center by dx and dy (x+=dx, etc) # rotate fig2 by da degrees counterclockwise around its center: fig2.orient(da,fig2.center()) # fig2.center() should return (x,y) fig1.orient(330,(width/2,height/2)) # rotate fig1 around window center fig1.draw(brush,gc) fig2.draw(brush,gc) i+=1 da += 10 # increase angle of rotation updateDisplay() # always called at end of loop to display frame # end while cleanup() # should be called after end of all animation # end mydraw You may want to comment out parts of the code above to work on your program incrementally (suggest comment out .orient calls until you get rotation to work). You can change the values the variables in the program to suit your taste, but you cannot change how each method is called. You may also add other attributes and methods (such as an inherent angle attribute) but only in a backwards compatible way (the original code must still work). The following function rotates point by angle degrees counterclockwise around origin. point and origin are tuples (pairs) such as (5,4), (5,9), etc.. The function also returns the rotated point as a pair. def rotate(point,angle,origin): # point and origin are tuples x,y = point x0,y0 = origin x = x-x0 # adjust x,y relative to origin y = y-y0 ra = angle*pi/180 # convert to radians nx = x*cos(ra) + y*sin(ra) ny = y*cos(ra) - x*sin(ra) return ( int(nx+x0+0.5), int(ny+y0+0.5) ) # return pair of rounded integers # returns point pair ########## Part III (Extra Practice): Dates. ############################### # This part is not technially "required" but it will give you further # practice with object oriented programming. # For this part you need to implement objects similar to the mstime # object. You want a class of objects called 'date'. Each date object will # have a year, a month, and a day. Here's the code you'd like to write: date1 = date(11,30,2016) # create date object for november 30th, 2016 date2 = date(12,31,2013) # december 31st, 2013 print date1.tostring() # prints "11/30/2016" print date2.leapyear() # prints False, since 2013 % 4 != 0 date1.nextday() # advance date (destructively) to 12/1/2016 date2.nextday() # advance date to 1/1/2014 date3 = date2.dayafter() # RETURNS a date object representing 1/2/2014, but # is NON-DESTRUCTIVE (doesn't change date2). if date2 < date1: print "date2 comes before date1" #### don't forget! ## Hint: the difficult method is nextday. For this, you need to know ## the number of days in each month. The following array may help you: Days = [31,28,31,30,31,30,31,31,30,31,30,31] # However, you also need to adjust the value of Days[1] (Feburary) if # the current year is a leap year. You can define this array inside your # nextday function, or as a variable of your object (self.Days). # Hint: overload operators such as =, etc by defining a # __cmp__(self,other) method that returns 0 if the two objects are # considered equal, a negative integer if self < other, and a positive # integer if self > other. For exampke date2 < date 1 should return true. # To check if one date comes before another, first compare the year. If # the years are the same, compare the month. If the months are also the same, # compare the day. print date1 >= date2 # should print True #############################################EXTRAS########### ## (CHALLENGE) The formula for determining leap years is not as simple # as dividing by 4. Research the real formula and implement it. ## (MEGACHALLENGE): implement a method to compute the number of days until # the given date: christmas = date(12,25,2016) print date1.daysuntil(christmas), "days until Christmas" # Hint: convert the date to one number: christmas is day 359 of 365. But # always take into account leap years first. If the argument comes before # the date object, the function should return a negative number. ## (GIGACHALLENGE) Write a method to return the day of the week # of a data object. It should work as follows: date1 = date(11,18,2013) print date1.dayofweek() # should print "Monday" # Knowing that 11/18/2013 is a Monday should be enough for you to figure # out the day-of-week of all the other dates. What day was 1/1/1? # (don't worry about when the Gregorian calendar was adopted.) ## (TERACHALLENGE) Friday the 13th is an unlucky day (and a very bad movie). # Write a function to find the NEXT friday the 13th after a given date: date1.nextfri13() # should return a date object representing the next # friday the 13th after date1.