import unittest import random import pyfmi.testcase import operator import string import math from itertools import * points = 5 def module_game(m1, m2): return (assess(m1, m2), assess(m2, m1)) def assess(mod, other): return sum(( end3_funcs(mod), avg_lists(mod, other), commutatives(mod), 3*monty_python_dicts(mod), )) def valid_attributes(mod): return (attr for attr in dir(mod) if not attr.startswith('_')) def end3_funcs(mod): func_names = [attr for attr in valid_attributes(mod) if callable(getattr(mod, attr))] count = 0 for func in func_names: if len(func) < 3: continue start = func[:3] if any((otherfunc.endswith(start) for otherfunc in func_names if func != otherfunc)): count += 1 return count def avg_lists(mod, other): other_ints = [getattr(other, attr) for attr in valid_attributes(other) if isinstance(getattr(other, attr), (int, long))] other_sum, other_len = sum(other_ints), len(other_ints) mod_lists = (getattr(mod, attr) for attr in valid_attributes(mod) if isinstance(getattr(mod, attr), list)) count = 0 square = lambda x: x*x for l in mod_lists: jingled_items = [sum(imap(square, tup)) for tup in l] jingled_sum, jingled_len = sum(jingled_items), len(jingled_items) # don't use floats # we know that always both the sum and the len are non-negative if jingled_sum > 0 and 0 == other_len: count += 1 elif jingled_sum*other_len > jingled_len*other_sum: count += 1 return count def commutatives(mod): funcs = [getattr(mod, attr) for attr in valid_attributes(mod) if callable(getattr(mod, attr))] count = 0 for func in funcs: if func(0,0) == 0 and\ all((func(i, j) == func(j, i) for i in xrange(0, 99) for j in xrange(i+1, 100))): count += 1 return count def monty_python_dicts(mod): WANTED = set(['chapman', 'cleese', 'gilliam', 'idle', 'jones', 'palin']) dicts = [getattr(mod, attr) for attr in valid_attributes(mod) if isinstance(getattr(mod, attr), dict)] count = 0 # DSU, DSU def make_decorate(dict_): def decorate(key): value = dict_[key] svalue = str(value).lstrip('-') return (len(svalue), math.tan(math.radians(value))) return decorate for d in dicts: ordered = sorted(d, key=make_decorate(d), reverse=True) if set(imap(string.lower, ordered[:6])) == WANTED: count += 1 return count class ProblemTests(pyfmi.testcase.TestCase): def test_1_end3_funcs_simple(self): m1 = self.make_mod() m2 = self.make_mod() self.add_funcs(m1, 'tiririram', 'robustotroniX'); self.add_funcs(m2, 'habobUTU', 'UTUmana', 'UTUdaba'); self.assert_game(m1, m2, (0, 2)) def test_2_end3_funcs_complex(self): m1 = self.make_mod() m2 = self.make_mod() self.add_funcs(m1, 'roy_boss', 'destroy', 'roy_keen', 'pinkoRroy', # more than one end with one beginning 'boyish', # non-function, see m1.eenboy below ); m1.eenboy = ('Pinko', 'the', 'Pink', 'panther') self.add_funcs(m2, 'ri', 'rri', # just 2 chars 'saZub', 'xxsaz', # different case '_baba', 'abaduc', # underscore 'Tru', 'xTru', # 3-char func, ok ) self.assert_game(m1, m2, (2, 1)) def test_3_avg_lists_simple(self): m1 = self.make_mod() m2 = self.make_mod() self.add_ints(m1, -33, 77, 31) # 75/3 -> 25 m2.l0 = [(5,), (5,), (5,), (), (6, 8), (), ()] # 25,25,25,0,100,0,0 -> 25 => equal m2.l1 = [(), ()] # 0, less m2.l2 = [(10,), (213,), (3, 4, 5, 88), (-18, -3, 44)] # uncountable ;) self.assert_game(m1, m2, (0, 1)) def test_4_avg_lists_tricky(self): # only zeros m1 = self.make_mod() m1.guga = [] m1.gugu = [()] m1.i = 0 m2 = self.make_mod() m2.l0 = [(), (), (), (), ()] self.assert_game(m1, m2, (0, 0)) # negative, zero m1 = self.make_mod() m2 = self.make_mod() self.add_ints(m1, -88, 2, -123, 22, 0, 0, 0, -77) # -33.125, every list in m2 should suffice self.add_ints(m2, 0, -3, 3) # 0, quite every list in m1 should suffice m1.l = [] m1.l0 = [()] m1.l1 = [(), (), (), (), (), (-4,)] m2.l = [(), (7,), (9,)] self.assert_game(m1, m2, (1, 1)) # non-integer averages m1 = self.make_mod() m2 = self.make_mod() self.add_ints(m1, 21, 21, 21, 22) # 21.25, 21 if int div used m2.l = [(8,), (), ()] # 21.(3), 21 if int div used self.assert_game(m1, m2, (0, 1)) #TODO: bigger test, who knows what could go wrong :) def test_5_comm_simple(self): m1 = self.make_mod() m2 = self.make_mod() m1.a = operator.add m1.b = operator.mul m1.c = self.make_func() m2.d = lambda x,y: 0 m2.e = self.make_func() self.assert_game(m1, m2, (2, 1)) def test6_comm_complex(self): m1 = self.make_mod() m2 = self.make_mod() m1.x = 77 m1.a = lambda x,y: x+y if x != 98 and y != 99 else -2 # nyyah m1.b = lambda x,y: x*y if x != 0 and y != 99 else 666 m2.c = lambda x,y: x*y + y * x # 0:1 m2.d = lambda x,y: 0 if x != 99 and y != 98 else 42 m2.e = lambda x,y: 1 if x != 0 and y != 0 else 0 # 0:2 m2.f = lambda x,y: x+y if x!=50 and y!=47 else 7324 m2.g = lambda x,y: x+y if x!=99 and y!=0 else -11 self.assert_game(m1, m2, (0, 2)) def test7_sort_simple(self): m1 = self.make_mod() m2 = self.make_mod() # no tan or case-insensitivity needed here m1.d = {'Chapman': 1111111, 'Cleese': 111111, 'Gilliam': 11111, 'Idle': 1111, 'Palin': 111, 'Jones': 11, 'Pinko': 1} m1.baba = 8 self.assert_game(m1, m2, (3, 0)) def test_8_sort_complex(self): if hasattr(self.user, 'fail8'): raise "Infinite loop in digits counting!" m1 = self.make_mod() m2 = self.make_mod() m1.a = {} m2.b = {'ChApMaN': -123213, 'cleese': 3, 'GiLLiam': 88, 'iDLE': 3.14, 'PalIn': 111, 'joNes': 0} # case m2.c = {'ChApMaN': 77, 'cleese': 88, 'GiLLiam': 99, 'iDLE': 33, 'PalIn': 21, 'joNes': 11, 'JONES': 92} m2.d = {'hey': -2, 'ChApMaN': 77, 'cleese': 88, 'GiLLiam': 99, 'iDLE': 33, 'PalIn': 21, 'joNes': 11, 'JONES': 92, 'bazuki': 88} self.assert_game(m1, m2, (0, 6)) def assert_game(self, m1, m2, res): self.assertEqual(self.user.module_game(m1, m2), res) @staticmethod def make_func(): """Makes none-commutative functions""" funcs = ( lambda x,y: x*y+333, lambda x,y: -3, lambda x,y: x**y, ) return random.choice(funcs) @staticmethod def add_funcs(mod, *names): for name in names: setattr(mod, name, ProblemTests.make_func()) @staticmethod def add_ints(mod, *values): for (i, value) in enumerate(values): setattr(mod, 'int%d' % i, value) @staticmethod def make_mod(): import imp return imp.new_module('m_'+str(random.randint(0, 2**31))) if __name__ == "__main__": ProblemTests.user_filename = 'test.py'; suite = unittest.defaultTestLoader.loadTestsFromTestCase(ProblemTests) res = unittest.TestResult() suite.run(res) runner = unittest.TextTestRunner() runner.run(suite)