Exemplo n.º 1
0
    def correct_nb_iterations(self, actual, **args):
        """
        """

        return_code, text_output = actual

        coms = [rap.title("Iterations count")]

        C = coms.append
        R = rap.remark
        D = rap.disp_msg

        if return_code == 124:

            coms.append(
                rap.remark(
                    "AInfinity", 300,
                    "The execution of your code generates an infinite loop: correction impossible!\n"
                ))
            return 0, coms

        elif return_code != 0:
            coms.append(
                rap.remark("AAssist", 200,
                           "The code execution failed due to an error.\n"))
            return 0, coms

        if not self.ok_code:
            C(
                D("There is no point in testing this if the code is not correct...\n"
                  ))
            return 0, coms

        lines = text_output.splitlines()
        N = int(lines[0].split()[2])
        M = int(lines[1].split()[2])
        nb_it_stu = max(int(i) for i in lines[7].split())
        A = lines[2]
        B = lines[3]

        Disp_tab = "".join(("Avec N = ", str(N), ", et M = ", str(M),
                            "\nA : [", A, "]\nB : [", B, "]\n"))

        if nb_it_stu > N + M:
            C(
                R(
                    "ATours", 50,
                    "{}\nYour code generates {} iterations while the maximal limit is {}\n"
                    .format(Disp_tab, nb_it_stu, N + M)))
            return 0, coms
        else:
            coms.append(
                rap.disp_msg("If N = {}, M = {}, there are {} iterations: {}"
                             "".format(N, M, nb_it_stu, self.get_positive())))

        return 1, coms
Exemplo n.º 2
0
    def statement_respect(self, code, **args):
        """
        
        """
        coms = [rap.title("Compliance with the instructions and constrains")]

        self.report = None

        try:
            self.report = self.stats.compute_report(code, 0, False)
        except Exception:
            coms.append(
                rap.remark("AACode", 1500,
                           "An error occured during the code analysis\n"))
            return 0, coms

        rep = self.report

        if sum((rep.while_count, rep.for_count, rep.dowhile_count)) > 1:
            coms.append(
                rap.remark(
                    "ALoopInv", 500,
                    "The code does not comply with the number of loop constrain!\n\n"
                    "Therefore, your grade for the implementation part is 0.\n"
                ))
            return 0, coms

        if sum((rep.return_in_loop, rep.continue_in_loop, rep.break_in_loop,
                rep.goto_count)) != 0:
            coms.append(
                rap.remark(
                    "AGotoEtc", 500,
                    "The code contains break-like instructions like \"break\", \"continue\" or \"goto\"\n\n"
                    "Therefore, your grade for the implementation part is 0.\n"
                ))
            return 0, coms

        if self.report.called_func:
            coms.append(
                rap.remark(
                    "AEnonce", 500,
                    "The code calls the following functions: {}\nThis is forbidden for this Challenge!\n"
                    .format(",".join((s for s in self.report.called_func)))))

            return 0, coms

        coms.append(rap.disp_msg(self.get_positive()))

        return 1, coms
Exemplo n.º 3
0
    def check_sum(actual, **args):
        """Check the terms in a sum representation
        
        The string parameter should represent a sum of integer. This code check
        if the terms of the sum are correct and give a grade.
        
        Args:
            actual (string): a string representing a sum (numbers separed by '+'
                sign.
        
        Keywords Args:
            terms (list of int): sorted list of terms
        """
        #FIXME
        com = [rap.title(args['title'], 1)]

        grade = 1

        if debug:
            print repr(actual)

        terms = args['terms']

        try:
            actual_term = [int(s.strip()) for s in actual.split('+')]

        except ValueError:
            grade = 0
            com.append(
                rap.remark(
                    "C0.4.2", 50,
                    "Error in the sum expression. You must type numbers that are"
                    "separated with a '+'. Check your answer!\n", 0))
            return (grade, com)

        if terms == sorted(actual_term):
            com.append(rap.disp_msg(ran.choice(GT_Homework0.POSITIVE), 0))
        else:
            grade = 0
            com.append(rap.remark("C0.4.2", 50, "The sum is not correct\n", 0))

        return (grade, com)
