// Numbas version: exam_results_page_options {"name": "Spreadsheets extension", "metadata": {"description": "

Several questions demonstrating the spreadsheets extension

", "licence": "Creative Commons Attribution 4.0 International"}, "duration": 0, "percentPass": "0", "showQuestionGroupNames": false, "shuffleQuestionGroups": false, "showstudentname": true, "question_groups": [{"name": "Group", "pickingStrategy": "all-ordered", "pickQuestions": 1, "questionNames": ["", "", "", "", "", "", ""], "variable_overrides": [[], [], [], [], [], [], []], "questions": [{"name": "Product fact sheet", "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": "A spreadsheet 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}, "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/"}], "tags": [], "metadata": {"description": "

Using some passages of text, fill in a product fact sheet.

\n

A simple example showing how to mark entries in a spreadsheet.

", "licence": "Creative Commons Attribution 4.0 International"}, "statement": "

You're considering buying a new {product_name}. The manufacturer's website contains the following information:

\n
\n

The new {product_name} does everything you need it do. Drawing only {electricity_use}W, it uses much less electricity than most towns. And invention fluid use is lower than ever, at a mere {fluid_use}ml per hour.

\n

Measuring {dimensions[0]}×{dimensions[1]}×{dimensions[2]}cm, where can't you put it?

\n

Priced affordably at {currency(price,\"£\",\"p\")}, get one today!

\n
\n

You also found some reviews online:

\n

{reviews_table}

\n

One review noted that each {product_name} incurs {currency(externalised_costs,\"£\",\"p\")} in externalised costs.

", "advice": "", "rulesets": {}, "builtin_constants": {"e": true, "pi,\u03c0": true, "i": true}, "constants": [], "variables": {"raw_spreadsheet": {"name": "raw_spreadsheet", "group": "Spreadsheet", "definition": "spreadsheet_from_base64_file(safe(\"product-fact-sheet.xlsx\"), safe(\"UEsDBBQACAgIAJp0uVYAAAAAAAAAAAAAAAALAAAAX3JlbHMvLnJlbHOtks9KAzEQh+99ipB7d7YVRGSzvYjQm0h9gJjM/mE3mTAZdX17gwhaqaUHj0l+8803Q5rdEmb1ipxHikZvqlorjI78GHujnw736xu9a1fNI85WSiQPY8qq1MRs9CCSbgGyGzDYXFHCWF464mClHLmHZN1ke4RtXV8D/2To9oip9t5o3vuNVof3hJewqetGh3fkXgJGOdHiV6KQLfcoRi8zvBFPz0RTVaAaTrtsL3f5e04IKNZbseCIcZ24VLOMmL91PLmHcp0/E+eErv5zObgIRo/+vJJN6cto1cDRJ2g/AFBLBwhmqoK34AAAADsCAABQSwMEFAAICAgAmnS5VgAAAAAAAAAAAAAAAA8AAAB4bC93b3JrYm9vay54bWyNU8lu2zAQvfcrBN5tLV5qG5YDV46QAN0Qp8mZkkYWa4oUyPGWov/eEWWlKdpDDzY5C9+8mXla3pxr6R3BWKFVzMJhwDxQuS6E2sXs22M6mDHPIlcFl1pBzC5g2c3q3fKkzT7Teu/Re2VjViE2C9+3eQU1t0PdgKJIqU3NkUyz821jgBe2AsBa+lEQTP2aC8U6hIX5HwxdliKHjc4PNSjsQAxIjsTeVqKxbLUshYSnriGPN81nXhPthMuc+atX2l+Nl/F8f2hSyo5ZyaUFarTSpy/Zd8iROuJSMq/gCOE8GPcpf0BopEwqQ87W8STgZH/HW9Mh3mkjXrRCLre50VLGDM3hWo2Iosj/Fdm2g3rkme2d52ehCn2KGa3o8uZ+ctdnUWBFC5yOZuPedwdiV2HMZuE8Yh7y7KEdVMwmAT0rhbHoijgUTp0cgeq1FjXkv+nI7aw/PeUG6l6GLVU67wuq7HSCFDoKKzJJjM1CUMDcF5FD7GGo3ZzmLxAM5Sf6oIhC2HIyUH7SBUGsCe0af13O1d6ARE4kh0EQtrBwxo8W3XlVktR0/0tNUmQGOv04KTHvYETMfryfRtNkNo0G0TocDcLwdjL4MBpPBultmtLgkk0yT3+SrBzqgn5JR9+ioW/kAcrthVZ77iS2dpR8yur+HTO/V8TqF1BLBwiLeDPt9wEAAG4DAABQSwMEFAAICAgAmnS5VgAAAAAAAAAAAAAAAA0AAAB4bC9zdHlsZXMueG1s7Vvfj5tGEH7vX4F4b8DG5uzKdpTSUvWlipqLVKnqAzZrjLLsomWd2Pnru8saDPaOg39czndZ+wGYYWY+PmaG4Xw7ebvJsPUZsSKlZGr33ri2hciCxilJpvbHx/DnkW0VPCJxhClBU3uLCvvt7KdJwbcYfVghxC3hgRRTe8V5/ovjFIsVyqLiDc0REZolZVnExSFLnCJnKIoLaZRhp++6vpNFKbFnE7LOwowX1oKuCRcwapGlNn/GQugPbEu5C2gsoPyBCGIRtp3ZxNk5mE2WlOz9PNhKMJsUX63PERZOXHk6iTKkjt+xVHlYRlmKt0rYL10qwwvM3TsznysFZ2skdbU3/yIqIG+XEQt565/prdzI259i3L79QjCb5BHniJFQHFi7/cdtLnKIiKRWbsrzvnF2wqJtrz/sblBQnMYSRRJQTJnFkvnUDkPfD4IwlG7mbcVYfJTCafi8MprnSceaaK4bhjePJmNpry0InuDafi8/mmjyEwQ3v7YgcF0gmlJoo5UbkZ1zymLRaus2J/uckllxGiWURPhjPrWXES6QXYt+o19IJZxNMFpyEYelyUpuOc0lHMo5zcROZSORKM83jWCVbV/U60q07RuGO/TbiH2oelogVexD/98diJaRF47qGYA8ZW18p3AnauM5y+Fucu0sILsd0YsXCOMP0uCfZd2Q+66IvVkeD52kPBCzsWzku13laXcQ5TnehlQ6KWcZJfi1PKUleofThGTo4MT3jHK04OUMXopnk6g60VpRln4VruXMk+xmXjmy83QhReribYujDf+b8kh5EZi+sCh/FMKa65TEZWChK1YsJZ8eaZjWakFTXsOwMF18QnEFcpXGwrRxprNZHjDl7nnqXcrTDuchUU1xk6kqW14OmL4BA4C5uLYMGAPGgDFgDJhLwAy8e3pSDnp3hWZwV2j694Rm/MxgnOb4rob55hw/vHSO3yyPoTcBXYn9pQ31LdoGAG09PW3Xvged5mwhBIjdO2XDPWX9JmX956CsfIG+d8ZcgDGve23qKXvVpdnIM8/k2Zl55pk868qav2dt0GRtYB4BHSgbNikbGso6dLNWlvmmm327m7UYezDdrFuetUpzZErzXMrMO8DZlI0NZR3aWZfC7N7OfkDOgMo0nJ3gDChNw9mJ4awH/PXMTGfgdHZ1mr3q6azx4uSbd81za9O/5YvTq84zFyCtez8Dfgx4xYkGcQa8b5rahGvz6ufmD1mcZqo9nzMz1Tq734kb//1Z/2bs2w2pJZeeTO2/5Goj3KBtvk4xT4k6co4NApplUXV+b9gy8EAD61/3v9rIbxn5WqM1Y4gstrXNQ8tmcMqmFWvUsnvQ2b1HTN7B2mTcMlFLYfZkCnu5LEJs5a3boDjYHbJkfrD0RH7Kf+s90OxXdBxqlJVOIxeyQBqp03uDbJQ/KI5eMwKvx3VHoEbq9N4gmxFoI+V6TeDKLxRHb7NfiHSs8TzfhxhVS26OEAQQb77vupA3CJu0gOJU66q6cw3fbThDTucBdE9PZQh0pXAmQlcKcy01et7Uqi39/YHi7Nd5HceBNEqn08ic0tvsV68dZ2K1GksXB9KMx5BG5qKeA98HEPjyq78/UJV43nis10gbPQLPgzSyGmENhEBigDRe+ZxyDvq3U/V1Z7/wd/Y/UEsHCNoI783aBAAAPTwAAFBLAwQUAAgICACadLlWAAAAAAAAAAAAAAAAGAAAAHhsL3dvcmtzaGVldHMvc2hlZXQxLnhtbL1XTW/bOBC9768QdOhpa1myHX/UdpHY8bZAmgRJugX2RkuURYQSVZKym/z6HX5IouVsECyK9JBKj8PhvDek/Dj//Cun3h5zQVix8MNe3/dwEbOEFLuF//1h83Hie0KiIkGUFXjhP2Hhf17+MT8w/igyjKUHCQqx8DMpy1kQiDjDORI9VuICRlLGcyThle8CUXKMEj0pp0HU758FOSKFbzLM+FtysDQlMV6zuMpxIU0SjimSUL7ISCnqbL+SN+VLODoA1boep8S1GWnyhcOTfDmJORMslb2Y5ba0U5bTYHrEM4/fUliO+GNVfoTEJZDbEkrkk67RX8518lvupYRKzL+xBPqSIiowjJVoh++x/F7qcfnAbgGoh4PlPLCTl/OEgISq7R7H6cI/D2ebqYrQAX8TfBDOsycydthAfRVFok6nwb84Sa5IgQGVvLLgHTusGP0CQsDOcgf+waBYDXCyy6DCK5zKJqVE23tMcSxx4s67qSSFRe6f8i2jTYIEp6iiUpUAyzFe43uoeOEXSk4KKVmpllhhShVN34tV7FfIfzb0vWfG8vsYURBp0nder/XsDqjEvEJPrNKiwHnpw6g6ClvGHhWksvZVizQHJW6J1LGxNfgeAnSPbS0D991M9cRP045B2y2V2H2uG7PR+wUabXUADX6QRGZQV9gbDUbh6CwaNSpBT75gpTgMRz041s/Qixqx6jMj8xXeYwrxuiAXgxUMv+CoAFvPGkm0nHN28KATSudKSJaboGYJvf60N4YnkiS4aAZM9CsF6WqgdxSVQu2OesvHajnVV6FXhckC0P2yPw/2UGlsIy7qiMACqy6w7gKXXWDjAAEQbdhGr7Ed/W6uka4icriGHa4mYtByNcDQmRIdT1mbiFFL3gBnzpTB8ZRNHdFVY/Cuagx0FWOnzmFHjTqiUaMLXBpg4uQYdbiaiOkJ1+FrXPU5+71sh2YH9p1Szzp0bYh7FsbHISsb4m6hyXHI5fBEkmlHkuF/SDJ6Z0lGhky72y8sMmw7bhFne1vE3d9h55OxsTHjE4rjd93hY1OG24uwe+KbmIbyCbJ2kSM6k3fu2MQUMnUJdb5HFyYmcjd62PkArV6K6Rz+tY1xT0PYHu4jGabvLMPUlHb0Ie8eZhvjfMpPkLVFhm1fA+cHOcd8px2GgEqqQqpvloO29k//rHXwy2gGn/lT/HwwWw1ewseztTku7bLgSjkp5E2pXbqXgS0EZ93ayF1rIbsIWNna1GWMk2dWSERXYP0xb+VU9xdJ4tOBwPjhb4jvCCxMtdHs98aT8ci6z/YVHJq+/4yicfMPGr5lEjr80kim3W2bIGVMOu9B48WrEkxgifk9ecZ6jwljN7V51B69dm32tbFpvqdS3HC9TsIOxUOGixtgC5uMEyCr7z0Lv2RcckTAXm4pih/Pi+RHRmRj+z245TgWO4aerFiuLlBCueQCq3W5kMrdXlf5Fhv7Vgm86cLdVqxLAj/3ikjdgxaJWUlw7ZaMWhutkZeQNIU+FVLnb8us4Zskudy3x2w5Z0liLhPLDygvP6303w8/KyY/PcA1RnjXcEW5Yzkq/rzDO7ijcDOo48JI/3c+D9o0KqMp5v9lVJp4+vlWp7W55oHLE16ba/LyX1BLBwgliv9CxQQAAGoPAABQSwMEFAAICAgAmnS5VgAAAAAAAAAAAAAAABoAAAB4bC9fcmVscy93b3JrYm9vay54bWwucmVsc62RTWvDMAyG7/0VRvfFSQdjjDi9jEGv/fgBxlHi0MQ2kta1/34uG1sKZezQk9DX875I9eo0jeqIxEMMBqqiBIXBxXYIvYH97u3hGVbNot7gaCWPsB8Sq7wT2IAXSS9as/M4WS5iwpA7XaTJSk6p18m6g+1RL8vySdOcAc0VU61bA7RuK1C7c8L/sGPXDQ5fo3ufMMgNCc1yHpEz0VKPYuArLzIH9G355T3lPyId2CPKr4OfUjZ3CdVfZh7vegtvCdutUH7s/CTz8reZRa2v3t18AlBLBwhP8Pl60gAAACUCAABQSwMEFAAICAgAmnS5VgAAAAAAAAAAAAAAABQAAAB4bC9zaGFyZWRTdHJpbmdzLnhtbI2Tz04DIRDG7z4F4VQPlupBTbO7TdT652JM1fRMYNolgWFlhrV9Ht/EJ5PWRK9cSIDfN9/Ml0yz2AUvRkjkIrbyfDqTAtBE63Dbyve3+7NrKYg1Wu0jQiv3QHLRnTRELIoUqZU98zBXikwPQdM0DoDlZxNT0FyuaatoSKAt9QAcvLqYzS5V0A6lMDEjF9srKTK6jwy3fw9dQ65rjiZzGrQp3qUKQRpBdi8p2mxYbHQ5jnUbxV2jDpIKGeoA80qFM5XoKiOW1MpMxFSluHMB8BB8Hb70YLj043gvMoGYrE+rdGtnua9rCIZK8hHctq8L/QlHQC5Tio3PzopJ8HV9L3cMCbV3BPY3VTH5/qrTrmB08FmX66uJCarIG22ruGfInLSvYh9irCt6XI1/UpUN7H4AUEsHCLY0sqwxAQAAvwMAAFBLAwQUAAgICACadLlWAAAAAAAAAAAAAAAAEQAAAGRvY1Byb3BzL2NvcmUueG1sjVLLTsMwELzzFZHvifNQKhQlqVRQuVAJiSIQN2NvU0PsWLbbtH+PkzRpgR6QfNidGc/uep3PD6L29qANb2SBoiBEHkjaMC6rAr2sl/4t8owlkpG6kVCgIxg0L29yqjLaaHjSjQJtORjPGUmTUVWgrbUqw9jQLQhiAqeQjtw0WhDrUl1hRegXqQDHYTjDAixhxBLcGfpqckQnS0YnS7XTdW/AKIYaBEhrcBRE+Ky1oIW5eqFnLpSC26OCq9KRnNQHwydh27ZBm/RS13+E31aPz/2oPpfdU1FAZX5qJKMaiAXmOYNsKDcyr8nd/XqJyjiMEz9M/ThdR2kWh+685/jX/c5wiBtdduw5cTEDQzVX1u1wIH8ALq+JrHbuwUuQ/sOil0xQt8qaGLtyS99wYIuj87iCjR2JE/bvkZJZlsYXI40GfWUNe979vTLti05p17XZfXwCtcNIU+Jiy20NAzyGf/5j+Q1QSwcIZcJtNGQBAADbAgAAUEsDBBQACAgIAJp0uVYAAAAAAAAAAAAAAAAQAAAAZG9jUHJvcHMvYXBwLnhtbJ2QTW/CMAyG7/sVVcS1TVu2glAatGnaCWk7dGi3KktcyJQvJSkq/34BNOA8n+zX1mP7JetJq+wAPkhrWlQVJcrAcCuk2bXos3vLlygLkRnBlDXQoiMEtKYP5MNbBz5KCFkimNCifYxuhXHge9AsFKltUmewXrOYSr/Ddhgkh1fLRw0m4rosGwxTBCNA5O4KRBfi6hD/CxWWn+4L2+7oEo+SDrRTLAIl+JZ2NjLVSQ20apJ+rcizc0pyFpMldCO/Pbyfd+BFMS8WRT3bSDNO/dey6ZvH7G6gTz/8AI94Xs5eRqlEXhN8DzuRtxevafVUlCnOA38awTdb6S9QSwcICmNv0PoAAACbAQAAUEsDBBQACAgIAJp0uVYAAAAAAAAAAAAAAAATAAAAW0NvbnRlbnRfVHlwZXNdLnhtbL1UO0/DMBDe+ysiryh2y4AQStqBxwiVKDMy8SUxjR+y3dL+e84pVFUJKYiIybLvvpdPdjbbqCZZg/PS6JxM6JgkoAsjpK5y8rS4Sy/JbDrKFlsLPsFe7XNSh2CvGPNFDYp7aixorJTGKR5w6ypmebHkFbDz8fiCFUYH0CENkYNMsxso+aoJye0Gj3e6CCfJ9a4vSuWEW9vIggcss1hlnTgHje8BrrU4cpd+OKOIbHt8La0/+17B6upIQKqYLJ53I14tdEPaAmIe8LqdFJDMuQv3XGEDe45JGB04T5fSpmFvxi1fjFnS/mvvUDNlKQsQplgphFBvHXDha4CgGtquVHGpT+j7sG3AD63ekv4geQvwrF0mA5vY85/wsRv34Rz+afS+5g7EY3D4vgefwCF3nw/Ez52xHn8GB7838Zk7olOLROCC7B/9XhGp/5wa4lsXIL5qjzLWfpTTd1BLBwiP9uU2WQEAAFcFAABQSwECFAAUAAgICACadLlWZqqCt+AAAAA7AgAACwAAAAAAAAAAAAAAAAAAAAAAX3JlbHMvLnJlbHNQSwECFAAUAAgICACadLlWi3gz7fcBAABuAwAADwAAAAAAAAAAAAAAAAAZAQAAeGwvd29ya2Jvb2sueG1sUEsBAhQAFAAICAgAmnS5VtoI783aBAAAPTwAAA0AAAAAAAAAAAAAAAAATQMAAHhsL3N0eWxlcy54bWxQSwECFAAUAAgICACadLlWJYr/QsUEAABqDwAAGAAAAAAAAAAAAAAAAABiCAAAeGwvd29ya3NoZWV0cy9zaGVldDEueG1sUEsBAhQAFAAICAgAmnS5Vk/w+XrSAAAAJQIAABoAAAAAAAAAAAAAAAAAbQ0AAHhsL19yZWxzL3dvcmtib29rLnhtbC5yZWxzUEsBAhQAFAAICAgAmnS5VrY0sqwxAQAAvwMAABQAAAAAAAAAAAAAAAAAhw4AAHhsL3NoYXJlZFN0cmluZ3MueG1sUEsBAhQAFAAICAgAmnS5VmXCbTRkAQAA2wIAABEAAAAAAAAAAAAAAAAA+g8AAGRvY1Byb3BzL2NvcmUueG1sUEsBAhQAFAAICAgAmnS5Vgpjb9D6AAAAmwEAABAAAAAAAAAAAAAAAAAAnREAAGRvY1Byb3BzL2FwcC54bWxQSwECFAAUAAgICACadLlWj/blNlkBAABXBQAAEwAAAAAAAAAAAAAAAADVEgAAW0NvbnRlbnRfVHlwZXNdLnhtbFBLBQYAAAAACQAJAD8CAABvFAAAAAA=\"))", "description": "", "templateType": "spreadsheet", "can_override": false}, "filled_spreadsheet": {"name": "filled_spreadsheet", "group": "Completed spreadsheet", "definition": "raw_spreadsheet\n|> fill_range(\"B2\",[[product_name]])\n|> fill_range(\"D2\", [[price]])\n|> fill_range(\"F3:F6\", [[electricity_use],[fluid_use],[externalised_costs]])\n|> fill_range(\"A5:C5\", [dimensions])\n|> fill_range(\"B9:D9\", [review_counts])", "description": "", "templateType": "anything", "can_override": false}, "product_names": {"name": "product_names", "group": "Data", "definition": "[ \"Whizzo 3\", \"The New Gloop\", \"Vwlr\", \"Crumpetron\", \"Autocomb Pro\" ]", "description": "", "templateType": "list of strings", "can_override": false}, "product_name": {"name": "product_name", "group": "Data", "definition": "random(product_names)", "description": "", "templateType": "anything", "can_override": false}, "dimensions": {"name": "dimensions", "group": "Data", "definition": "repeat(random(10..100#5),3)", "description": "", "templateType": "anything", "can_override": false}, "electricity_use": {"name": "electricity_use", "group": "Data", "definition": "random(10..200#5)", "description": "", "templateType": "anything", "can_override": false}, "fluid_use": {"name": "fluid_use", "group": "Data", "definition": "random(300..900#10)", "description": "", "templateType": "anything", "can_override": false}, "externalised_costs": {"name": "externalised_costs", "group": "Data", "definition": "random(1000..9000#100)", "description": "", "templateType": "anything", "can_override": false}, "price": {"name": "price", "group": "Data", "definition": "random(59..409#10)", "description": "", "templateType": "anything", "can_override": false}, "individual_reviews": {"name": "individual_reviews", "group": "Data", "definition": "repeat(random(scores),5)", "description": "", "templateType": "anything", "can_override": false}, "all_reviewers": {"name": "all_reviewers", "group": "Data", "definition": "[ \"Invention Review\", \"Product Quarterly\", \"Whence Gizmos\", \"Doodads Today\", \"That Thingamajig\", \"Contraption Action\" ]", "description": "", "templateType": "list of strings", "can_override": false}, "reviewers": {"name": "reviewers", "group": "Data", "definition": "shuffle(all_reviewers)", "description": "", "templateType": "anything", "can_override": false}, "reviews_table": {"name": "reviews_table", "group": "Data", "definition": "table(zip(reviewers,individual_reviews),[\"Reviewer\",\"Score\"])", "description": "", "templateType": "anything", "can_override": false}, "review_counts": {"name": "review_counts", "group": "Data", "definition": "map(len(filter(x=score,x,individual_reviews)),score,scores)", "description": "", "templateType": "anything", "can_override": false}, "scores": {"name": "scores", "group": "Data", "definition": "[ \"Bad\", \"Neutral\", \"Good\" ]", "description": "", "templateType": "list of strings", "can_override": false}}, "variablesTest": {"condition": "", "maxRuns": 100}, "ungrouped_variables": [], "variable_groups": [{"name": "Spreadsheet", "variables": ["raw_spreadsheet"]}, {"name": "Data", "variables": ["product_names", "product_name", "dimensions", "electricity_use", "fluid_use", "externalised_costs", "price", "scores", "individual_reviews", "all_reviewers", "reviewers", "reviews_table", "review_counts"]}, {"name": "Completed spreadsheet", "variables": ["filled_spreadsheet"]}], "functions": {}, "preamble": {"js": "", "css": ""}, "parts": [{"type": "spreadsheet", "useCustomName": false, "customName": "", "marks": "11", "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

Before making a purchase, you always fill in a product fact sheet. Fill in the product fact sheet for the {product_name}, using the information above.

", "settings": {"initial_sheet": "raw_spreadsheet", "correct_answer": "filled_spreadsheet", "disable_ranges": "[\"A1:F1\", \"A2\",\"C2\",\"E2:F2\",\"A3:C3\",\"A4:C4\",\"E3:E5\",\"A7:D8\",\"A8:A9\"]", "mark_ranges": "[\n \"Product name\": \"B2\",\n \"Price\": \"D2\",\n \"Running costs\": \"F3:F5\",\n \"Dimensions\": \"A5:C5\",\n \"Reviews\": \"B9:D9\"\n]", "marking_method": "per_cell", "tolerance": "0"}}], "partsMode": "all", "maxMarks": 0, "objectives": [], "penalties": [], "objectiveVisibility": "always", "penaltyVisibility": "always"}, {"name": "Fill in table of books per child", "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": "A spreadsheet 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}, "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/"}], "tags": [], "metadata": {"description": "

The student is shown a table with rows for each class in a school, and two columns of numbers: books, and children. They have to work out the column totals, and the number of books per child, and enter them in the table.

", "licence": "Creative Commons Attribution 4.0 International"}, "statement": "", "advice": "

For the totals on the bottom row, add up the numbers in each column:

\n

{highlighted_totals}

\n

To work out the books per child, divide Books by Children, and round down to the nearest whole number.

\n

For example, in {first_class_name}, the number of books per children is

\n

\\[ \\simplify[basic]{ {num_books[0]} / {num_children[0]}} \\approx \\var{floor(num_books[0]/num_children[0])} \\]

\n

{highlighted_books_per_child}

", "rulesets": {}, "builtin_constants": {"e": true, "pi,\u03c0": true, "i": true}, "constants": [], "variables": {"initial_spreadsheet": {"name": "initial_spreadsheet", "group": "Ungrouped variables", "definition": "disable_cells(fill_range(\n big_spreadsheet,\n \"B2:C6\",\n zip(map(string(x),x,num_books),map(string(x),x,num_children),map(dpformat(x,2),x,books_per_child))\n), [\"A1:D1\", \"A1:A7\", \"B2:C6\", \"D7\"])", "description": "", "templateType": "anything", "can_override": false}, "big_spreadsheet": {"name": "big_spreadsheet", "group": "Ungrouped variables", "definition": "spreadsheet_from_base64_file(safe(\"books-per-child.xlsx\"), safe(\"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\"))", "description": "", "templateType": "spreadsheet", "can_override": false}, "num_books": {"name": "num_books", "group": "Ungrouped variables", "definition": "repeat(random(60..200),5)", "description": "", "templateType": "anything", "can_override": false}, "num_children": {"name": "num_children", "group": "Ungrouped variables", "definition": "repeat(random(25..30),5)", "description": "", "templateType": "anything", "can_override": false}, "books_per_child": {"name": "books_per_child", "group": "Ungrouped variables", "definition": "map(floor(books/children),[books,children],zip(num_books,num_children))", "description": "", "templateType": "anything", "can_override": false}, "completed_spreadsheet": {"name": "completed_spreadsheet", "group": "Ungrouped variables", "definition": "initial_spreadsheet\n|> fill_range(\"B7:C7\",[map(string(sum(x)),x,[num_books,num_children])]) \n|> fill_range(\"D2:D6\", books_per_child)", "description": "", "templateType": "anything", "can_override": false}, "highlighted_totals": {"name": "highlighted_totals", "group": "Ungrouped variables", "definition": "initial_spreadsheet\n|> fill_range(\"B7:C7\",[map(string(sum(x)),x,[num_books,num_children])]) \n|> update_range(\"B7:C7\",bg_color(\"lightblue\"))", "description": "

For the advice section.

\n

The spreadsheet with the totals filled in and highlighted.

", "templateType": "anything", "can_override": false}, "highlighted_books_per_child": {"name": "highlighted_books_per_child", "group": "Ungrouped variables", "definition": "completed_spreadsheet\n|> update_range(\"D2:D6\", bg_color(\"lightblue\"))", "description": "

For the advice section.

\n

The completed spreadsheet with the entries in the \"books per child\" column highlighted.

", "templateType": "anything", "can_override": false}, "first_class_name": {"name": "first_class_name", "group": "Ungrouped variables", "definition": "big_spreadsheet[\"A2\"]", "description": "", "templateType": "anything", "can_override": false}}, "variablesTest": {"condition": "", "maxRuns": 100}, "ungrouped_variables": ["big_spreadsheet", "initial_spreadsheet", "completed_spreadsheet", "num_books", "num_children", "books_per_child", "highlighted_totals", "highlighted_books_per_child", "first_class_name"], "variable_groups": [], "functions": {}, "preamble": {"js": "", "css": ""}, "parts": [{"type": "spreadsheet", "useCustomName": false, "customName": "", "marks": "15", "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

Fill in this table. Round the \"books per child\" down to the nearest whole number.

", "settings": {"initial_sheet": "initial_spreadsheet", "correct_answer": "completed_spreadsheet", "disable_ranges": "[\"A1:D1\",\"A1:A7\",\"B2:C6\", \"D7\"]", "mark_ranges": "[\"Books per child\": \"D2:D6\", \"Total books\": \"B7\", \"Total children\": \"C7\"]", "marking_method": "per_range", "tolerance": "0"}}], "partsMode": "all", "maxMarks": 0, "objectives": [], "penalties": [], "objectiveVisibility": "always", "penaltyVisibility": "always"}, {"name": "Calculate areas of rooms in a house", "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": "A spreadsheet 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": [["question-resources/house-outline_nHd5Iw5.svg", "/srv/numbas/media/question-resources/house-outline_nHd5Iw5.svg"]], "navigation": {"allowregen": true, "showfrontpage": false, "preventleave": false, "typeendtoleave": false}, "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/"}], "tags": [], "metadata": {"description": "

The student is shown a diagram with measurements of rooms in a house. They have to enter the measurements in a spreadsheet, then the area of each room, and finally the total area of the house.

", "licence": "Creative Commons Attribution 4.0 International"}, "statement": "

A surveyor has measured the rooms in a house and produced the following drawing (not to scale):

\n

\"Plan

\n

Measurements are given in metres.

", "advice": "

First write in the dimensions given on the drawing:

\n

{update_range(dimensions_spreadsheet, \"B2:C6\", highlight_style)}

\n

Next, calculate the area of each room, by multiplying the width by the height. Round to the nearest cm2, or 0.0001 m2.

\n

{update_range(areas_spreadsheet, \"D2:D6\", highlight_style)}

\n

Then, add up the areas to find the total area:

\n

{update_range(filled_spreadsheet, \"D7\", highlight_style)}

", "rulesets": {}, "builtin_constants": {"e": true, "pi,\u03c0": true, "i": true}, "constants": [], "variables": {"dimensions_spreadsheet": {"name": "dimensions_spreadsheet", "group": "Spreadsheet", "definition": "fill_range(spreadsheet, \"B2:C6\", dimensions)", "description": "

The spreadsheet with the dimensions filled in but not the areas.

", "templateType": "anything", "can_override": false}, "spreadsheet": {"name": "spreadsheet", "group": "Spreadsheet", "definition": "disable_cells(raw_spreadsheet, [\"A1:D1\", \"A1:A7\", \"A7:C7\"])", "description": "", "templateType": "anything", "can_override": false}, "dimensions": {"name": "dimensions", "group": "Measurements", "definition": "[\n [x1+x2,y1],\n [x3,y1+y2+y3],\n [x1,y2],\n [x2,y2],\n [x1+x2,y3]\n]", "description": "", "templateType": "anything", "can_override": false}, "filled_spreadsheet": {"name": "filled_spreadsheet", "group": "Spreadsheet", "definition": "fill_range(areas_spreadsheet, \"D7\", [precround(total_area,4)])\n", "description": "

The completed spreadsheet, with the total area cell filled in.

", "templateType": "anything", "can_override": false}, "areas": {"name": "areas", "group": "Ungrouped variables", "definition": "map(x*y,[x,y],dimensions)", "description": "

The area of each room.

", "templateType": "anything", "can_override": false}, "names": {"name": "names", "group": "Ungrouped variables", "definition": "map(x[0],x,spreadsheet[\"A2:A6\"])", "description": "

Names of the rooms.

", "templateType": "anything", "can_override": false}, "dims": {"name": "dims", "group": "Ungrouped variables", "definition": "map(\"{dpformat(w,2)} \u00d7 {dpformat(h,2)}\",[w,h],dimensions)", "description": "

Strings describing the rooms' dimensions, to insert in the image.

", "templateType": "anything", "can_override": false}, "total_area": {"name": "total_area", "group": "Ungrouped variables", "definition": "sum(areas)", "description": "

The total area of the house.

", "templateType": "anything", "can_override": false}, "areas_spreadsheet": {"name": "areas_spreadsheet", "group": "Spreadsheet", "definition": "fill_range(dimensions_spreadsheet, \"D2:D6\", map(precround(x,4),x,areas))", "description": "

The spreadsheet with dimensions and areas filled in.

", "templateType": "anything", "can_override": false}, "highlight_style": {"name": "highlight_style", "group": "Ungrouped variables", "definition": "[\"style\": [\"fill\": [\"fgColor\": [\"rgb\": \"ccccff\"]]]]", "description": "

Style which fills in cells with a bright colour to highlight them.

", "templateType": "anything", "can_override": false}, "x1,x2,x3": {"name": "x1,x2,x3", "group": "Ungrouped variables", "definition": "repeat(random(1..2#0.01), 3)", "description": "

The three widths - the width of hallway 1, hallway 2, and the dining room.

", "templateType": "anything", "can_override": false}, "y1,y2,y3": {"name": "y1,y2,y3", "group": "Ungrouped variables", "definition": "repeat(random(1..2#0.01), 3)", "description": "

The three vertical measurements: kitchen, hallway, and living room.

", "templateType": "anything", "can_override": false}, "raw_spreadsheet": {"name": "raw_spreadsheet", "group": "Spreadsheet", "definition": "spreadsheet_from_base64_file(safe(\"room-areas.xlsx\"), safe(\"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\"))", "description": "", "templateType": "spreadsheet", "can_override": false}}, "variablesTest": {"condition": "", "maxRuns": 100}, "ungrouped_variables": ["x1,x2,x3", "y1,y2,y3", "names", "dims", "areas", "total_area", "highlight_style"], "variable_groups": [{"name": "Spreadsheet", "variables": ["raw_spreadsheet", "dimensions_spreadsheet", "spreadsheet", "dimensions_spreadsheet", "areas_spreadsheet", "filled_spreadsheet"]}, {"name": "Measurements", "variables": ["dimensions"]}], "functions": {}, "preamble": {"js": "", "css": ""}, "parts": [{"type": "spreadsheet", "useCustomName": false, "customName": "", "marks": "30", "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

Fill in this survey form. Give lengths in metres to the nearest centimetre, and areas in square metres to the nearest cm2.

", "settings": {"initial_sheet": "spreadsheet", "correct_answer": "filled_spreadsheet", "disable_ranges": "[\"A1:D1\", \"A1:A6\",\"A7:C7\"]", "mark_ranges": "[\"Dimensions\": \"B2:C6\", \"Areas\": \"D2:D6\", \"Total area\": \"D7\"]", "marking_method": "per_range", "tolerance": "0.01"}}], "partsMode": "all", "maxMarks": 0, "objectives": [], "penalties": [], "objectiveVisibility": "always", "penaltyVisibility": "always"}, {"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": "A spreadsheet 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}, "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/"}], "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.

\n

For 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": {}, "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"}, {"name": "Journey record", "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": "A spreadsheet 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}, "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/"}], "tags": [], "metadata": {"description": "

Given a data sheet with distances between cities and costs for different forms of transport, and some information about modes of transport used, fill in a form for a journey.

", "licence": "Creative Commons Attribution 4.0 International"}, "statement": "

{data_spreadsheet}

\n

You are travelling from {from} to {to}.

\n

You travel {distance_description}.

", "advice": "", "rulesets": {}, "builtin_constants": {"e": true, "pi,\u03c0": true, "i": true}, "constants": [], "variables": {"raw_spreadsheet": {"name": "raw_spreadsheet", "group": "Journey record form", "definition": "spreadsheet_from_base64_file(safe(\"journey.xlsx\"), safe(\"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\"))", "description": "", "templateType": "spreadsheet", "can_override": false}, "filled_spreadsheet": {"name": "filled_spreadsheet", "group": "Journey record form", "definition": "fill_range(\n fill_range(\n fill_range(raw_spreadsheet, \"B2:B3\", [from,to]),\n \"B6:E10\",\n list(transpose(matrix([mode_distances,journey_cost,journey_co2,journey_time])))\n ),\n \"B11:E11\",\n totals\n)", "description": "", "templateType": "anything", "can_override": false}, "from,to": {"name": "from,to", "group": "Ungrouped variables", "definition": "shuffle(cities)", "description": "", "templateType": "anything", "can_override": false}, "cities": {"name": "cities", "group": "Cities", "definition": "data_spreadsheet[\"B2:E2\"][0]", "description": "", "templateType": "anything", "can_override": false}, "cost_per_km": {"name": "cost_per_km", "group": "Costs", "definition": "map(precround(x,2),x,[\n random(0.5..1.5#0),\n random(0.2..1#0),\n random(0.5..3#0),\n 0,\n random(0.01..0.05#0),\n])", "description": "

The average cost per km of each mode of transport.

", "templateType": "anything", "can_override": false}, "co2_per_km": {"name": "co2_per_km", "group": "Costs", "definition": "map(precround(x,3),x,[\n random(0.15..0.2#0),\n random(0.1..0.15#0),\n random(0.03..0.06#0),\n 0,\n 0\n])", "description": "

The average CO2 emissions per km of each mode of transport.

", "templateType": "anything", "can_override": false}, "speed": {"name": "speed", "group": "Costs", "definition": "[\n random(45..115#5),\n random(30..80#5),\n random(90..210#5),\n random(3..6),\n random(25..40)\n]", "description": "

The average travel speed of each mode of transport.

", "templateType": "anything", "can_override": false}, "raw_data_spreadsheet": {"name": "raw_data_spreadsheet", "group": "Data spreadsheet", "definition": "spreadsheet_from_base64_file(safe(\"journey-data.xlsx\"), safe(\"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\"))", "description": "", "templateType": "spreadsheet", "can_override": false}, "data_spreadsheet": {"name": "data_spreadsheet", "group": "Data spreadsheet", "definition": "fill_range(raw_data_spreadsheet, \"B9:D13\", list(transpose(matrix([cost_per_km,co2_per_km,speed]))))", "description": "", "templateType": "anything", "can_override": false}, "distance": {"name": "distance", "group": "Distance travelled", "definition": "let(\n c1,indices(cities,from)[0],\n c2,indices(cities,to)[0],\n\n let(\n a,max(c1,c2),\n b,min(c1,c2),\n n,parsenumber(data_spreadsheet[\"{upper(letterordinal(a+1))}{b+3}\"],\"plain\"),\n \n if(isnan(n),0,n)\n )\n)", "description": "

The distance between the chosen cities.

", "templateType": "anything", "can_override": false}, "mode_distances": {"name": "mode_distances", "group": "Distance travelled", "definition": "let(\n num_modes, random(2..3),\n shuffle(random_integer_partition(distance,num_modes)+repeat(0,5-num_modes))\n)", "description": "", "templateType": "anything", "can_override": false}, "transport_modes": {"name": "transport_modes", "group": "Distance travelled", "definition": "map(x[0],x,raw_spreadsheet[\"A6:A10\"])", "description": "", "templateType": "anything", "can_override": false}, "distance_description": {"name": "distance_description", "group": "Distance travelled", "definition": "let(\n used_modes, filter(x[0]>0,x,zip(mode_distances, transport_modes)),\n texts, map(\"{d}km {lower(mode)}\",[d,mode], used_modes[0..len(used_modes)]),\n \n if(len(used_modes)>1,\n join(texts[0..-1], \", \")\n +\n \", and the rest \"+lower(used_modes[-1][1])\n ,\n texts[0]\n )\n)", "description": "", "templateType": "anything", "can_override": false}, "journey_cost": {"name": "journey_cost", "group": "Costs", "definition": "map(precround(d*c,2),[d,c],zip(mode_distances,cost_per_km))", "description": "

The incurred cost of each mode of transport.

", "templateType": "anything", "can_override": false}, "journey_co2": {"name": "journey_co2", "group": "Costs", "definition": "map(precround(d*c,3),[d,c],zip(mode_distances,co2_per_km))", "description": "", "templateType": "anything", "can_override": false}, "journey_time": {"name": "journey_time", "group": "Costs", "definition": "map(round(60*d/s),[d,s],zip(mode_distances,speed))", "description": "", "templateType": "anything", "can_override": false}, "totals": {"name": "totals", "group": "Costs", "definition": "map(precround(sum(l),2),l,[mode_distances,journey_cost,journey_co2,journey_time])", "description": "", "templateType": "anything", "can_override": false}}, "variablesTest": {"condition": "", "maxRuns": 100}, "ungrouped_variables": ["from,to"], "variable_groups": [{"name": "Data spreadsheet", "variables": ["raw_data_spreadsheet", "data_spreadsheet"]}, {"name": "Cities", "variables": ["cities"]}, {"name": "Costs", "variables": ["co2_per_km", "cost_per_km", "speed", "journey_cost", "journey_co2", "journey_time", "totals"]}, {"name": "Journey record form", "variables": ["raw_spreadsheet", "filled_spreadsheet"]}, {"name": "Distance travelled", "variables": ["mode_distances", "distance", "transport_modes", "distance_description"]}], "functions": {}, "preamble": {"js": "", "css": ""}, "parts": [{"type": "spreadsheet", "useCustomName": false, "customName": "", "marks": "26", "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

Using the data sheet above, fill in the journey record form below.

\n

Round costs to the nearest penny, CO2 emissions to the nearest gram, and time to the nearest minute.

", "settings": {"initial_sheet": "raw_spreadsheet", "correct_answer": "filled_spreadsheet", "disable_ranges": "[\"A1:D1\",\"A2:A3\",\"A4:D4\",\"A5:D5\", \"A5:A11\"]", "mark_ranges": "[\n \"From and To\": \"B2:B3\",\n \"Distance travelled\": \"B6:B10\",\n \"Cost\": \"C6:C10\",\n \"CO2 emissions\": \"D6:D10\",\n \"Time\": \"E6:E10\",\n \"Totals\": \"B11:E11\"\n]", "marking_method": "per_cell", "tolerance": "0.01"}}], "partsMode": "all", "maxMarks": 0, "objectives": [], "penalties": [], "objectiveVisibility": "always", "penaltyVisibility": "always"}, {"name": "PhET springs experiment", "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": "A spreadsheet 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}, "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/"}], "tags": [], "metadata": {"description": "

An experiment using a PhET applet. The student can attach masses of different weights to a spring, and is asked to measure and record how far it stretches. Their measurements are shown on a graph, and they're asked to estimate the formula for the length in terms of the mass.

", "licence": "Creative Commons Attribution 4.0 International"}, "statement": "

In this experiment you will establish a formula for how far a spring stretches when you attach a mass to it.

\n

\n

Select the Lab experiment.

\n

Choose the strength of your spring. Keep the strength the same throughout the experiment.

\n

Measure the difference between the unstretched length and the resting position for a variety of masses, and enter your measurements in the table below.

", "advice": "", "rulesets": {}, "builtin_constants": {"e": true, "pi,\u03c0": true, "i": true}, "constants": [], "variables": {"raw_spreadsheet": {"name": "raw_spreadsheet", "group": "Ungrouped variables", "definition": "spreadsheet_from_base64_file(safe(\"spring.xlsx\"), safe(\"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\"))", "description": "", "templateType": "spreadsheet", "can_override": false}, "blank_spreadsheet": {"name": "blank_spreadsheet", "group": "Ungrouped variables", "definition": "slice(raw_spreadsheet,\"A1:C6\")", "description": "

The spreadsheet with some rows added

", "templateType": "anything", "can_override": false}, "plot": {"name": "plot", "group": "Ungrouped variables", "definition": "jsxgraph(\n 600,600,[-25,110,310,-5],\n dict(map([\"p{i}\", [\"point\",[0,0], [\"id\": \"p{i}\", \"withLabel\": false]]],i,0..4)),\n [\"axes\":true]\n)", "description": "", "templateType": "anything", "can_override": false}, "k": {"name": "k", "group": "Ungrouped variables", "definition": "let(valid_entries, filter(not (isnan(x[0]) or isnan(x[1])), x, zip(masses,lengths)),\n sum(map(l/m, [m,l], valid_entries))/len(valid_entries)\n)", "description": "", "templateType": "anything", "can_override": false}, "masses": {"name": "masses", "group": "Ungrouped variables", "definition": "map(parsenumber(x,\"plain\"),[x],filled_spreadsheet[\"A2:A6\"])", "description": "", "templateType": "anything", "can_override": false}, "lengths": {"name": "lengths", "group": "Ungrouped variables", "definition": "map(parsenumber(x,\"plain\"),[x],filled_spreadsheet[\"B2:B6\"])", "description": "", "templateType": "anything", "can_override": false}, "filled_spreadsheet": {"name": "filled_spreadsheet", "group": "Ungrouped variables", "definition": "fill_range(blank_spreadsheet, \"A2:C6\",\n [\n [\"6\",\"1\", \"0.1666\"],\n [\"12\",\"2\", \"0.1666\"],\n [\"18\",\"3\", \"0.1666\"],\n [\"24\",\"4\", \"0.1666\"],\n [\"30\",\"5\", \"0.1666\"],\n ]\n)", "description": "", "templateType": "anything", "can_override": false}}, "variablesTest": {"condition": "", "maxRuns": 100}, "ungrouped_variables": ["raw_spreadsheet", "blank_spreadsheet", "plot", "filled_spreadsheet", "masses", "lengths", "k"], "variable_groups": [], "functions": {}, "preamble": {"js": "", "css": "iframe.phet {\n width: 100%;\n height: 80vh;\n}"}, "parts": [{"type": "spreadsheet", "useCustomName": false, "customName": "", "marks": "0", "scripts": {}, "customMarkingAlgorithm": "masses: map(parsenumber(x,\"plain\"),[x],studentAnswer[\"A2:A6\"])\n\nlengths: map(parsenumber(x,\"plain\"),[x],studentAnswer[\"B2:B6\"])\n\npoints: map(plot[\"p{i}\"], i, 0..4)\n\npositions:\n map(vector(mass,length), [mass, length], filter(not (isnan(x[0]) or isnan(x[1])), x, zip(masses,lengths)))\n\njxg_input:\n flatten(map(\n [ jxg_show(p,not (isnan(mass) or isnan(length))),\n jxg_set_position(p, vector(mass, length))\n ],\n [p,mass,length],\n zip(points, masses, lengths)\n ))", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": false, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "settings": {"initial_sheet": "blank_spreadsheet", "correct_answer": "blank_spreadsheet", "disable_ranges": "[\"A1:C1\"]", "mark_ranges": "dict()", "marking_method": "per_cell", "tolerance": "0"}}, {"type": "information", "useCustomName": false, "customName": "", "marks": 0, "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

{plot}

"}, {"type": "gapfill", "useCustomName": false, "customName": "", "marks": 0, "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [{"variable": "filled_spreadsheet", "part": "p0", "must_go_first": true}], "variableReplacementStrategy": "alwaysreplace", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

Write a formula for the length, $l$, in terms of the mass, $m$

\n

$l = $ [[0]]

", "gaps": [{"type": "jme", "useCustomName": false, "customName": "", "marks": 1, "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "answer": "{k}*m", "answerSimplification": "fractionnumbers", "showPreview": true, "checkingType": "absdiff", "checkingAccuracy": 0.001, "failureRate": 1, "vsetRangePoints": 5, "vsetRange": [0, 1], "checkVariableNames": false, "singleLetterVariables": false, "allowUnknownFunctions": true, "implicitFunctionComposition": false, "caseSensitive": false, "valuegenerators": [{"name": "m", "value": ""}]}], "sortAnswers": false}], "partsMode": "all", "maxMarks": 0, "objectives": [], "penalties": [], "objectiveVisibility": "always", "penaltyVisibility": "always"}, {"name": "Truth table", "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": "A spreadsheet 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}, "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/"}], "tags": [], "metadata": {"description": "

Fill in a truth table: the values for \"A\" and \"B\" are filled in, and the student has to work out \"A or B\" and then \"(A or B) implies B\".

", "licence": "Creative Commons Attribution 4.0 International"}, "statement": "", "advice": "

$A \\cup B$ is true if $A$ is true or $B$ is true, or both.

\n

So the corresponding column in the truth table is as follows:

\n

{filled_table_or}

\n

The third column combines $A \\cup B$ and $B$. Use the truth table for logical implication, $\\implies$:

\n

{implication_truth_table}

\n

The column $A \\cup B$ in our table corresponds to $A$ in the table for implication, and the column $B$ in our table corresponds to $B$ in the table for implication.

\n

So the completed truth table is as follows:

\n

{filled_table}

", "rulesets": {}, "builtin_constants": {"e": true, "pi,\u03c0": true, "i": true}, "constants": [], "variables": {"truth_table": {"name": "truth_table", "group": "Ungrouped variables", "definition": "spreadsheet([[\"A\", \"B\", \"A \u222a B\", \"(A \u222a B) \u27f9 B\"]])\n |> fill_range(\"A2:B5\", product([\"T\",\"F\"],2))\n |> update_range(\"A1:D1\", font_style(\"bold\") |> border(\"bottom\", \"thin\"))", "description": "", "templateType": "anything", "can_override": false}, "values": {"name": "values", "group": "Ungrouped variables", "definition": "product([true,false],2)", "description": "

The possible combinations of values of A and B.

", "templateType": "anything", "can_override": false}, "a_or_b": {"name": "a_or_b", "group": "Ungrouped variables", "definition": "map(a or b, [a,b], values)", "description": "", "templateType": "anything", "can_override": false}, "a_or_b_implies_b": {"name": "a_or_b_implies_b", "group": "Ungrouped variables", "definition": "map((a or b) implies b, [a,b], values)", "description": "", "templateType": "anything", "can_override": false}, "filled_table": {"name": "filled_table", "group": "Ungrouped variables", "definition": "truth_table\n |> fill_range(\"C2:D5\", map(map(if(x,\"T\",\"F\"),x,row),row,transpose([a_or_b, a_or_b_implies_b])))", "description": "", "templateType": "anything", "can_override": false}, "q": {"name": "q", "group": "Ungrouped variables", "definition": "map(a implies b, [a,b], values)", "description": "", "templateType": "anything", "can_override": false}, "implication_truth_table": {"name": "implication_truth_table", "group": "Ungrouped variables", "definition": "spreadsheet([[\"A\", \"B\", \"A \u27f9 B\"]])\n |> fill_range(\"A2:B5\", product([\"T\",\"F\"],2))\n |> update_range(\"A1:C1\", font_style(\"bold\") |> border(\"bottom\", \"thin\"))\n |> fill_range(\"C2:C5\", map(if(a implies b,\"T\",\"F\"), [a,b], product([true,false],2)))", "description": "

The truth table for the logical implication operator.

", "templateType": "anything", "can_override": false}, "filled_table_or": {"name": "filled_table_or", "group": "Ungrouped variables", "definition": "truth_table\n |> fill_range(\"C2:C5\", map(if(x,\"T\",\"F\"),x,a_or_b))\n |> update_range(\"C2:C5\", bg_color(\"lightblue\"))", "description": "

The truth table with the $A \\cup B$ column filled in.

", "templateType": "anything", "can_override": false}}, "variablesTest": {"condition": "", "maxRuns": 100}, "ungrouped_variables": ["truth_table", "values", "a_or_b", "a_or_b_implies_b", "filled_table", "q", "implication_truth_table", "filled_table_or"], "variable_groups": [], "functions": {}, "preamble": {"js": "", "css": ""}, "parts": [{"type": "spreadsheet", "useCustomName": false, "customName": "", "marks": "8", "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

Fill in this truth table.

", "settings": {"initial_sheet": "truth_table", "correct_answer": "filled_table", "disable_ranges": "[\"A1:D1\", \"A1:B5\"]", "mark_ranges": "[\"A \u222a B\": \"C2:C5\", \"(A \u222a B) \u27f9 B\": \"D2:D5\"]", "marking_method": "per_cell", "tolerance": "0"}}], "partsMode": "all", "maxMarks": 0, "objectives": [], "penalties": [], "objectiveVisibility": "always", "penaltyVisibility": "always"}]}], "allowPrinting": true, "navigation": {"allowregen": true, "reverse": true, "browse": true, "allowsteps": true, "showfrontpage": false, "showresultspage": "oncompletion", "navigatemode": "menu", "onleave": {"action": "none", "message": ""}, "preventleave": true, "startpassword": "", "allowAttemptDownload": false, "downloadEncryptionKey": ""}, "timing": {"allowPause": true, "timeout": {"action": "none", "message": ""}, "timedwarning": {"action": "none", "message": ""}}, "feedback": {"showactualmark": true, "showtotalmark": true, "showanswerstate": true, "allowrevealanswer": true, "advicethreshold": 0, "intro": "

The spreadsheets extension allows you to display and manipulate tables of data in a Numbas question.

\n

The \"Spreadsheet\" custom part type asks the student to fill in a given spreadsheet, and you can mark the completed spreadsheet.

", "end_message": "", "reviewshowscore": true, "reviewshowfeedback": true, "reviewshowexpectedanswer": true, "reviewshowadvice": true, "feedbackmessages": []}, "diagnostic": {"knowledge_graph": {"topics": [], "learning_objectives": []}, "script": "diagnosys", "customScript": ""}, "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/"}], "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": "A spreadsheet 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": [["question-resources/house-outline_nHd5Iw5.svg", "/srv/numbas/media/question-resources/house-outline_nHd5Iw5.svg"]]}