def main(rulepath, datapath, detailed=False, name_filter=None, is_student=False): ruleset = rules.parse_file(rulepath) exported = aaps.read_exported_kattis_file(datapath) def handle_student(student): kattis = aaps.KattisResult() if is_student: kattis.resolve_sessions_with_input() add_sub = lambda sub: kattis.add_submission(sub) util.map_now(add_sub, student.submissions) context = resolver.make_context() plugins = kattis.get_plugins() add_plugin = lambda c, r: resolver.context_add_plugin(context, c, r) util.starmap_now(add_plugin, plugins) result = resolver.resolve(ruleset, context) return make_student_result(student, ruleset, kattis, context, result) def name_match(student): return name_filter.lower() in student.name or \ name_filter.lower() in student.username students = util.filter_now(name_match, exported.students) student_results = util.map_now(handle_student, students) print_result = lambda result: print_student_result(result, detailed) util.map_now(print_result, student_results)
def resolve(ruleset, context): rules = ruleset.rules result = Result() context_set_result(context, result) def on_rule_fail(rule): result_update_failed_goal(result, rule) def on_rule_success(rule): points = 0 try: points = context.value_expression(rule.points) except TypeError as e: print('Got a TypeError saying "{}"'.format(e)) print('while trying to resolve points for: \n\n{}\n'.format(rule)) result_update_resolved_goal(result, rule, points) def process_rule(rule): needs = context.bool_expression(rule.needs) success = lambda: on_rule_success(rule) fail = lambda: on_rule_fail(rule) util.crossroad(lambda: needs, success, fail) def process_by_index(index): process_rule(rules[index]) order = topological_order(rules) util.map_now(process_by_index, order) return result
def main(): check_config_path_or_write_help_message() config = get_config() reply = login(config) def get_profile_page(idx): hostname = urlparse(config.get('kattis', 'loginurl')).netloc username = config.get('user', 'username') return 'https://{}/users/{}?page={}'.format(hostname, username, idx) # If someone has over 1000 pages then they surely will have no problem # finding out how this looks and rewriting this to work for them. one_thousand_pages = [get_profile_page(idx) for idx in range(1000)] allpages = collections.deque(one_thousand_pages) collected = collections.deque() page1 = allpages[0] def collector(info): collected.append(info) if len(collected) % 100 == 0: print('Collected at least {} entries'.format( 100 * (len(collected) // 100)), file=sys.stderr) def destructor(): return 'IShouldStopNow' def thread_main(): for idx in range(100): try: page = allpages.popleft() except IndexError: return result = scrape_site(page, reply.cookies, collector, destructor) if result == 'IShouldStopNow': return threads = [threading.Thread(target=thread_main) for _ in range(10)] start_thread = lambda t: t.start() util.map_now(start_thread, threads) for thread in threads: thread.join() student = {'username': '******', 'name': 'Me', 'email': '', 'submissions': []} for submission in collected: judgement = 'Accepted' if 'accepted' in submission[ 'status'] else 'Wrong Answer' item = { 'time': submission['time'], 'judgement': judgement, 'problem': submission['problem_id'] } student['submissions'].append(item) data = {"students": [student], "sessions": []} print(json.dumps(data))
def add_student_session_problems(starttime, student, problems): is_student = lambda s: s.username == student student_data = util.find(is_student, result.students) student_not_exist = util.constant(not bool(student_data)) is_solved = lambda problem: 'solve_time' in problem add_problem = lambda problem: add_session_problem( student_data, problem, starttime) handle_single_problem = util.cond([(student_not_exist, util.noop), (is_solved, add_problem)]) util.map_now(handle_single_problem, problems)
def json_to_student(root): username = root.get('username', '[No Username]') name = root.get('name', '[No Name]') email = root.get('email', '') json_submissions = root.get('submissions', []) submissions = util.map_now(json_to_submission, json_submissions) student = make_student(username, name, email) add_sub = lambda sub: student_add_submission(student, sub) util.map_now(add_sub, submissions) return student
def handle_student(student): kattis = aaps.KattisResult() if is_student: kattis.resolve_sessions_with_input() add_sub = lambda sub: kattis.add_submission(sub) util.map_now(add_sub, student.submissions) context = resolver.make_context() plugins = kattis.get_plugins() add_plugin = lambda c, r: resolver.context_add_plugin(context, c, r) util.starmap_now(add_plugin, plugins) result = resolver.resolve(ruleset, context) return make_student_result(student, ruleset, kattis, context, result)
def resolver(context, tree): # If a problem does not have a deadline, then assume it is a lab # and move the deadline to something like 100 years from now. problems = util.map_now(make_problem, tree['uppgift']['problems']) deadline = tree['uppgift'].get('deadline', '01-01-2117 08:00') points = lambda problem: count_for_single_problem(problem, deadline) return sum(map(points, problems))
def parse_json(json, _from_file=''): # Create ruleset and add rules from json ruleset = make_ruleset() add_rule = lambda rule: ruleset_add_rule(ruleset, make_rule_from_json(rule) ) rules = json.get('rules', []) util.map_now(add_rule, rules) # Find all includes and include their rules as well include_group = get_include_group(json.get('includes', [])) def is_not_origin(fpath): return os.path.abspath(fpath) != os.path.abspath(_from_file) def add_rules_from_file(fpath): util.map_now(add_rule, get_rules_from_file(fpath)) include_group_except_self = filter(is_not_origin, include_group) util.map_now(add_rules_from_file, include_group_except_self) return ruleset
def add_session(session): # starttime in seconds since epoch starttime = int(session['starttime']) results = session['results'] add_team = lambda result: add_team_result(starttime, result) util.map_now(add_team, results)
def add_team_result(starttime, result): members = result['members'] problems = result['problems'] add_for_student = lambda student: add_student_session_problems( starttime, student, problems) util.map_now(add_for_student, members)
def read_exported_kattis_file(fpath): with open(fpath, 'r') as fp: content = json.load(fp) json_students = content['students'] def normalize_time(timestr): # Time is given in two different ways. Eiter '%Y-%m-%d %H:%M:%S' # or '%H:%M:%S' and in the latter it is supposed to be today. items = timestr.split('-') if len(items) <= 1: # Add date in front, it is the date for today today = time.localtime() return '{}-{}-{} {}'.format(today.tm_year, today.tm_mon, today.tm_mday, timestr) return timestr def json_to_submission(submission): problem_id = submission['problem'] judgement = submission['judgement'] subtime = normalize_time(submission['time']) judgement_translation_map = { 'Wrong Answer': 'WA', 'Time Limit Exceeded': 'TLE', 'Accepted': 'AC', 'Run Time Error': 'RTE', 'Memory Limit Exceeded': 'MLE', } inputtimeformat = '%Y-%m-%d %H:%M:%S' time_struct = time.strptime(subtime, inputtimeformat) year, month, day, hour, minute = time_struct[:5] output_time = '{}-{}-{} {}:{}'.format(day, month, year, hour, minute) result = judgement_translation_map.get(judgement, '') return make_submission(problem_id, output_time, result) def json_to_student(root): username = root.get('username', '[No Username]') name = root.get('name', '[No Name]') email = root.get('email', '') json_submissions = root.get('submissions', []) submissions = util.map_now(json_to_submission, json_submissions) student = make_student(username, name, email) add_sub = lambda sub: student_add_submission(student, sub) util.map_now(add_sub, submissions) return student result = make_exported_kattis() students = util.map_now(json_to_student, json_students) add_student = lambda student: exported_kattis_add_student(result, student) util.map_now(add_student, students) def solve_time(starttime, solvetime): solvetime_in_s = solvetime * 60 t = time.ctime(starttime + solvetime_in_s) year, month, day, hour, minute = t[:5] return '{}-{}-{} {}:{}'.format(day, month, year, hour, minute) def add_session_problem(student, problem, starttime): timestr = solve_time(starttime, problem['solve_time']) problem_id = problem['problem_name'] submission = make_submission(problem_id, timestr, 'AC') student_add_submission(student, submission) def add_student_session_problems(starttime, student, problems): is_student = lambda s: s.username == student student_data = util.find(is_student, result.students) student_not_exist = util.constant(not bool(student_data)) is_solved = lambda problem: 'solve_time' in problem add_problem = lambda problem: add_session_problem( student_data, problem, starttime) handle_single_problem = util.cond([(student_not_exist, util.noop), (is_solved, add_problem)]) util.map_now(handle_single_problem, problems) def add_team_result(starttime, result): members = result['members'] problems = result['problems'] add_for_student = lambda student: add_student_session_problems( starttime, student, problems) util.map_now(add_for_student, members) def add_session(session): # starttime in seconds since epoch starttime = int(session['starttime']) results = session['results'] add_team = lambda result: add_team_result(starttime, result) util.map_now(add_team, results) util.map_now(add_session, content['sessions']) return result
def add_rev_dependency(key, values): util.map_now(lambda val: rule_rev_dependency[val].append(key), values)
def find_and_add_goals(index, rule): get_need = find_expressions('get', rule.needs) get_point = find_expressions('get', rule.points) all_goals = get_need + get_point add_goal = lambda expr: goal_dependencies[index].add(expr['get']) util.map_now(add_goal, all_goals)
def topological_order(rules): # 1. Find each rule and the goals that it depends on # 2. Create a dependency tree where each rule depends # on all rules that go towards what they depend on # 3. Solve dependency with toposort goal_dependencies = collections.defaultdict(set) def find_and_add_goals(index, rule): get_need = find_expressions('get', rule.needs) get_point = find_expressions('get', rule.points) all_goals = get_need + get_point add_goal = lambda expr: goal_dependencies[index].add(expr['get']) util.map_now(add_goal, all_goals) util.starmap_now(find_and_add_goals, enumerate(rules)) def is_dependency_rule(index, original_idx): return rules[index].towards in goal_dependencies[original_idx] def find_rule_dependency(index): indices = range(len(rules)) # Note: also include self, because we can have the case that a user writes # a rule that depends on itself being completed... indexes_to_add = filter(lambda idx: is_dependency_rule(idx, index), indices) return list(indexes_to_add) rule_dependency = util.map_now(find_rule_dependency, range(len(rules))) rule_rev_dependency = [[] for _ in range(len(rules))] def add_rev_dependency(key, values): util.map_now(lambda val: rule_rev_dependency[val].append(key), values) util.starmap_now(add_rev_dependency, enumerate(rule_dependency)) connection_count = [len(x) for x in rule_dependency] # rule_rev_dependency is our dependency mapping and connection_count count # how many unsolved we depend on def should_add_to_queue(index): return connection_count[index] == 0 def add_to_queue(index): queue.append(index) def process_item(index): connection_count[index] -= 1 util.cond([(should_add_to_queue, add_to_queue)])(index) queue = list(filter(should_add_to_queue, range(len(rules)))) idx = 0 # We need to continuously evaluate the length of the queue so we # need to run with a while loop -.- while idx < len(queue): item = queue[idx] util.map_now(process_item, rule_rev_dependency[item]) idx += 1 return queue
def search_in_list(seq): return util.map_now(find_expression_rec, seq)
def process_all_rows(): data = util.map_now(process_row, rows) util.map_now(collector, data)
def resolver(context, tree): expression = tree[string] values = util.map_now(lambda expr: handle_expr(context, expr), get_values(expression)) return oper(values)
def add_rules_from_file(fpath): util.map_now(add_rule, get_rules_from_file(fpath))