Exemplo n.º 4
0
    def check_string(actual, **args):
        """
        Comparation of string
        """
        # First display the title
        i = 1
        com = [rap.title(args['title'], 1)]

        ground_truth = args['correct']

        i += 1
        grade = 0

        if (ground_truth == actual.lower()):
            com.append(rap.disp_msg(ran.choice(GT_Homework0.POSITIVE), i))
            grade = 1
        else:
            com.append(rap.remark(*(args['remark'])))

        return (grade, com)
Exemplo n.º 5
0
    def check_russian_mul(actual, **args):
        """Check russian multiplication correctness
        
        This check the russian multiplication proposed by the student. The 
        proposition is intended to be a string that is parsed by this function. 
        
        Checking computed:
            * Correct parsing 
            * Proposition answers to the question
            * Table size
            * Multiplication per 2 of multiplicand
            * Reminders calculation
            * Table correctness
            * Final result correctness
        
        Args:
            actual (string):
            
        Keyword Args:
            russia (list of list of int): representing a 2D array (list of 
                lines) of size n * 4. n is the number of lines and can vary 
                whereas the number of column (4) should be fixed. The table
                a | b | c | d
                e | f | g | h
                is hence represented as [[a,b,c,d],[e,f,g,h]]
        
        Returns:
            (int): a grade (over 1).
            (string): a french commentary that gives feedback about the 
                correctness oth the student's proposal
        """
        #FIXME
        com = [rap.title(args['title'], 1)]
        append = com.append

        # Get the structure from the answer
        russia_table = args['russia']
        """
        PARTIE I : data parsing and elementary tests
        """

        if debug:
            print repr(actual)

        # Recover the proposed table from the string
        try:
            actual_table = [[int(i.strip()) for i in t.split('|')]
                            for t in actual.splitlines()]
        except ValueError:
            append(
                rap.remark(
                    "AEnonce", 200,
                    "An error occured with the Russian peasant multiplication\n"
                    "You typed:\n\"{}\"\n".format(actual), 0))
            return (0, com)

        # Test 1 : premier multiplicande et multiplicateur correct
        try:
            if not ((actual_table[0][0] == russia_table[0][0]
                     and actual_table[0][1] == russia_table[0][1]) or
                    (actual_table[0][0] == russia_table[0][1]
                     and actual_table[0][1] == russia_table[0][0])):
                append(
                    rap.remark(
                        "AEnonce", 200,
                        "The first multiplier and/or the first multiplicand"
                        " are incorrect. Check you are computing the right operation."
                        "\nYou were asked: {} x {}\n".format(
                            russia_table[0][0], russia_table[0][1]), 0))
                return (0, com)
        except IndexError:
            append(
                rap.remark(
                    "AEnonce", 200,
                    "Format error for the Russian peasant multiplication\n"
                    "You typed:\n\"{}\"\n".format(actual), 0))
            return (0, com)

        length = int(math.floor(math.log(actual_table[0][1], 2)) + 1)

        # Test 2 : tables de longueur correcte :
        if len(actual_table) != length:
            append(
                rap.remark(
                    "AEnonce", 200,
                    "The table length is not correct. Do you divide properly the multiplier?\n",
                    0))
            return (0, com)

        # Test 2b : vérifier qu'il y a bien 4 valeur par ligne :
        if not all(len(line) == 4 for line in actual_table):
            append(
                rap.remark(
                    "AEnonce", 200,
                    "The table width is incorrect: there must be 4 columns:"
                    " Multiplicand, multiplier, Remainder and partial sum. In that order!",
                    0))
            return (0, com)
        """
        PARTIE II : deeper tests
        """
        score = 10
        #com = ""

        # Test 3 : multiplicande est multiplié par 2 à chaque ligne
        mul2 = all(actual_table[i][0] == 2 * actual_table[i - 1][0]
                   for i in range(1, length))

        if not mul2:
            append(
                rap.remark(
                    "ARUS_MUL", 75,
                    "The multiplicand must be multiplied by 2 from a row to another.\n",
                    0))
            score -= 2.5

        # Calcul des reste sont corrects
        reminders = all(line[2] == line[1] % 2 for line in actual_table)

        if not reminders:
            append(
                rap.remark("ARUS_MUL", 75,
                           "The remainders are not properly computed\n", 0))
            score -= 2.5

        # Calcul des multiplicateurs divisés
        multi = all(actual_table[i][1] == actual_table[i - 1][1] // 2
                    for i in range(1, length))

        # Vérification des sommes partielles
        sum_part = (all((actual_table[i][3] == actual_table[i - 1][3] +
                         actual_table[i][2] * actual_table[i][0])
                        for i in range(1, length)) and actual_table[0][3]
                    == actual_table[0][2] * actual_table[0][0])

        if not (multi and sum_part):
            append(
                rap.remark(
                    "ARUS_MUL", 75,
                    "There are error in the table (concerning multiplicands or partial sum)\n",
                    0))
            score -= 2.5
        else:
            append(rap.disp_msg("Partial sums are correct.\n", 0))

        # Résultat final est correct
        # Index -1 is the last elem...
        if actual_table[length - 1][3] != russia_table[-1][-1]:
            append(
                rap.remark("ARUS_MUL", 75, "The final result is incorrect.\n",
                           0))
            score -= 2.5
        else:
            append(rap.disp_msg("The final result is correct.\n", 0))

        return (score / 10.0, com)
