// Numbas version: finer_feedback_settings {"name": "Construct a spreadsheet from scratch", "extensions": ["jsxgraph", "sheets"], "custom_part_types": [{"source": {"pk": 242, "author": {"name": "Christian Lawson-Perfect", "pk": 7}, "edit_page": "/part_type/242/edit"}, "name": "Spreadsheet", "short_name": "spreadsheet", "description": "
An editable spreadsheet. Ranges of cells can be disabled, and you can specify ranges of cells to be marked. A cell is marked correct if its value is equal to the value in the expected answer spreadsheet.
", "help_url": "", "input_widget": "spread-sheet", "input_options": {"correctAnswer": "settings[\"correct_answer\"]", "hint": {"static": true, "value": ""}, "initial_sheet": {"static": false, "value": "disable_cells(settings[\"initial_sheet\"], settings[\"disable_ranges\"])"}}, "can_be_gap": true, "can_be_step": true, "marking_script": "correctAnswer:\nsettings[\"correct_answer\"]\n\nmark:\nif(sum(mark_ranges)=0,\n incorrect(),\n apply(mark_ranges)\n)\n\ninterpreted_answer:\nstudentAnswer\n\nrange_cells:\nmap(parse_range(ref),ref,values(settings[\"mark_ranges\"]))\n\ntotal_cells:\nlen(flatten(range_cells))\n\nrange_weights:\nswitch(\n settings[\"marking_method\"]=\"per_cell\",\n map(len(r)/total_cells, r, range_cells),\n // otherwise, mark per range\n repeat(1/len(range_cells), len(range_cells))\n)\n\nmark_ranges:\nmap(\n let(\n range_credit,\n sum(map(\n let(\n correctCellString, correctAnswer[c],\n correctCellNumber, parsenumber(correctCellString, notation_styles),\n studentCellString, studentAnswer[c],\n studentCellNumber, parsenumber(studentCellString, notation_styles),\n award(\n 1/len(cells), \n if(isnan(correctCellNumber) and correctCellString<>\"\",\n lower(correctCellString) = lower(studentCellString),\n abs(studentCellNumber - if(isnan(correctCellNumber),0,correctCellNumber)) <= settings[\"tolerance\"]\n )\n )\n ),\n c,\n cells\n )),\n message,\n switch(\n range_credit=0,\n if(len(cells)=1, \"This entry is incorrect.\", \"All entries in this range are incorrect.\"),\n range_credit=1,\n if(len(cells)=1, \"This entry is correct.\", \"All entries in this range are correct.\"),\n //otherwise\n \"Some entries in this range are correct.\"\n ),\n assert(len(cells)=0, add_credit(range_credit*w, \"{name}: \"+message)); \n range_credit\n ),\n [cells,w,name],\n zip(range_cells, range_weights, keys(settings[\"mark_ranges\"]))\n)\n\nnotation_styles:\n[\"plain\",\"si-en\"]", "marking_notes": [{"name": "correctAnswer", "description": "A spreadsheet representing the expected answer.
", "definition": "settings[\"correct_answer\"]"}, {"name": "mark", "description": "This is the main marking note. It should award credit and provide feedback based on the student's answer.", "definition": "if(sum(mark_ranges)=0,\n incorrect(),\n apply(mark_ranges)\n)"}, {"name": "interpreted_answer", "description": "A value representing the student's answer to this part.", "definition": "studentAnswer"}, {"name": "range_cells", "description": "For each range to be marked, the addresses of the cells in that range.
", "definition": "map(parse_range(ref),ref,values(settings[\"mark_ranges\"]))"}, {"name": "total_cells", "description": "The total number of cells to be marked. Cells in overlapping ranges will be counted once for each range they're in.
", "definition": "len(flatten(range_cells))"}, {"name": "range_weights", "description": "The weight of each range, as a proportion of the available credit.
", "definition": "switch(\n settings[\"marking_method\"]=\"per_cell\",\n map(len(r)/total_cells, r, range_cells),\n // otherwise, mark per range\n repeat(1/len(range_cells), len(range_cells))\n)"}, {"name": "mark_ranges", "description": "Mark each of the ranges specified by the question author.
", "definition": "map(\n let(\n range_credit,\n sum(map(\n let(\n correctCellString, correctAnswer[c],\n correctCellNumber, parsenumber(correctCellString, notation_styles),\n studentCellString, studentAnswer[c],\n studentCellNumber, parsenumber(studentCellString, notation_styles),\n award(\n 1/len(cells), \n if(isnan(correctCellNumber) and correctCellString<>\"\",\n lower(correctCellString) = lower(studentCellString),\n abs(studentCellNumber - if(isnan(correctCellNumber),0,correctCellNumber)) <= settings[\"tolerance\"]\n )\n )\n ),\n c,\n cells\n )),\n message,\n switch(\n range_credit=0,\n if(len(cells)=1, \"This entry is incorrect.\", \"All entries in this range are incorrect.\"),\n range_credit=1,\n if(len(cells)=1, \"This entry is correct.\", \"All entries in this range are correct.\"),\n //otherwise\n \"Some entries in this range are correct.\"\n ),\n assert(len(cells)=0, add_credit(range_credit*w, \"{name}: \"+message)); \n range_credit\n ),\n [cells,w,name],\n zip(range_cells, range_weights, keys(settings[\"mark_ranges\"]))\n)"}, {"name": "notation_styles", "description": "Accepted number notation styles for a value in an individual cell.
", "definition": "[\"plain\",\"si-en\"]"}], "settings": [{"name": "initial_sheet", "label": "Initial sheet", "help_url": "", "hint": "Aspreadsheet
object giving the initial state of the sheet that the student should fill in.", "input_type": "code", "default_value": "", "evaluate": true}, {"name": "correct_answer", "label": "Correct answer", "help_url": "", "hint": "A spreadsheet
object representing a correct answer to the part.", "input_type": "code", "default_value": "", "evaluate": true}, {"name": "disable_ranges", "label": "Ranges to disable", "help_url": "", "hint": "A list of cell or range references, denoting the cells that should not be editable.", "input_type": "code", "default_value": "[]", "evaluate": true}, {"name": "mark_ranges", "label": "Ranges to mark", "help_url": "", "hint": "A dictionary of cell or range references, mapping names to ranges of cells, denoting the cells that should be compared for equality with the expected answer.", "input_type": "code", "default_value": "dict()", "evaluate": true}, {"name": "marking_method", "label": "Marking method", "help_url": "", "hint": "", "input_type": "dropdown", "default_value": "per_cell", "choices": [{"value": "per_cell", "label": "Each cell has the same weight"}, {"value": "per_range", "label": "Each range has the same weight"}]}, {"name": "tolerance", "label": "Allowed margin of error", "help_url": "", "hint": "", "input_type": "code", "default_value": "0", "evaluate": true}], "public_availability": "always", "published": true, "extensions": ["sheets"]}], "resources": [], "navigation": {"allowregen": true, "showfrontpage": false, "preventleave": false, "typeendtoleave": false}, "question_groups": [{"pickingStrategy": "all-ordered", "questions": [{"name": "Construct a spreadsheet from scratch", "tags": [], "metadata": {"description": "Demonstrates how to construct a spreadsheet value from scratch, without uploading an .xlsx file.
", "licence": "Creative Commons Attribution 4.0 International"}, "statement": "Here is a score sheet from the local games league.
\n{spreadsheet}
", "advice": "To calculate points per second, divide score by time.
\nFor example, for person {spreadsheet[\"B1\"]}, the points per second is:
\n\\[ \\simplify[basic]{{scores[0]} / {times[0]} = {points_per_second[0]}} = \\var{precround(points_per_second[0],2)} \\text{ to 2 decimal places} \\]
", "rulesets": {}, "extensions": ["jsxgraph", "sheets"], "builtin_constants": {"e": true, "pi,\u03c0": true, "i": true}, "constants": [], "variables": {"spreadsheet": {"name": "spreadsheet", "group": "Ungrouped variables", "definition": "spreadsheet([[\"Person\",\"A\",\"B\",\"C\"], [\"Score\"]+scores, [\"Time\"]+times])\n |> update_range(\"A1:A3\", font_style(\"bold\") |> border(\"right\",\"thin\"))", "description": "", "templateType": "anything", "can_override": false}, "scores": {"name": "scores", "group": "Ungrouped variables", "definition": "repeat(random(1..10),3)", "description": "", "templateType": "anything", "can_override": false}, "times": {"name": "times", "group": "Ungrouped variables", "definition": "repeat(random(30..120#5),3)", "description": "", "templateType": "anything", "can_override": false}, "spreadsheet_to_fill": {"name": "spreadsheet_to_fill", "group": "Ungrouped variables", "definition": "spreadsheet\n |> fill_range(\"A4\", [\"Points per second\"])\n |> update_range(\"A4\", font_style(\"bold\") |> border(\"right\",\"thin\"))\n |> update_range(\"A4:D4\", border(\"top\",\"thin\"))", "description": "", "templateType": "anything", "can_override": false}, "points_per_second": {"name": "points_per_second", "group": "Ungrouped variables", "definition": "map(score/time, [score,time], zip(scores,times))", "description": "", "templateType": "anything", "can_override": false}, "filled_spreadsheet": {"name": "filled_spreadsheet", "group": "Ungrouped variables", "definition": "spreadsheet_to_fill\n |> fill_range(\"B4:D4\", [map(precround(x,2),x,points_per_second)])", "description": "", "templateType": "anything", "can_override": false}}, "variablesTest": {"condition": "", "maxRuns": 100}, "ungrouped_variables": ["scores", "times", "spreadsheet", "spreadsheet_to_fill", "points_per_second", "filled_spreadsheet"], "variable_groups": [], "functions": {}, "preamble": {"js": "", "css": ""}, "parts": [{"type": "spreadsheet", "useCustomName": false, "customName": "", "marks": "3", "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "Fill in the \"points per second\" row. Round values to 2 decimal places.
", "settings": {"initial_sheet": "spreadsheet_to_fill", "correct_answer": "filled_spreadsheet", "disable_ranges": "[\"A1:A4\", \"A1:D3\"]", "mark_ranges": "[ \"Points per second\": \"B4:D4\" ]", "marking_method": "per_cell", "tolerance": "0.005"}}], "partsMode": "all", "maxMarks": 0, "objectives": [], "penalties": [], "objectiveVisibility": "always", "penaltyVisibility": "always", "type": "question", "contributors": [{"name": "Christian Lawson-Perfect", "profile_url": "http://clppc:8000/accounts/profile/1/"}, {"name": "Christian Lawson-Perfect", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/7/"}]}]}], "contributors": [{"name": "Christian Lawson-Perfect", "profile_url": "http://clppc:8000/accounts/profile/1/"}, {"name": "Christian Lawson-Perfect", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/7/"}]}