diff --git a/backend/server/routers/ctf.py b/backend/server/routers/ctf.py index 378103f9f..5c340f063 100644 --- a/backend/server/routers/ctf.py +++ b/backend/server/routers/ctf.py @@ -133,46 +133,33 @@ def term_sums_even(data: PlannerData) -> bool: Check that the sum of the course codes in even terms is even """ is_even: Callable[[int], bool] = lambda x: x % 2 == 0 - print("Checking even") - for y, year in enumerate(data.plan): - # Exclude summer term + odd terms - for i, term in enumerate(year[2::2], 2): - term_sum = sum(map(get_code, term.keys())) - print(f"{y}T{i} sum: {term_sum}") - if not is_even(term_sum): - print("failed: ", term) - return False - - return True + return all( + is_even(sum(map(get_code, term.keys()))) + for year in data.plan[::2] + for term in year[1::2] + ) -# TODO def term_sums_odd(data: PlannerData) -> bool: """ Check that the sum of the course codes in odd terms is odd """ is_odd: Callable[[int], bool] = lambda x: x % 2 == 1 - print("Checking odd") - for year in data.plan[::2]: - # Exclude summer term + even terms - for term in year[1::2]: - term_sum = sum(map(get_code, term.keys())) - if not is_odd(term_sum): - print("failed: ", term) - return False - return True + return all( + is_odd(sum(map(get_code, term.keys()))) + for year in data.plan[::2] + for term in year[1::2] + ) def comp1511_marks(data: PlannerData) -> bool: """ Ollie must achieve a mark of 100 in COMP1511 to keep his scholarship """ - for year in data.plan: - for term in year: - for course in term: - _, marks = term[course] # type: ignore - if course == "COMP1511": - return marks == 100 - - return False + return any( + marks == 100 and course == "COMP1511" + for year in data.plan + for term in year + for (course, (_, marks)) in term.items() # type: ignore + ) def gen_ed_sum(data: PlannerData) -> bool: @@ -204,12 +191,13 @@ def math_limit(data: PlannerData) -> bool: In your N-th year, you can only take N + 1 math courses """ for i, year in enumerate(data.plan, 1): - num_math = len([ - course + # Use sum(1, ...) instead of len to avoid dual allocation + num_math = sum( + 1 for term in year for course in term if course.startswith("MATH") - ]) + ) if num_math > i + 1: return False @@ -228,15 +216,16 @@ def comp1531_third_year(data: PlannerData) -> bool: COMP1531 must be taken in the third year """ third_year = data.plan[2] - for term in third_year: - for course in term: - if course == "COMP1531": - return True - - return False + return any( + course == "COMP1531" + for term in third_year + for course in term + ) -# (validator_func, message, Optional) -requirements: list[tuple[Callable[[PlannerData], bool], str, Optional[str]]] = [ +ValidatorFn = Callable[[PlannerData], bool] +ObjectiveMessage = str +Flag = str +requirements: list[tuple[ValidatorFn, ObjectiveMessage, Optional[Flag]]] = [ # Challenge 1 (hard_requirements, "Before you can submit, you must check that you are in a 3 year CS degree and have a math minor", None), (summer_course, "Ollie must take one summer COMP course.", None), @@ -255,7 +244,7 @@ def comp1531_third_year(data: PlannerData) -> bool: ] @router.post("/validateCtf/") -def validate_ctf(data : PlannerData): +def validate_ctf(data: PlannerData): """ Validates the CTF """ @@ -270,10 +259,11 @@ def validate_ctf(data : PlannerData): "flags": flags, "message": msg } + passed.append(msg) if flag is not None: flags.append(flag) - print("Ok: ", req_num) + return { "valid": True, "failed": -1, diff --git a/frontend/src/pages/TermPlanner/ValidateCtfButton/ValidateCtfButton.tsx b/frontend/src/pages/TermPlanner/ValidateCtfButton/ValidateCtfButton.tsx index c2ccc9a77..9acb9cdfb 100644 --- a/frontend/src/pages/TermPlanner/ValidateCtfButton/ValidateCtfButton.tsx +++ b/frontend/src/pages/TermPlanner/ValidateCtfButton/ValidateCtfButton.tsx @@ -1,13 +1,12 @@ -/* eslint-disable */ import React from 'react'; import { useSelector } from 'react-redux'; +import { Typography } from 'antd'; import axios from 'axios'; +import styled from 'styled-components'; import prepareCoursesForValidationPayload from 'utils/prepareCoursesForValidationPayload'; import { RootState } from 'config/store'; import CS from '../common/styles'; import S from './styles'; -import { Typography } from 'antd'; -import styled from 'styled-components'; type CtfResult = { valid: boolean; @@ -30,7 +29,7 @@ const loadingResult: CtfResult = { failed: 0, passed: [], message: 'Loading...', - flags: [], + flags: [] }; const ModalTitle = styled(Title)` @@ -38,7 +37,6 @@ const ModalTitle = styled(Title)` color: ${({ theme }) => theme.text} !important; `; - const ValidateCtfButton = () => { const planner = useSelector((state: RootState) => state.planner); const degree = useSelector((state: RootState) => state.degree); @@ -46,14 +44,12 @@ const ValidateCtfButton = () => { const [result, setResult] = React.useState(loadingResult); const validateCtf = async () => { - // TODO: Call this async and disaplay output setOpen(true); const res = await axios.post( '/ctf/validateCtf/', prepareCoursesForValidationPayload(planner, degree, false) ); setResult(res.data); - console.log(res.data); }; return ( @@ -68,38 +64,33 @@ const ValidateCtfButton = () => { > Passed Challenges - { -
    - {result.passed.map((challenge, index) => ( - <> -
  1. - {challenge} -
  2. - - ))} -
- } +
    + {result.passed.map((challenge) => ( +
  1. + {challenge} +
  2. + ))} +
+ Unlocked Flags
    - {(result.flags.length > 0) && result.flags.map((flag, index) => ( - <> -
  1. - {flag} + {result.flags.length > 0 && + result.flags.map((flag) => ( +
  2. + {flag}
  3. - - ))} + ))}
+ - { - result.valid ? ( - {result.message} - ) : ( - Next: {result.message} - ) - } + {result.valid ? ( + {result.message} + ) : ( + Next: {result.message} + )}