Exemplo n.º 6
0
    def correct_fct_term(self, actual, **args):

        coms = [rap.title("Loop Variant")]

        if not self.report:
            coms.append(
                rap.disp_msg(
                    "The code analysis has failed. This was previously mentioned.\n"
                ))
            return (0, coms)

        TOTAL = 3.0
        grade = 3.0

        fb_fct_t = 0
        FB_STEP = 20

        C = coms.append
        R = rap.remark
        D = rap.disp_msg

        ids = re.findall(r"[a-zA-Z_]\w*", actual)
        ids_in_guard = self.report.loops_list[0]['ids']

        go_on = True

        # Une fonction t est construite sur base des variables du programme.

        for i in ids:
            if i not in ids_in_guard:
                C(
                    D("The identifier {} does not seem to appear in the loop condition.\n"
                      .format(i)))
                fb_fct_t += FB_STEP
                go_on = False

        varA = self.vars['A']
        varB = self.vars['B']

        if not (varA in ids and varB in ids):
            C(
                D("The variables {} and/or {} does not appear in the Loop Variant expression,\n"
                  "this is a problem\n".format(varA, varB)))
            fb_fct_t += FB_STEP
            go_on = False

        if not go_on:
            C(
                R("AFCTT", fb_fct_t,
                  "Continuing to test the Loop Variant is not possible.\n"))
            return 0, coms

        # Computaiotn of several values.

        def compute_t(values):
            try:
                val = eval(actual, {}, values)
            except Exception as e:
                if DEBUG:
                    print actual, values
                return None

            return val

        tests = (
            {
                varA: 0,
                varB: 0,
                'N': 100.0,
                'M': 50.0,
                'L': 50.0
            },
            {
                varA: 99,
                varB: 49,
                'N': 100.0,
                'M': 50.0,
                'L': 50.0
            },
            {
                varA: 10,
                varB: 10,
                'N': 100.0,
                'M': 50.0,
                'L': 50.0
            },
            {
                varA: 11,
                varB: 10,
                'N': 100.0,
                'M': 50.0,
                'L': 50.0
            },
            {
                varA: 10,
                varB: 11,
                'N': 100.0,
                'M': 50.0,
                'L': 50.0
            },
        )

        results = [compute_t(v) for v in tests]

        if any(r is None for r in results):
            C(
                R(
                    "AAssist", 1000,
                    "Something went wrong when calculating the value of the Loop Variant\n."
                ))
            return 0, coms

        integer_test = [
            isinstance(v, float) and v.is_integer() for v in results
        ]

        # Entier
        if not all(integer_test):
            fb_fct_t += 2 * FB_STEP
            C(D("Your Loop Variant does not seem to be an integer function.\n")
              )

        # Positif si B
        if not all(r > 0 for r in results):
            fb_fct_t += 2 * FB_STEP
            C(
                D("Your Loop variant does not seem to be always positive if the loop condition is true!\n"
                  "-> Check all the possible cases.\n"))

        # Décroissance (I love that)
        if not (results[3] < results[2]):
            fb_fct_t += 3 * FB_STEP
            C(
                D("If between 2 iterations, the value of {} is increasing, the value of the Loop Variant should be decreasing.\n"
                  .format(varA)))

        if not (results[4] < results[2]):
            fb_fct_t += 3 * FB_STEP
            C(
                D("If between 2 iterations, the value of {} is increasing, the value of the Loop Variant should be decreasing.\n"
                  .format(varB)))

        if fb_fct_t:
            C(rap.add_ffwd("AFCTT", fb_fct_t))
            return 0, coms
        else:
            C(D(self.get_positive()))

        return grade / TOTAL, coms
