{
  "title": "Pseudocode across exam boards: OCR, Cambridge 9618, AQA and Python",
  "description": "Every construct in the boards' own pseudocode documents, side by side with idiomatic Python. A null code value means the board's guide does not define that construct.",
  "url": "https://cambridgecomputersciencetutor.com/pseudocode-exam-boards",
  "author": "Junaid Khalid",
  "copyright": "Pseudocode syntax is transcribed from documents copyright Cambridge OCR, Cambridge University Press & Assessment and AQA, for teaching reference. Link to the page above when you reuse this file.",
  "boards": [
    {
      "id": "ocr",
      "name": "Cambridge OCR Exam Reference Language",
      "scope": "GCSE J277 and A Level H446"
    },
    {
      "id": "cie",
      "name": "Cambridge International 9618 pseudocode",
      "scope": "AS & A Level 9618, exams 2026 to 2029"
    },
    {
      "id": "aqa",
      "name": "AQA pseudo-code",
      "scope": "GCSE 8525 guide"
    },
    {
      "id": "py",
      "name": "Python 3",
      "scope": "Idiomatic equivalent"
    }
  ],
  "sources": [
    {
      "id": "j277",
      "title": "Cambridge OCR GCSE (9-1) Computer Science J277 specification",
      "version": "Version 3.1, May 2026. Section 3c, OCR Exam Reference Language",
      "url": "https://www.ocr.org.uk/images/558027-specification-gcse-computer-science-j277.pdf"
    },
    {
      "id": "h446",
      "title": "Cambridge OCR A Level Computer Science H446 specification",
      "version": "Version 3.0, April 2026. Appendix 5d, Pseudocode",
      "url": "https://www.ocr.org.uk/images/170844-specification-accredited-a-level-gce-computer-science-h446.pdf"
    },
    {
      "id": "cie",
      "title": "Cambridge International AS & A Level Computer Science 9618 Pseudocode Guide for Teachers",
      "version": "For examination in 2027, 2028 and 2029. Version 1, September 2024",
      "url": "https://www.cambridgeinternational.org/Images/721401-2027-2029-pseudocode-guide.pdf"
    },
    {
      "id": "cie2026",
      "title": "Cambridge International 9618 Pseudocode Guide for Teachers",
      "version": "For examination in 2026. Version 1, September 2023",
      "url": "https://www.cambridgeinternational.org/Images/697401-2026-pseudocode-guide-for-teachers.pdf"
    },
    {
      "id": "cieInsert",
      "title": "Cambridge International 9618/21 Insert",
      "version": "May/June 2024",
      "url": "https://www.cambridgeinternational.org/Images/673618-june-2024-insert-paper-21.pdf"
    },
    {
      "id": "cieEr24",
      "title": "Cambridge International 9618 Principal Examiner Report for Teachers",
      "version": "June 2024, Papers 21, 22 and 23",
      "url": "https://www.cambridgeinternational.org/Images/673617-june-2024-examiner-report.pdf"
    },
    {
      "id": "aqa",
      "title": "AQA GCSE Computer Science 8525 Notes and guidance: Pseudo-code",
      "version": "Copyright 2024, 15 pages",
      "url": "https://filestore.aqa.org.uk/resources/computing/AQA-8525-NG-PC.PDF"
    },
    {
      "id": "aqaSpec",
      "title": "AQA GCSE Computer Science 8525 specification",
      "version": "Version 1.3, 16 June 2025. GCSE exams June 2027 onwards",
      "url": "https://www.aqa.org.uk/filestore/resource/updated-gcse-computer-science-spec.pdf"
    },
    {
      "id": "aqa7517",
      "title": "AQA A-level Computer Science 7517/1 question paper",
      "version": "June 2022",
      "url": "https://filestore.aqa.org.uk/sample-papers-and-mark-schemes/2022/june/AQA-75171-QP-JUN22.PDF"
    },
    {
      "id": "aqa7517Spec",
      "title": "AQA AS and A-level Computer Science 7516/7517 specification",
      "version": "Version 1.6, 31 July 2023",
      "url": "https://www.aqa.org.uk/subjects/computer-science/a-level/computer-science-7517/specification"
    },
    {
      "id": "aqaEr22",
      "title": "AQA GCSE Computer Science 8525/1 Report on the Examination",
      "version": "June 2022",
      "url": "https://filestore.aqa.org.uk/sample-papers-and-mark-schemes/2022/june/AQA-85251-WRE-JUN22.PDF"
    },
    {
      "id": "aqaEr23",
      "title": "AQA GCSE Computer Science 8525/1A-C Report on the Examination",
      "version": "June 2023",
      "url": "https://filestore.aqa.org.uk/sample-papers-and-mark-schemes/2023/june/AQA-85251-WRE-JUN23.PDF"
    },
    {
      "id": "ocrEr24",
      "title": "OCR J277/02 Examiners' report",
      "version": "Summer 2024",
      "url": "https://www.ocr.org.uk/Images/727491-examiners-report-computational-thinking-algorithms-and-programming.pdf"
    },
    {
      "id": "ocrEr25",
      "title": "OCR J277/02 Examiners' report",
      "version": "Summer 2025",
      "url": "https://www.ocr.org.uk/Images/753233-examiners-report-computational-thinking-algorithms-and-programming.pdf"
    },
    {
      "id": "ocrAEr24",
      "title": "OCR H446/02 Examiners' report",
      "version": "Summer 2024",
      "url": "https://www.ocr.org.uk/Images/726390-examiners-report-algorithms-and-programming.pdf"
    },
    {
      "id": "ocrAEr25",
      "title": "OCR H446/02 Examiners' report",
      "version": "Summer 2025",
      "url": "https://www.ocr.org.uk/Images/752069-examiners-report-algorithms-and-programming.pdf"
    },
    {
      "id": "python",
      "title": "The Python Tutorial and Library Reference",
      "version": "Python 3",
      "url": "https://docs.python.org/3/tutorial/controlflow.html"
    }
  ],
  "groups": [
    {
      "id": "basics",
      "label": "Basics"
    },
    {
      "id": "operators",
      "label": "Operators"
    },
    {
      "id": "selection",
      "label": "Selection"
    },
    {
      "id": "iteration",
      "label": "Iteration"
    },
    {
      "id": "data",
      "label": "Arrays and records"
    },
    {
      "id": "subroutines",
      "label": "Procedures and functions"
    },
    {
      "id": "strings",
      "label": "Strings and conversion"
    },
    {
      "id": "files",
      "label": "File handling"
    },
    {
      "id": "objects",
      "label": "Objects"
    }
  ],
  "constructs": [
    {
      "id": "comment",
      "group": "basics",
      "name": "Comments",
      "difference": "OCR and Cambridge use //. AQA and Python use #.",
      "boards": {
        "ocr": {
          "code": "//This function squares a number",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "// this procedure swaps\n// values of X and Y",
          "note": "Each line of a multi-line comment starts with //.",
          "source": "9618 guide 1.5",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "# comment\n# comment and so on",
          "note": "Multi-line comments repeat # on every line.",
          "source": "AQA p. 2",
          "exam_insert_only": false
        },
        "py": {
          "code": "# This function squares a number",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "assignment",
      "group": "basics",
      "name": "Assignment",
      "difference": "OCR assigns with =. Cambridge and AQA use the arrow, because = is their equality test.",
      "boards": {
        "ocr": {
          "code": "x = 3\nname = \"Louise\"",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "Counter ← 0\nCounter ← Counter + 1",
          "note": "The assignment operator is ←.",
          "source": "9618 guide 2.6",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "a ← 3\nb ← a + 1\nc ← 'Hello'",
          "note": null,
          "source": "AQA p. 2",
          "exam_insert_only": false
        },
        "py": {
          "code": "x = 3\nname = \"Louise\"",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "constant",
      "group": "basics",
      "name": "Constants",
      "difference": "Cambridge writes CONSTANT X = value. AQA writes CONSTANT X ← value. Same keyword, different operator.",
      "boards": {
        "ocr": {
          "code": "const vat = 0.2",
          "note": "Defined in J277 only. The H446 appendix has no constant keyword.",
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "CONSTANT HourlyRate = 6.50\nCONSTANT DefaultText = \"N/A\"",
          "note": "Only literals can be used as the value of a constant.",
          "source": "9618 guide 2.5",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "CONSTANT PI ← 3.141\nCONSTANT CLASS_SIZE ← 23",
          "note": "Names of constants are always written in capitals.",
          "source": "AQA p. 2",
          "exam_insert_only": false
        },
        "py": {
          "code": "VAT = 0.2",
          "note": "Capitals are a naming convention only. Python has no constant keyword.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "declare",
      "group": "basics",
      "name": "Declaring a variable and its type",
      "difference": "Only Cambridge has a declaration statement. OCR declares on first assignment.",
      "boards": {
        "ocr": {
          "code": null,
          "note": "No declaration statement. H446: a variable is declared the first time a value is assigned and assumes the data type of that value.",
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "DECLARE Counter : INTEGER\nDECLARE TotalToPay : REAL\nDECLARE GameOver : BOOLEAN",
          "note": "Types: INTEGER, REAL, CHAR, STRING, BOOLEAN, DATE. Declaring is described as good practice.",
          "source": "9618 guide 2.1, 2.4",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide. Type names (String, Real, Integer) appear only inside RECORD declarations.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "counter: int = 0\ntotal_to_pay: float = 0.0",
          "note": "Annotations are optional hints. counter = 0 is the usual form.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "global",
      "group": "basics",
      "name": "Global variables",
      "difference": "Only OCR has a keyword for it.",
      "boards": {
        "ocr": {
          "code": "global userID = \"Cust001\"",
          "note": "Variables declared inside a function or procedure are local to it (H446).",
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "user_id = \"Cust001\"\n\ndef log_out():\n    global user_id\n    user_id = \"\"",
          "note": "global is only needed to reassign the name inside a function.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "input",
      "group": "basics",
      "name": "Input",
      "difference": "OCR's input() takes a prompt. Cambridge INPUT is a statement. AQA USERINPUT is an expression.",
      "boards": {
        "ocr": {
          "code": "myName = input(\"Please enter a name\")",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "INPUT Answer",
          "note": null,
          "source": "9618 guide 5.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "a ← USERINPUT",
          "note": null,
          "source": "AQA p. 15",
          "exam_insert_only": false
        },
        "py": {
          "code": "my_name = input(\"Please enter a name\")",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "output",
      "group": "basics",
      "name": "Output",
      "difference": "OCR uses print(). Cambridge and AQA use OUTPUT with comma-separated values.",
      "boards": {
        "ocr": {
          "code": "print(\"My name is Noni\")",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "OUTPUT \"You have \", Lives, \" lives left\"",
          "note": null,
          "source": "9618 guide 5.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "OUTPUT a\nOUTPUT a, g",
          "note": null,
          "source": "AQA p. 15",
          "exam_insert_only": false
        },
        "py": {
          "code": "print(\"You have\", lives, \"lives left\")",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "case-convention",
      "group": "basics",
      "name": "Keyword case",
      "difference": "OCR keywords are lower case. Cambridge and AQA keywords are upper case.",
      "boards": {
        "ocr": {
          "code": "if ... then\nelseif ... then\nelse\nendif",
          "note": "Lower-case keywords; operators AND, OR, NOT, MOD and DIV are capitals.",
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "IF ... THEN\nELSE\nENDIF",
          "note": "Keywords upper case, identifiers mixed case (NumberOfPlayers), indent usually three spaces. Identifiers are case insensitive.",
          "source": "9618 guide 1.2, 1.3, 2.3",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "IF ... THEN\nELSE IF ... THEN\nELSE\nENDIF",
          "note": "Keywords are emboldened in the guide and printed in capitals.",
          "source": "AQA p. 1, 8",
          "exam_insert_only": false
        },
        "py": {
          "code": "if score > 10:\n    print(\"high\")\nelif score > 5:\n    print(\"medium\")\nelse:\n    print(\"low\")",
          "note": "Lower case, case sensitive, and indentation is syntax.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "arithmetic",
      "group": "operators",
      "name": "Arithmetic",
      "difference": "All four use + - * /. Cambridge says / always gives a REAL.",
      "boards": {
        "ocr": {
          "code": "x = 6+5     // gives 11\nx = 12/2    // gives 6",
          "note": null,
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "TotalToPay ← NumberOfHours * HourlyRate",
          "note": "/ gives a REAL even if both operands are integers.",
          "source": "9618 guide 5.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "a + b * c\n(a + b) * c",
          "note": "Brackets indicate precedence. / is used instead of ÷.",
          "source": "AQA p. 3",
          "exam_insert_only": false
        },
        "py": {
          "code": "x = 6 + 5   # 11\nx = 12 / 2  # 6.0 (always a float)",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "div-mod",
      "group": "operators",
      "name": "Integer division and remainder",
      "difference": "Every board spells them DIV and MOD. Python uses // and %.",
      "boards": {
        "ocr": {
          "code": "17 DIV 5   // gives 3\n12 MOD 5   // gives 2",
          "note": null,
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "10 DIV 3   // evaluates to 3\n10 MOD 3   // evaluates to 1",
          "note": "The examples are from the Paper 2 insert; the guide defines DIV and MOD without examples.",
          "source": "9618 guide 5.2; 9618/21 insert",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "9 DIV 5   # evaluates to 1\n9 MOD 5   # evaluates to 4",
          "note": null,
          "source": "AQA p. 3",
          "exam_insert_only": false
        },
        "py": {
          "code": "17 // 5   # 3\n12 % 5    # 2",
          "note": "// floors, so -7 // 2 is -4. No guide defines DIV or MOD for negative numbers.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "power",
      "group": "operators",
      "name": "Exponent",
      "difference": "Only OCR defines one, and it is ^, which means something else in Python.",
      "boards": {
        "ocr": {
          "code": "3^4   // gives 81",
          "note": null,
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "3 ** 4   # 81",
          "note": "In Python ^ is bitwise XOR, so 3 ^ 4 is 7.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "comparison",
      "group": "operators",
      "name": "Comparison",
      "difference": "Equality is == in OCR, = in Cambridge and AQA. Not-equal is != , <> and ≠ respectively.",
      "boards": {
        "ocr": {
          "code": "==  !=  <  <=  >  >=",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "=  <>  <  <=  >  >=",
          "note": null,
          "source": "9618 guide 5.3",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "=  ≠  <  ≤  >  ≥",
          "note": null,
          "source": "AQA p. 4",
          "exam_insert_only": false
        },
        "py": {
          "code": "a == b, a != b\na < b, a <= b\na > b, a >= b",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "logical",
      "group": "operators",
      "name": "Boolean operators",
      "difference": "AND, OR, NOT in capitals on every board. Lower case in Python.",
      "boards": {
        "ocr": {
          "code": "while x<=5 AND flag==false",
          "note": null,
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "AND  OR  NOT",
          "note": null,
          "source": "9618 guide 5.4",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "(3 = 3) AND (3 ≤ 4)\n(x < 1) OR (x > 9)\nNOT (a < b)",
          "note": null,
          "source": "AQA p. 4",
          "exam_insert_only": false
        },
        "py": {
          "code": "x <= 5 and not flag",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "concat",
      "group": "operators",
      "name": "Joining strings",
      "difference": "Cambridge is the odd one out: & joins strings, and + costs marks.",
      "boards": {
        "ocr": {
          "code": "print(\"Hello, your name is: \" + name)",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "\"Summer\" & \" \" & \"Pudding\"",
          "note": "Produces \"Summer Pudding\".",
          "source": "9618 guide 5.5",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "'computer' + 'science'",
          "note": "Evaluates to 'computerscience'.",
          "source": "AQA p. 13",
          "exam_insert_only": false
        },
        "py": {
          "code": "greeting = \"Hello, your name is: \" + name\ngreeting = f\"Hello, your name is: {name}\"",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "literals",
      "group": "operators",
      "name": "String, character and Boolean literals",
      "difference": "Cambridge separates 'X' (CHAR) from \"X\" (STRING). AQA's examples use single quotes.",
      "boards": {
        "ocr": {
          "code": "name = \"Bob\"\nflag == false",
          "note": "Double quotes for strings; the H446 example writes false in lower case.",
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "'x'           // CHAR\n\"This is a string\"   // STRING\nTRUE  FALSE",
          "note": "A REAL literal always has a digit either side of the point: 4.0, 0.3.",
          "source": "9618 guide 2.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "c ← 'Hello'\nTrue  False",
          "note": "Boolean values are written False or True.",
          "source": "AQA p. 1, 2",
          "exam_insert_only": false
        },
        "py": {
          "code": "'x' == \"x\"   # True: both are str\ngame_over = False",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "if-else",
      "group": "selection",
      "name": "IF ... ELSE",
      "difference": "OCR needs then and endif in lower case. Cambridge and AQA use THEN ... ENDIF.",
      "boards": {
        "ocr": {
          "code": "if answer == \"Yes\" then\n    print(\"Correct\")\nelse\n    print(\"Error\")\nendif",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "IF ChallengerScore > ChampionScore THEN\n   OUTPUT ChallengerName, \" is the new champion\"\nELSE\n   OUTPUT ChampionName, \" is still the champion\"\nENDIF",
          "note": null,
          "source": "9618 guide 6.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "IF (a MOD 2) = 0 THEN\n   OUTPUT 'even'\nELSE\n   OUTPUT 'odd'\nENDIF",
          "note": null,
          "source": "AQA p. 7",
          "exam_insert_only": false
        },
        "py": {
          "code": "if answer == \"Yes\":\n    print(\"Correct\")\nelse:\n    print(\"Error\")",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "else-if",
      "group": "selection",
      "name": "Else-if chains",
      "difference": "OCR: elseif (one word). AQA: ELSE IF (two words). Cambridge defines neither.",
      "boards": {
        "ocr": {
          "code": "if answer == \"Yes\" then\n    print(\"Correct\")\nelseif answer == \"No\" then\n    print(\"Wrong\")\nelse\n    print(\"Error\")\nendif",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": null,
          "note": "Not defined in the guide. Its own example nests an IF inside the ELSE, each with its own ENDIF. CASE is the other route.",
          "source": "9618 guide 6.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "IF (a MOD 4) = 0 THEN\n   OUTPUT 'multiple of 4'\nELSE IF (a MOD 4) = 1 THEN\n   OUTPUT 'leaves a remainder of 1'\nELSE\n   OUTPUT 'leaves a remainder of 3'\nENDIF",
          "note": null,
          "source": "AQA p. 8",
          "exam_insert_only": false
        },
        "py": {
          "code": "if answer == \"Yes\":\n    print(\"Correct\")\nelif answer == \"No\":\n    print(\"Wrong\")\nelse:\n    print(\"Error\")",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "case",
      "group": "selection",
      "name": "CASE / switch",
      "difference": "OCR: switch ... endswitch. Cambridge: CASE OF ... ENDCASE with ranges. AQA has none.",
      "boards": {
        "ocr": {
          "code": "switch day :\n    case \"Sat\":\n        print(\"Saturday\")\n    case \"Sun\":\n        print(\"Sunday\")\n    default:\n        print(\"Weekday\")\nendswitch",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "CASE OF Move\n   'W' : Position ← Position - 10\n   'S' : Position ← Position + 10\n   OTHERWISE : CALL Beep\nENDCASE",
          "note": "A case can be a range: <value1> TO <value2>. Cases are tested in order and only the first match runs. OTHERWISE must be last.",
          "source": "9618 guide 6.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide. Use IF ... ELSE IF.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "match day:\n    case \"Sat\":\n        print(\"Saturday\")\n    case \"Sun\":\n        print(\"Sunday\")\n    case _:\n        print(\"Weekday\")",
          "note": "match needs Python 3.10 or later.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "for",
      "group": "iteration",
      "name": "Count-controlled loop",
      "difference": "OCR and Cambridge close with next i / NEXT i. AQA closes with ENDFOR. All include the end value; Python's range does not.",
      "boards": {
        "ocr": {
          "code": "for i=0 to 9\n    print(\"Loop\")\nnext i",
          "note": "Prints \"Loop\" 10 times, 0 to 9 inclusive.",
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "FOR Index ← 1 TO 30\n   StudentNames[Index] ← \"\"\nNEXT Index",
          "note": "Both bounds inclusive. Repeating the identifier after NEXT is good practice.",
          "source": "9618 guide 3.2, 7.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "FOR a ← 1 TO 3\n   OUTPUT a\nENDFOR\n# will output 1, 2, 3",
          "note": "The loop variable does not exist after the loop has finished.",
          "source": "AQA p. 6",
          "exam_insert_only": false
        },
        "py": {
          "code": "for i in range(0, 10):\n    print(\"Loop\")",
          "note": "range(0, 10) stops at 9: the end value is excluded.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "for-step",
      "group": "iteration",
      "name": "Loop with a step",
      "difference": "step in OCR, STEP in Cambridge and AQA. All three allow a negative step.",
      "boards": {
        "ocr": {
          "code": "for i=10 to 0 step -1\n    print(i)\nnext i",
          "note": "Prints 10 down to 0 inclusive.",
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "FOR Position ← 20 TO 10 STEP -1\n   ...\nNEXT Position",
          "note": null,
          "source": "9618 guide 7.1, 9.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "FOR a ← 5 TO 1 STEP -2\n   OUTPUT a\nENDFOR\n# will output 5, 3, 1",
          "note": null,
          "source": "AQA p. 6",
          "exam_insert_only": false
        },
        "py": {
          "code": "for i in range(10, -1, -1):\n    print(i)",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "while",
      "group": "iteration",
      "name": "Pre-condition loop (WHILE)",
      "difference": "while ... endwhile on OCR, WHILE ... ENDWHILE on Cambridge and AQA. No DO on any board.",
      "boards": {
        "ocr": {
          "code": "while answer != \"Correct\"\n    answer = input(\"New answer\")\nendwhile",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "WHILE Number > 9\n   Number ← Number - 9\nENDWHILE",
          "note": null,
          "source": "9618 guide 7.3",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "WHILE a < 4\n   OUTPUT a\n   a ← a + 1\nENDWHILE",
          "note": null,
          "source": "AQA p. 5",
          "exam_insert_only": false
        },
        "py": {
          "code": "while answer != \"Correct\":\n    answer = input(\"New answer\")",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "repeat",
      "group": "iteration",
      "name": "Post-condition loop",
      "difference": "OCR: do ... until. Cambridge and AQA: REPEAT ... UNTIL. Python has no equivalent keyword.",
      "boards": {
        "ocr": {
          "code": "do\n    answer = input(\"New answer\")\nuntil answer == \"Correct\"",
          "note": "Runs once before the condition is checked.",
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "REPEAT\n   OUTPUT \"Please enter the password\"\n   INPUT Password\nUNTIL Password = \"Secret\"",
          "note": null,
          "source": "9618 guide 7.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "REPEAT\n   OUTPUT a\n   a ← a + 1\nUNTIL a = 4",
          "note": null,
          "source": "AQA p. 5",
          "exam_insert_only": false
        },
        "py": {
          "code": "while True:\n    answer = input(\"New answer\")\n    if answer == \"Correct\":\n        break",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "for-each",
      "group": "iteration",
      "name": "For each item",
      "difference": "Only AQA defines it. Cambridge examiners have penalised it as Python-like syntax.",
      "boards": {
        "ocr": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "cie": {
          "code": null,
          "note": "Not defined in the guide. The June 2024 examiner report lists FOR Line IN InputFile as a common mistake.",
          "source": null,
          "exam_insert_only": false
        },
        "aqa": {
          "code": "FOR prime IN primes\n   total ← total + prime\nENDFOR",
          "note": "Also works over the characters of a string. Array items cannot be modified this way.",
          "source": "AQA p. 6, 10",
          "exam_insert_only": false
        },
        "py": {
          "code": "for prime in primes:\n    total = total + prime",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "array-1d",
      "group": "data",
      "name": "Declaring a 1D array",
      "difference": "OCR and AQA index from 0. Cambridge states both bounds, usually from 1.",
      "boards": {
        "ocr": {
          "code": "array colours[5]\narray colours = [\"Blue\", \"Pink\", \"Green\", \"Yellow\", \"Red\"]",
          "note": "array colours[5] has 5 elements, index 0 to 4. Arrays store a single data type.",
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "DECLARE StudentNames : ARRAY[1:30] OF STRING",
          "note": "Good practice to state the lower bound; generally 1 is used.",
          "source": "9618 guide 3.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "primes ← [2, 3, 5, 7, 11, 13]",
          "note": "Exam questions index from 0 unless they say otherwise.",
          "source": "AQA p. 1, 9",
          "exam_insert_only": false
        },
        "py": {
          "code": "colours = [\"Blue\", \"Pink\", \"Green\", \"Yellow\", \"Red\"]\nnames = [\"\"] * 5",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "array-access",
      "group": "data",
      "name": "Reading and updating an element",
      "difference": "Square brackets everywhere. Watch which index is first.",
      "boards": {
        "ocr": {
          "code": "names[3] = \"Noni\"\nprint(names[3])",
          "note": null,
          "source": "J277 3c; H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "StudentNames[1] ← \"Ali\"\nStudentNames[n+1] ← StudentNames[n]",
          "note": null,
          "source": "9618 guide 3.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "primes[0]       # evaluates to 2\nprimes[5] ← 17",
          "note": null,
          "source": "AQA p. 9",
          "exam_insert_only": false
        },
        "py": {
          "code": "names[3] = \"Noni\"\nprint(names[3])",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "array-2d",
      "group": "data",
      "name": "2D arrays",
      "difference": "OCR and Cambridge write [row, column]. AQA and Python write [row][column].",
      "boards": {
        "ocr": {
          "code": "array gameboard[8,8]\ngameboard[1,0] = \"Pawn\"",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "DECLARE NoughtsAndCrosses : ARRAY[1:3,1:3] OF CHAR\nNoughtsAndCrosses[2,3] ← 'X'",
          "note": null,
          "source": "9618 guide 3.1, 3.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "table ← [[1, 2],[2, 4],[3, 6],[4, 8]]\ntable[3][1]        # evaluates to 8\ntable[3][1] ← 16",
          "note": null,
          "source": "AQA p. 9",
          "exam_insert_only": false
        },
        "py": {
          "code": "gameboard = [[\"\" for col in range(8)] for row in range(8)]\ngameboard[1][0] = \"Pawn\"",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "array-whole",
      "group": "data",
      "name": "Assigning a whole array",
      "difference": "Cambridge allows it for same-size arrays, and bans assigning a range in one statement.",
      "boards": {
        "ocr": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "cie": {
          "code": "SavedGame ← NoughtsAndCrosses",
          "note": "Allowed if same size and type. StudentNames[1 TO 30] ← \"\" should not be used: loop instead.",
          "source": "9618 guide 3.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "saved_game = [row[:] for row in board]",
          "note": "saved_game = board would share the same list, not copy it.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "array-length",
      "group": "data",
      "name": "Length of an array",
      "difference": "Only AQA defines it, as LEN().",
      "boards": {
        "ocr": {
          "code": null,
          "note": "Not defined for arrays in the guide (.length is defined for strings).",
          "source": null,
          "exam_insert_only": false
        },
        "cie": {
          "code": null,
          "note": "Not defined for arrays in the guide (LENGTH is a string function).",
          "source": null,
          "exam_insert_only": false
        },
        "aqa": {
          "code": "LEN(primes)      # evaluates to 6\nLEN(table[0])    # evaluates to 2",
          "note": null,
          "source": "AQA p. 10",
          "exam_insert_only": false
        },
        "py": {
          "code": "len(primes)\nlen(table[0])",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "record",
      "group": "data",
      "name": "Records",
      "difference": "Cambridge: TYPE ... ENDTYPE with DECLARE lines. AQA: RECORD ... ENDRECORD. OCR's guide has none.",
      "boards": {
        "ocr": {
          "code": null,
          "note": "Not defined in the guide, although J277 content (2.2.3) covers the use of records to store data.",
          "source": null,
          "exam_insert_only": false
        },
        "cie": {
          "code": "TYPE StudentRecord\n   DECLARE LastName : STRING\n   DECLARE YearGroup : INTEGER\nENDTYPE\n\nDECLARE Pupil1 : StudentRecord\nPupil1.LastName ← \"Johnson\"\nForm[Index].YearGroup ← Form[Index].YearGroup + 1",
          "note": null,
          "source": "9618 guide 4.1, 4.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "RECORD Car\n   make : String\n   model : String\n   reg : String\n   price : Real\n   noOfDoors : Integer\nENDRECORD\n\nmyCar ← Car('Ford', 'Focus', 'DX17 GYT', 1399.99, 5)\nmyCar.model ← 'Fiesta'",
          "note": null,
          "source": "AQA p. 11",
          "exam_insert_only": false
        },
        "py": {
          "code": "from dataclasses import dataclass\n\n@dataclass\nclass Car:\n    make: str\n    model: str\n    reg: str\n    price: float\n    no_of_doors: int\n\nmy_car = Car(\"Ford\", \"Focus\", \"DX17 GYT\", 1399.99, 5)\nmy_car.model = \"Fiesta\"",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "user-types",
      "group": "data",
      "name": "Enumerated, pointer and set types",
      "difference": "Cambridge only.",
      "boards": {
        "ocr": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "cie": {
          "code": "TYPE Season = (Spring, Summer, Autumn, Winter)\nTYPE TIntPointer = ^INTEGER\nTYPE LetterSet = SET OF CHAR\nDEFINE Vowels ('A','E','I','O','U'): LetterSet",
          "note": "MyPointer ← ^ThisSeason takes an address; MyPointer^ reads the value stored there.",
          "source": "9618 guide 4.1, 4.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "from enum import Enum\n\nclass Season(Enum):\n    SPRING = 1\n    SUMMER = 2\n    AUTUMN = 3\n    WINTER = 4\n\nvowels = {\"A\", \"E\", \"I\", \"O\", \"U\"}",
          "note": "Python has no pointer type.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "procedure",
      "group": "subroutines",
      "name": "Defining a procedure",
      "difference": "AQA has one keyword, SUBROUTINE, for both kinds. A RETURN makes it a function.",
      "boards": {
        "ocr": {
          "code": "procedure greeting(name)\n    print(\"hello\"+name)\nendprocedure",
          "note": null,
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "PROCEDURE Square(Size : INTEGER)\n   FOR Side ← 1 TO 4\n      CALL MoveForward(Size)\n      CALL Turn(90)\n   NEXT Side\nENDPROCEDURE",
          "note": "Every parameter has a data type.",
          "source": "9618 guide 8.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "SUBROUTINE showAdd(a, b)\n   result ← a + b\n   OUTPUT result\nENDSUBROUTINE",
          "note": "A subroutine with no RETURN is a procedure.",
          "source": "AQA p. 12",
          "exam_insert_only": false
        },
        "py": {
          "code": "def greeting(name):\n    print(\"hello\" + name)",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "procedure-call",
      "group": "subroutines",
      "name": "Calling a procedure",
      "difference": "Cambridge alone needs CALL, and only for procedures.",
      "boards": {
        "ocr": {
          "code": "greeting(\"Hamish\")",
          "note": null,
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "CALL Square(100)\nCALL DefaultSquare()",
          "note": null,
          "source": "9618 guide 8.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "showAdd(2, 3)",
          "note": null,
          "source": "AQA p. 12",
          "exam_insert_only": false
        },
        "py": {
          "code": "greeting(\"Hamish\")",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "function",
      "group": "subroutines",
      "name": "Defining a function",
      "difference": "Cambridge declares the return type with RETURNS. OCR and AQA do not type anything.",
      "boards": {
        "ocr": {
          "code": "function triple(number)\n    return number*3\nendfunction",
          "note": null,
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "FUNCTION Max(Number1 : INTEGER, Number2 : INTEGER) RETURNS INTEGER\n   IF Number1 > Number2 THEN\n      RETURN Number1\n   ELSE\n      RETURN Number2\n   ENDIF\nENDFUNCTION",
          "note": "RETURN ends the function immediately.",
          "source": "9618 guide 8.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "SUBROUTINE add(a, b)\n   result ← a + b\n   RETURN result\nENDSUBROUTINE",
          "note": null,
          "source": "AQA p. 12",
          "exam_insert_only": false
        },
        "py": {
          "code": "def triple(number):\n    return number * 3",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "function-call",
      "group": "subroutines",
      "name": "Calling a function",
      "difference": "A function call is part of an expression. Writing CALL in front of one is a Cambridge mark-loser.",
      "boards": {
        "ocr": {
          "code": "y=triple(7)",
          "note": null,
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "OUTPUT \"Penalty Fine = \", Max(10, Distance*2)",
          "note": "The keyword CALL should not be used when calling a function.",
          "source": "9618 guide 8.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "answer ← add(2, 3) * 6",
          "note": null,
          "source": "AQA p. 12",
          "exam_insert_only": false
        },
        "py": {
          "code": "y = triple(7)",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "byref",
      "group": "subroutines",
      "name": "By value and by reference",
      "difference": "By value is the default on OCR and Cambridge. Cambridge's BYREF covers every parameter after it.",
      "boards": {
        "ocr": {
          "code": "procedure foobar(x:byVal, y:byRef)\n    ...\nendprocedure",
          "note": "A-Level only. Values are passed by value unless stated.",
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "PROCEDURE SWAP(BYREF X : INTEGER, Y : INTEGER)\n   Temp ← X\n   X ← Y\n   Y ← Temp\nENDPROCEDURE",
          "note": "BYREF need not be repeated, so Y is by reference too. Parameters should not be passed by reference to a function.",
          "source": "9618 guide 8.3",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "def swap(x, y):\n    return y, x\n\na, b = swap(a, b)",
          "note": "Python has no by-reference parameters. Return the new values, or mutate a list passed in.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "length",
      "group": "strings",
      "name": "String length",
      "difference": ".length in OCR, LENGTH() in Cambridge, LEN() in AQA. Cambridge examiners have penalised LEN().",
      "boards": {
        "ocr": {
          "code": "subject = \"ComputerScience\"\nsubject.length        // gives 15",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "LENGTH(\"Happy Days\")   // returns 10",
          "note": null,
          "source": "9618 guide 5.5",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "LEN('computer science')   # evaluates to 16",
          "note": null,
          "source": "AQA p. 13",
          "exam_insert_only": false
        },
        "py": {
          "code": "len(\"Happy Days\")   # 10",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "substring",
      "group": "strings",
      "name": "Substrings",
      "difference": "Three boards, three argument orders: (start, count) from 0; (string, start, length) from 1; (start, end, string) inclusive from 0.",
      "boards": {
        "ocr": {
          "code": "subject.substring(3,5)   // returns \"puter\"",
          "note": "Start index, then number of characters. 0 indexed.",
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "MID(\"ABCDEFGH\", 2, 3)   // returns \"BCD\"",
          "note": "String, start position, length. Position 1 is the first character.",
          "source": "9618 guide 5.5",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "SUBSTRING(2, 9, 'computer science')\n# evaluates to 'mputer s'",
          "note": "Start position, end position (both included), then the string. Indexing from 0.",
          "source": "AQA p. 13",
          "exam_insert_only": false
        },
        "py": {
          "code": "\"ComputerScience\"[3:8]      # 'puter'    = OCR substring(3,5)\n\"ABCDEFGH\"[1:4]             # 'BCD'      = MID(..., 2, 3)\n\"computer science\"[2:10]    # 'mputer s' = SUBSTRING(2, 9, ...)",
          "note": "A slice [a:b] starts at a and stops before b.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "left-right",
      "group": "strings",
      "name": "Left and right characters",
      "difference": "OCR methods .left() and .right(). Cambridge's guide has RIGHT only; LEFT appears in the exam insert.",
      "boards": {
        "ocr": {
          "code": "subject.left(4)    // returns \"Comp\"\nsubject.right(3)   // returns \"nce\"",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "RIGHT(\"ABCDEFGH\", 3)   // returns \"FGH\"\nLEFT(\"ABCDEFGH\", 3)    // returns \"ABC\"",
          "note": "RIGHT is in the guide. LEFT is not; it is supplied in the Paper 2 insert.",
          "source": "9618 guide 5.5; 9618/21 insert",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide. Use SUBSTRING.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "subject[:4]    # 'Comp'\nsubject[-3:]   # 'nce'",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "case-convert",
      "group": "strings",
      "name": "Upper and lower case",
      "difference": "The Cambridge guide's UCASE/LCASE take one CHAR. The exam insert uses TO_UPPER/TO_LOWER instead.",
      "boards": {
        "ocr": {
          "code": "subject.upper   // gives \"COMPUTERSCIENCE\"\nsubject.lower   // gives \"computerscience\"",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "UCASE('h')   // returns 'H'\nLCASE('W')   // returns 'w'",
          "note": "The June 2024 Paper 2 insert gives TO_UPPER(x) and TO_LOWER(x) for a CHAR or a STRING, e.g. TO_UPPER(\"Error 803\").",
          "source": "9618 guide 5.5; 9618/21 insert",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "subject.upper()\nsubject.lower()",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "char-codes",
      "group": "strings",
      "name": "Character codes",
      "difference": "OCR: ASC/CHR. AQA: CHAR_TO_CODE/CODE_TO_CHAR. Cambridge: only in the exam insert.",
      "boards": {
        "ocr": {
          "code": "ASC('A')   // returns 65\nCHR(97)    // returns 'a'",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "ASC('A')   // returns 65\nCHR(65)    // returns 'A'",
          "note": "Not in the guide. Supplied in the Paper 2 insert.",
          "source": "9618/21 insert",
          "exam_insert_only": true
        },
        "aqa": {
          "code": "CHAR_TO_CODE('a')   # evaluates to 97\nCODE_TO_CHAR(97)    # evaluates to 'a'",
          "note": null,
          "source": "AQA p. 14",
          "exam_insert_only": false
        },
        "py": {
          "code": "ord(\"A\")   # 65\nchr(97)    # 'a'",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "casting",
      "group": "strings",
      "name": "Converting between types",
      "difference": "OCR borrows Python's names. AQA spells out every direction. Cambridge's guide has INT(); the rest are in the insert.",
      "boards": {
        "ocr": {
          "code": "str(345)\nint(\"3\")\nfloat(\"4.52\")\nreal(\"4.52\")\nbool(\"True\")",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "INT(27.5415)   // returns 27",
          "note": "The Paper 2 insert adds NUM_TO_STR(87.5) returns \"87.5\", STR_TO_NUM(\"23.45\") and IS_NUM().",
          "source": "9618 guide 5.6; 9618/21 insert",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "STRING_TO_INT('16')\nSTRING_TO_REAL('16.3')\nINT_TO_STRING(16)\nREAL_TO_STRING(16.3)",
          "note": null,
          "source": "AQA p. 14",
          "exam_insert_only": false
        },
        "py": {
          "code": "str(345)\nint(\"3\")\nfloat(\"4.52\")\nint(27.5415)   # 27",
          "note": "Careful: bool(\"False\") is True in Python, because any non-empty string is True.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "random",
      "group": "strings",
      "name": "Random numbers",
      "difference": "OCR random(1,6) and AQA RANDOM_INT(1, 6) include both ends. Cambridge RAND(x) gives a REAL below x.",
      "boards": {
        "ocr": {
          "code": "myVariable = random(1,6)\nmyVariable = random(-1.0,10.0)",
          "note": "An integer 1 to 6 inclusive; a real -1.0 to 10.0 inclusive.",
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "RAND(87)   // may return 35.43",
          "note": "A REAL from 0 up to, but not including, x.",
          "source": "9618 guide 5.6",
          "exam_insert_only": false
        },
        "aqa": {
          "code": "diceRoll ← RANDOM_INT(1, 6)",
          "note": "Between 1 and 6 inclusive.",
          "source": "AQA p. 15",
          "exam_insert_only": false
        },
        "py": {
          "code": "import random\nrandom.randint(1, 6)       # 1 to 6 inclusive\nrandom.uniform(-1.0, 10.0)",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "file-read",
      "group": "files",
      "name": "Opening and reading a text file",
      "difference": "OCR GCSE writes open(), OCR A-Level writes openRead(). Cambridge uses statements with the file name every time.",
      "boards": {
        "ocr": {
          "code": "myFile = open(\"sample.txt\")\nx = myFile.readLine()\nmyFile.close()",
          "note": "J277. The H446 appendix opens for reading with openRead(\"sample.txt\").",
          "source": "J277 3c; H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "OPENFILE \"FileA.txt\" FOR READ\nREADFILE \"FileA.txt\", LineOfText\nCLOSEFILE \"FileA.txt\"",
          "note": "Modes: READ, WRITE, APPEND. A file is open in one mode at a time.",
          "source": "9618 guide 9.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "with open(\"sample.txt\") as my_file:\n    x = my_file.readline()",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "file-eof",
      "group": "files",
      "name": "Reading to the end of a file",
      "difference": "OCR: .endOfFile(). Cambridge: EOF(file name), which examiners report candidates leave empty.",
      "boards": {
        "ocr": {
          "code": "while NOT myFile.endOfFile()\n    print(myFile.readLine())\nendwhile",
          "note": null,
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "WHILE NOT EOF(\"FileA.txt\")\n   READFILE \"FileA.txt\", LineOfText\nENDWHILE",
          "note": null,
          "source": "9618 guide 9.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "with open(\"sample.txt\") as my_file:\n    for line in my_file:\n        print(line.rstrip(\"\\n\"))",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "file-write",
      "group": "files",
      "name": "Writing to a text file",
      "difference": "OCR's two guides disagree: J277 writeLine adds to the end, H446 openWrite overwrites.",
      "boards": {
        "ocr": {
          "code": "myFile = openWrite(\"sample.txt\")\nmyFile.writeLine(\"Hello World\")\nmyFile.close()",
          "note": "H446: openWrite overwrites any previous contents. J277: writeLine on a file from open() writes to the END of the file.",
          "source": "H446 5d; J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": "OPENFILE \"FileB.txt\" FOR WRITE\nWRITEFILE \"FileB.txt\", LineOfText\nCLOSEFILE \"FileB.txt\"",
          "note": "WRITE creates a new file and loses existing data. APPEND adds after it.",
          "source": "9618 guide 9.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "with open(\"sample.txt\", \"w\") as my_file:\n    my_file.write(\"Hello World\\n\")",
          "note": "\"w\" overwrites, \"a\" appends.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "file-new",
      "group": "files",
      "name": "Creating a new file",
      "difference": "Only OCR GCSE has a separate command.",
      "boards": {
        "ocr": {
          "code": "newFile(\"myText.txt\")",
          "note": "The file then has to be opened with open().",
          "source": "J277 3c",
          "exam_insert_only": false
        },
        "cie": {
          "code": null,
          "note": "No separate command. Opening FOR WRITE creates a new file.",
          "source": null,
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "open(\"myText.txt\", \"x\").close()   # fails if it exists",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "file-random",
      "group": "files",
      "name": "Random-access files",
      "difference": "Cambridge only: SEEK, GETRECORD and PUTRECORD.",
      "boards": {
        "ocr": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "cie": {
          "code": "OPENFILE \"StudentFile.Dat\" FOR RANDOM\nSEEK \"StudentFile.Dat\", 10\nGETRECORD \"StudentFile.Dat\", Pupil\nPUTRECORD \"StudentFile.Dat\", NewPupil",
          "note": null,
          "source": "9618 guide 9.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "with open(\"students.dat\", \"r+b\") as f:\n    f.seek(10 * RECORD_SIZE)\n    data = f.read(RECORD_SIZE)",
          "note": "Python seeks to a byte offset, so the record size is yours to define.",
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "class",
      "group": "objects",
      "name": "Class and constructor",
      "difference": "Both OCR A-Level and Cambridge call the constructor new / NEW. AQA's guide has no objects.",
      "boards": {
        "ocr": {
          "code": "class Pet\n    private name\n    public procedure new(givenName)\n        name=givenName\n    endprocedure\nendclass",
          "note": "A-Level (H446) only.",
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "CLASS Pet\n   PRIVATE Name : STRING\n   PUBLIC PROCEDURE NEW(GivenName : STRING)\n      Name ← GivenName\n   ENDPROCEDURE\nENDCLASS",
          "note": null,
          "source": "9618 guide 10.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "class Pet:\n    def __init__(self, given_name):\n        self._name = given_name",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "inherit",
      "group": "objects",
      "name": "Inheritance",
      "difference": "inherits / INHERITS, and the parent constructor is reached through super / SUPER.",
      "boards": {
        "ocr": {
          "code": "class Dog inherits Pet\n    private breed\n    public procedure new(givenName, givenBreed)\n        super.new(givenName)\n        breed=givenBreed\n    endprocedure\nendclass",
          "note": null,
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "CLASS Cat INHERITS Pet\n   PRIVATE Breed: STRING\n   PUBLIC PROCEDURE NEW(GivenName : STRING, GivenBreed : STRING)\n      SUPER.NEW(GivenName)\n      Breed ← GivenBreed\n   ENDPROCEDURE\nENDCLASS",
          "note": "The 2026 guide declared Breed as INTEGER while assigning it a STRING. The 2027 to 2029 guide fixes it.",
          "source": "9618 guide 10.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "class Dog(Pet):\n    def __init__(self, given_name, given_breed):\n        super().__init__(given_name)\n        self._breed = given_breed",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "object-use",
      "group": "objects",
      "name": "Creating an object and calling a method",
      "difference": "OCR: new Dog(...). Cambridge: NEW Cat(...). Python has no new keyword.",
      "boards": {
        "ocr": {
          "code": "myDog = new Dog(\"Fido\", \"Scottish Terrier\")\nplayer.setAttempts(5)\nprint(player.getAttempts())",
          "note": null,
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "MyCat ← NEW Cat(\"Kitty\", \"Shorthaired\")\nPlayer.SetAttempts(5)\nOUTPUT Player.GetAttempts()",
          "note": null,
          "source": "9618 guide 10.1, 10.2",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "my_dog = Dog(\"Fido\", \"Scottish Terrier\")\nplayer.set_attempts(5)\nprint(player.get_attempts())",
          "note": null,
          "source": null,
          "exam_insert_only": false
        }
      }
    },
    {
      "id": "access",
      "group": "objects",
      "name": "Public and private members",
      "difference": "Both boards assume public unless the question says otherwise.",
      "boards": {
        "ocr": {
          "code": "private attempts = 3\npublic procedure setAttempts(number)\n    attempts=number\nendprocedure\npublic function getAttempts()\n    return attempts\nendfunction",
          "note": null,
          "source": "H446 5d",
          "exam_insert_only": false
        },
        "cie": {
          "code": "PRIVATE Attempts : INTEGER\nPUBLIC PROCEDURE SetAttempts(Number : INTEGER)\n   Attempts ← Number\nENDPROCEDURE\nPRIVATE FUNCTION GetAttempts() RETURNS INTEGER\n   RETURN Attempts\nENDFUNCTION",
          "note": null,
          "source": "9618 guide 10.1",
          "exam_insert_only": false
        },
        "aqa": {
          "code": null,
          "note": "Not defined in the guide.",
          "source": null,
          "exam_insert_only": false
        },
        "py": {
          "code": "class Player:\n    def __init__(self):\n        self._attempts = 3\n\n    def set_attempts(self, number):\n        self._attempts = number\n\n    def get_attempts(self):\n        return self._attempts",
          "note": "A leading underscore marks a member as private by convention only.",
          "source": null,
          "exam_insert_only": false
        }
      }
    }
  ]
}