Exemplo n.º 7
0
    def correct_invariant(self, actual, **args):
        """
        
        """
        #Some decl.
        NO = Limit.NO
        MINUS = Limit.MINUS
        TOTAL = 10.0
        grade = TOTAL

        BAD_INV_PRIO = 40  # If #failure is high, will be event. > 350

        raw_limits = actual

        coms = [rap.title("Graphical Loop Invariant Correction")]

        C = coms.append
        R = rap.remark
        D = rap.disp_msg

        limits_list, com_lim = make_limits_list_wFB(raw_limits)

        C(
            D("\n".join((
                "Here is how the system understood your Invariant:\n",
                affichage_invariant(limits_list),
                '',
            ))))

        if com_lim:
            C(R("AEncodage", 100, com_lim))

        #var decl. to be used in the following

        Astart = limits_list[0]
        Aprev = limits_list[1]
        Aindex = limits_list[2]
        Alast = limits_list[3]
        Asize = limits_list[4]

        Bstart = limits_list[5]
        Bprev = limits_list[6]
        Bindex = limits_list[7]
        Blast = limits_list[8]
        Bsize = limits_list[9]

        Cstart = limits_list[10]
        Cprev = limits_list[11]
        Cindex = limits_list[12]
        Clast = limits_list[13]
        Csize = limits_list[14]

        epith = limits_list[15]
        src1 = limits_list[16]
        src2 = limits_list[17]
        inter = limits_list[18]

        # Invariant's correction

        fb_inv_needed = 0.0
        self.vars = {"A": None, "B": None, "C": None}

        if len(limits_list) > 19:
            coms.append(
                rap.remark("AEncodage", 100, "You must encode 19 boxes.\n"))
            return (0, coms)

        def test_one_tab(start, prev, index, last, size, correct_size, name,
                         offset):
            C(D("\nAbout the array {}:\n──────────────────\n".format(name)))
            TOTAL = 3.0
            grade = TOTAL
            fb_inv_needed = 0

            # mandatory
            if start != Limit(0, NO):
                C(
                    D("Box {}: Wrong content! Array indeces all start at...\n".
                      format(0 + offset)))
                grade -= 1
                fb_inv_needed += BAD_INV_PRIO

            if size != Limit(correct_size, NO):
                C(
                    D("Box {}: Wrong content! The array size is expected.\n".
                      format(4 + offset)))
                grade -= 1
                fb_inv_needed += BAD_INV_PRIO

            if not (index.is_var() and index.modif == NO):
                C(
                    D("Box {}: An array index is expected here!\n".format(
                        2 + offset)))
                grade -= 1
                fb_inv_needed += BAD_INV_PRIO
            else:
                C(
                    D("Box {}: [INFO] A variable was detected: {}\n".format(
                        2 + offset, index.symbol)))
                self.vars[name] = index.symbol

            if prev.is_var() and prev.modif == NO:
                C(
                    D("Box {}: Considering the arrays sizes types (unsigned int), it is highly recommended to NOT\n"
                      "   put the variable on this side of the division bar!\n"
                      .format(1 + offset)))

            # not mandatory
            if not (prev.is_unspecified() or
                    (prev == Limit(index.symbol, MINUS))):
                C(
                    D("Box {}: The content of this Box MUST be related to the content of the Box {}\n"
                      "   (and this last one should be correct too).\n".format(
                          1 + offset, 2 + offset)))
                grade -= 0.5
                fb_inv_needed += BAD_INV_PRIO / 2

            if not (last.is_unspecified() or
                    (last == Limit(correct_size, MINUS))):
                C(
                    D("Box {}: Wrong content! The last array index is expected here.\n"
                      .format(5 + offset)))
                grade -= 0.5
                fb_inv_needed += BAD_INV_PRIO / 2

            C(D("\n"))

            return max(0.0, grade / TOTAL), fb_inv_needed

        test, fbn = test_one_tab(Astart, Aprev, Aindex, Alast, Asize, "N", "A",
                                 1)
        fb_inv_needed += fbn
        grade -= (1 - test) * 2

        test, fbn = test_one_tab(Bstart, Bprev, Bindex, Blast, Bsize, "M", "B",
                                 6)
        fb_inv_needed += fbn
        grade -= (1 - test) * 2

        test, fbn = test_one_tab(Cstart, Cprev, Cindex, Clast, Csize, "L", "C",
                                 11)
        fb_inv_needed += fbn
        grade -= (1 - test) * 2

        C(D("\nBoxs remainder:\n───────────────\n"))

        # Boxs 16 to 19 relevance test

        clean = True

        if epith != Limit(7, NO):
            C(
                D("Box 16: The instructions does not mention \"{}\" values.\n".
                  format(fake_dict(DICO_1, epith.symbol))))
            grade -= 0.25
            fb_inv_needed += BAD_INV_PRIO / 4.0
            clean = False

        if not ((src1 == Limit(1, NO) and src2 == Limit(3, NO)) or
                (src2 == Limit(1, NO) and src1 == Limit(3, NO))):
            C(
                D("Box 17 and 18: The parts already treated (according to the drawing in A and B) must be specified.\n"
                  ))
            grade -= 0.5
            fb_inv_needed += BAD_INV_PRIO / 2.0
            clean = False

        if inter != Limit(5, NO):
            C(D("Box 19: Where is stored the result?\n"))
            grade - 0.25
            fb_inv_needed += BAD_INV_PRIO / 4.0
            clean = False

        if clean:
            C(D(self.get_positive() + "\n"))

        if fb_inv_needed:
            coms.append(rap.add_ffwd("AInvFail", fb_inv_needed))

        # Test des variables dans le code

        C(D("\nCode analysis:\n──────────────"))

        if not self.report:
            coms.append(
                rap.disp_msg(
                    "The code analysis has failed. This was previously mentioned.\n"
                ))
            grade -= 2
            return (grade / TOTAL, coms)
        else:
            init_dict = self.report.init_values

        def check_init(name, val_init):
            init = self.vars[name]

            malus = 0.0

            if init:
                if init not in init_dict:
                    C(
                        R(
                            "AInvInit", 200,
                            "\n-> The variable {} does not seem to be present in the code.\n"
                            .format(init)))
                    malus += 1
                elif init_dict[init] != val_init:
                    C(
                        R(
                            "AInvInit", 100,
                            "\n-> The variable {} does not seem to be initialized according to the Loop Invariant.\n"
                            .format(init)))
                    malus += 0.5
                else:
                    C(
                        D("\n=> The code and the Loop Invariant matches, as the initialisation of {} is concerned.\n"
                          .format(init)))

            else:
                C(
                    D("\nAs it stands, your Invariant cannot be confronted with the code for the array {}.\n"
                      .format(name)))
                malus += 1

            return malus

        # Variable parcourant A
        grade -= check_init("A", '0')

        # Variable parcourant B
        grade -= check_init("B", '0')

        # Variable parcourant C
        grade -= check_init("C", '0')

        return (grade / TOTAL, coms)