The problem: What is output?
Here is a question of the kind you meet on every ACSL contest. It is written in ACSL pseudocode, the made-up programming language ACSL uses so that every student reads the same program, whatever language they code in.
INPUT a, b c = a % 7 IF c > 3 && b < a THEN d = int(a / 4) + b ELSE IF !(b > 10) THEN d = a - b ^ 2 ELSE d = a + b END IF OUTPUT dWhat is output when the input is
a = 26andb = 9?Some of it looks like Python and some of it does not:
&&,!,^,END IF, and anintthat does not quite behave like Python's. The contest gives you no computer for this part: you read the program, trace it by hand, and write one exact answer.This unit teaches you to do exactly that, in three steps: how to read ACSL pseudocode and turn it into Python (Lesson 1), how to trace
IFbranches without slipping (Lesson 2), and, for Intermediate and Senior students, how to trace loops, arrays, grids and strings, which their Contest 1 also tests (Lesson 3). Write down your first guess now. In Lesson 1 you will translate the program into Python and check your guess; in Lesson 2 you will learn to get the answer by hand, the way the contest needs.-
Translate ACSL pseudocode into Python with the dialect table:
/,^,!,&&,||,absandsqrt. -
Use
math.floorfor ACSL'sint, which always rounds down, even below zero. -
Trace branches with a trace table:
IF … ELSE IFchains, separateIFs, nested decisions, and&&before||. -
Intermediate and above: trace
FORandWHILEloops, arrays, grids and strings, which your Contest 1 also tests.
-
Lesson 1 — Reading ACSL pseudocode
Division: Junior and above.
An ACSL program is a list of statements, one per line. The ones you meet most:
-
INPUT a, breads values. In a short-answer question the values are given to you, for example "the input isa = 26andb = 9". -
x = expressionstores a value, exactly as in Python. -
OUTPUT xprints.OUTPUT x, yprints both values on one line; in this book, as in Python'sprint(x, y), they are separated by one space.
-
-
IF … THEN … ELSE IF … THEN … ELSE … END IFmakes decisions.END IFmarks where theIFstops, the job indentation does in Python. -
WHILE … END WHILEandFOR … NEXTrepeat. They are in Lesson 3.
-
The dialect table
Python and ACSL pseudocode agree on most things. This table lists the ones you must translate, and the traps.
ACSL pseudocode Python Watch out =,==,!=,<,<=,>,>=the same =stores;==compares+,-,*,%the same %is the remainder//real division: 7 / 2is3.5. In Python/always gives a decimal (a float), so6 / 3prints2.0^(sometimes↑)**2 ^ 5is 32: multiply 2 by itself five times!notACSL's !binds before everything else; in Python writenot (…)with brackets&&andtrue only when both sides are true abs(x)abs(x)the size of xwithout its signint(x)math.floor(x)the greatest integer <=x. Not Python'sint(x), which chops toward zero: ACSLint(-1.5)is-2, Pythonint(-1.5)is-1sqrt(x)math.sqrt(x)gives a float: math.sqrt(49)is7.0. Questions use perfect squares or say how to roundIF … ELSE IF … ELSE … END IFif … elif … elsethe first true branch runs, and only that one FOR k = 1 TO 9 STEP 2 … NEXT kfor k in range(1, 10, 2)ACSL includes the end value (Lesson 3) A(3),A(r, c)A[3],A[r][c]arrays and 2D arrays (Lesson 3) len(S),S[j],S[a:b]len(S),S[j], …ACSL substrings are not Python slices (Lesson 3) One more pair: ACSL's
||is Python'sor, which is true when at least one side is true.ACSL works out an expression in this order:
!first, then^, then*,/and%, then+and-, then the comparisons, then&&, and||last. Python's order is the same, except thatnotcomes after the comparisons. When you translate, add brackets to make the order you mean certain.Real division and the remainder
Python has three division tools. ACSL pseudocode has only
/and%; a whole-number quotient is writtenint(a / b). Predict each line, then check it against the output.print(7 / 2) print(6 / 3) print(17 % 5) print(17 // 5)Scroll the code for more ↓
Output
3.5 2.0 2 36 / 3prints2.0, not2. Python's/always gives a float, even when the division comes out even. When a question shows a Python program, write exactly what Python prints,2.0included.Powers
ACSL writes a power with
^; Python writes it with**. A power is worked out before*,/,+and-.print(2 ** 5) print(10 - 3 ** 2) print((10 - 3) ** 2)Scroll the code for more ↓
Output
32 1 4910 - 3 ** 2is10 - 9, which is1: the power goes first. Brackets change the order, so(10 - 3) ** 2is49.ACSL
intis a floorACSL's
int(x)gives the greatest integer that is less than or equal tox. For3.7that is3, and for-3.7it is-4, because-4is below-3.7on the number line and-3is above it.Python's
int(x)does something else: it chops off the decimal part, which moves a negative number up toward zero. To get ACSL'sint, usefloorfrom Python'smathmodule. You metimportwith therandommodule;import mathloads the math tools the same way.import math print(math.floor(3.7), int(3.7)) print(math.floor(-3.7), int(-3.7)) print(math.floor(-7 / 2))Scroll the code for more ↓
Output
3 3 -4 -3 -4For positive numbers the two agree. For negative numbers they do not:
math.floor(-3.7)is-4, butint(-3.7)is-3. So ACSLint(-3.7)is-4, and translating it with Python'sintgives a wrong answer. Always translate ACSLint(x)asmath.floor(x).Absolute value and square roots
abs(x)works the same in both languages. ACSL'ssqrt(x)ismath.sqrt(x)in Python, and it always gives a float.import math print(abs(-8), abs(8)) print(math.sqrt(49)) print(math.sqrt(50)) print(math.floor(math.sqrt(50)))Scroll the code for more ↓
Output
8 8 7.0 7.0710678118654755 7math.sqrt(49)is7.0, a float. The square root of50is not a whole number, so a question that uses it must say how to round;int(sqrt(50))in ACSL, which ismath.floor(math.sqrt(50))in Python, is7.Not, and, or
ACSL's
!,&&and||are Python'snot,andandor. Put brackets afternot, so it applies to the whole comparison.b = 9 print(not (b > 10)) print(b > 5 and b < 8) print(b > 5 or b < 8)Scroll the code for more ↓
Output
True False Trueb > 10isFalse, sonot (b > 10)isTrue.andneeds both sides true;orneeds just one.Translating the opening problem
Here is the problem from the top of the unit, translated line by line. Here the input values are written into the program, as
a = 26andb = 9, in place of reading them withinput().import math a = 26 b = 9 c = a % 7 if c > 3 and b < a: d = math.floor(a / 4) + b elif not (b > 10): d = a - b ** 2 else: d = a + b print(d)Scroll the code for more ↓
Output
15Each piece of the table appears once:
&&becameand,!becamenot,^became**,ELSE IFbecameelif, and ACSL'sintbecamemath.floor. Running the translation is how you check an answer while you practise. In the contest you have no computer, so Lesson 2 is about getting the same answer by hand.The full program, reading
aandbfrom one input line, is saved asassets/l1.py.Try it import math parts = input().split() a = int(parts[0]) b = int(parts[1]) c = a % 7 if c > 3 and b < a: d = math.floor(a / 4) + b elif not (b > 10): d = a - b ** 2 else: d = a + b print(d)Scroll the code for more ↓
Run it from this unit's folder, feeding it an input file:
python assets/l1.py < assets/l1/1.inThe files
assets/l1/2.intoassets/l1/4.insend the program down each of the other branches. Trace each one by hand first, then check with the program.Lesson 2 — Tracing branches
Division: Junior and above.
To trace a program is to run it by hand, the way the computer would. Keep a small table with one column per variable. Go line by line; whenever a variable changes, write its new value in its column. At an
IF, work out the condition, write downtrueorfalse, and follow only the branch that runs.Tracing the opening problem
Input:
a = 26,b = 9.line a b c d note c = a % 726 9 5 26 = 3 × 7 + 5 IF c > 3 && b < a5 > 3true,9 < 26true, so trued = int(a / 4) + b15 26 / 4 = 6.5, int gives 6, and 6 + 9 = 15 The first condition is true, so the
ELSE IFandELSEbranches are skipped entirely. The answer is15. Check it againstassets/l1/1.out.Only the first true branch runs
In an
IF … ELSE IF … ELSEchain the conditions are tested from the top. The first true one runs its branch, and the rest are never looked at, even if they are true too. Predict the output, then check it.temp = 31 if temp > 20: label = "warm" elif temp > 30: label = "hot" else: label = "cold" print(label)Scroll the code for more ↓
Output
warm31 > 30is true, but that line is never reached, because31 > 20was true first. The output iswarm. Contest questions love this trap: when you trace a chain, stop at the first true condition.Separate IFs all get tested
Three separate
IFstatements are not a chain. Each one is tested in turn, and each test sees the values left by the ones before it.x = 7 if x > 5: x = x - 4 if x < 5: x = x * 3 if x % 2 == 0: x = x + 1 print(x)Scroll the code for more ↓
Output
9xgoes7 → 3 → 9, and9is odd, so the lastIFdoes nothing: the output is9. Had these been oneIF … ELSE IFchain, only the first branch would run and the output would be3. Look forEND IF(or, in Python,elif) to tell the two shapes apart.Nested conditions
An
IFcan sit inside a branch of anotherIF. The inner test only happens if the program reaches it. In ACSL pseudocode, eachIFhas its ownEND IF, which tells you where it stops.IF x > y THEN IF x % 2 == 0 THEN z = x - y ELSE z = x + y END IF ELSE z = y * 2 END IFx = 9 y = 4 if x > y: if x % 2 == 0: z = x - y else: z = x + y else: z = y * 2 print(z)Scroll the code for more ↓
Output
13Trace from the outside in:
9 > 4is true, so go inside;9 % 2is1, so the innerELSEruns andzis13. The outerELSEis never reached.And before or
In both languages,
&&(and) is worked out before||(or), just as*comes before+.x = 8 y = 2 print(x > 5 or y > 5 and x < y) print((x > 5 or y > 5) and x < y)Scroll the code for more ↓
Output
True FalseThe first line is
x > 5 or (y > 5 and x < y), which isTrue or False, soTrue. The brackets in the second line force theorfirst:True and False, soFalse. When a condition mixes&&and||without brackets, put in the brackets yourself before tracing.Whole-number arithmetic
Many branching questions pull digits apart with
%and whole-number division. In ACSL that division isint(n / 10); in Python,n // 10gives the same whole number.n = 482 hundreds = n // 100 tens = n // 10 % 10 ones = n % 10 print(hundreds, tens, ones) if hundreds + ones > tens: print("outside wins") else: print("middle wins")Scroll the code for more ↓
Output
4 8 2 middle winsn // 10 % 10is48 % 10, which is8, the tens digit. The remaindern % 10is always the last digit, andn // 10removes it.Put it together: this program reads three whole numbers, the side lengths of a triangle, and prints what kind of triangle they make. It uses a chain, a nested
IF, andand/ortogether. It is saved asassets/l2.py.Try it parts = input().split() a = int(parts[0]) b = int(parts[1]) c = int(parts[2]) if a + b <= c or a + c <= b or b + c <= a: print("NOT A TRIANGLE") elif a == b and b == c: print("EQUILATERAL") elif a == b or b == c or a == c: print("ISOSCELES") else: if a * a + b * b == c * c or a * a + c * c == b * b or b * b + c * c == a * a: print("RIGHT SCALENE") else: print("SCALENE")Scroll the code for more ↓
Trace it by hand on each input before you run it from this unit's folder:
python assets/l2.py < assets/l2/1.inThe order of the chain matters. Three equal sides are also "two equal sides", so the
EQUILATERALtest must come before theISOSCELEStest; and the "not a triangle" test comes first of all. Inputsassets/l2/1.intoassets/l2/5.inreach every one of the five outputs.Lesson 3 — Loops, arrays, grids and strings
Division: Intermediate and above.
Junior students meet loops, arrays and strings in later contests. Intermediate and Senior students are tested on all of them in Contest 1, so this lesson covers each one in ACSL pseudocode and in Python. Tracing works the same way: a table of variables, one line at a time.
FOR loops include the end
FOR k = 1 TO 9 STEP 2 OUTPUT k NEXT kThis outputs
1, 3, 5, 7, 9: ACSL'sFORincludes the end value9. Python'srangestops before its end, so the translation isrange(1, 10, 2): one more than the end. WithoutSTEP, the step is1.for k in range(1, 10, 2): print(k)Scroll the code for more ↓
Output
1 3 5 7 9A negative
STEPcounts down.FOR k = 20 TO 2 STEP -6visits20, 14, 8, 2. Counting down, Python'srangeneeds an end one less than ACSL's, so the translation isrange(20, 1, -6).total = 0 for k in range(20, 1, -6): total = total + k print(total)Scroll the code for more ↓
Output
44The rule is "go one step past the ACSL end": add 1 when counting up, subtract 1 when counting down. To trace a stepped loop, first write out the list of values the counter takes (
20, 14, 8, 2), then trace the body once for each.WHILE loops
WHILE condition … END WHILEis Python'swhile. The test comes before each pass, so the body can run zero times.n = 3517 reverse = 0 while n > 0: reverse = reverse * 10 + n % 10 n = n // 10 print(reverse)Scroll the code for more ↓
Output
7153A trace table makes this easy:
ngoes3517, 351, 35, 3, 0andreversegoes0, 7, 71, 715, 7153. Whennreaches0the test fails and the loop ends.Arrays
An ACSL array is written with round brackets:
A(3)is the item at position 3. A program says where its positions start. Most past ACSL problems start atA(1); some start atA(0).Python lists always start at position
0. When an ACSL array starts at 1, the easy translation is to put an unused0at position 0, so thatA(1)isA[1].A(1) = 6, A(2) = 3, A(3) = 8, A(4) = 5 FOR j = 1 TO 3 IF A(j) > A(j + 1) THEN A(j + 1) = A(j + 1) + A(j) END IF NEXT j OUTPUT A(4)A = [0, 6, 3, 8, 5] for j in range(1, 4): if A[j] > A[j + 1]: A[j + 1] = A[j + 1] + A[j] print(A[4])Scroll the code for more ↓
Output
22Trace the array as a row of boxes and change one box at a time.
j = 1: 6 > 3, soA(2)becomes 9.j = 2: now 9 > 8, soA(3)becomes 17.j = 3: 17 > 5, soA(4)becomes 22. Each pass sees the boxes as the pass before left them.2D arrays: grids
A 2D array is a grid of rows and columns, like a spreadsheet or a game board. ACSL writes one box as
A(r, c): rowr, columnc, always in that order.In Python a grid is a list of lists: a list of rows, each row a list.
grid[r]is a whole row, andgrid[r][c]is one box in it.grid = [[3, 8, 1], [7, 2, 9]] print(grid[1]) print(grid[1][2]) print(len(grid), len(grid[0]))Scroll the code for more ↓
Output
[7, 2, 9] 9 2 3Python counts rows and columns from
0, sogrid[1][2]is row 1, column 2: the9.len(grid)is the number of rows, andlen(grid[0]), the length of the first row, is the number of columns.To visit every box, use nested loops: rows on the outside, columns on the inside. This order, left to right along row 0, then row 1, and so on, is how you read a page.
grid = [[3, 8, 1], [7, 2, 9]] for r in range(len(grid)): for c in range(len(grid[0])): print(r, c, grid[r][c])Scroll the code for more ↓
Output
0 0 3 0 1 8 0 2 1 1 0 7 1 1 2 1 2 9A program often builds a grid from a rule. Build each row with
append, then append the row to the grid. Here each box holdsr * c, and, as in most ACSL problems, rows and columns start at 1: row 0 and column 0 are unused zeros.FOR r = 1 TO 3 FOR c = 1 TO 4 A(r, c) = r * c NEXT c NEXT rA = [] for r in range(4): row = [] for c in range(5): row.append(r * c) A.append(row) print(A[2]) print(A[3][4], A[2][3])Scroll the code for more ↓
Output
[0, 2, 4, 6, 8] 12 6The loops run from
0so that the unused row 0 and column 0 exist too; after that,A[r][c]in Python is exactlyA(r, c)in ACSL. On paper, draw the grid as a table with the row numbers down the side and the column numbers across the top.Some programs walk the grid a different way: down each column. Swap the loops: columns outside, rows inside. This adds up column 1 of the grid above:
1 + 2 + 3.A = [[0, 0, 0, 0, 0], [0, 1, 2, 3, 4], [0, 2, 4, 6, 8], [0, 3, 6, 9, 12]] total = 0 for r in range(1, 4): total = total + A[r][1] print(total)Scroll the code for more ↓
Output
6Strings
In ACSL, as in Python, a string's positions start at
0,len(S)is its length,S[j]is one character, and+joins strings. Substrings are where the two differ. ACSL's rules, forS = "ACSL WDTPD":ACSL means gives Python S[:3]the first 3 characters "ACS"S[:3]S[4:]the last 4 characters "DTPD"S[len(S) - 4:]S[2:6]positions 2 through 6, both included "SL WD"S[2:7]S[0]position 0 "A"S[0]A Python slice
S[a:b]stops before positionb, andS[a:]starts at positiona. So only the first form is written the same way. When a Python program is shown, use Python's rules; when ACSL pseudocode is shown, use ACSL's.S = "ACSL WDTPD" print(S[:3]) print(S[len(S) - 4:]) print(S[2:7]) print(S[4:])Scroll the code for more ↓
Output
ACS DTPD SL WD WDTPDThe last line is Python's own
S[4:]: everything from position 4 on," WDTPD", starting with the space. ACSL'sS[4:]would be"DTPD". Python programs in questions may also use the string methods you know, such asupper,lowerandreplace.Real division inside a loop
A real division can change a whole number into a decimal, and ACSL's
intthen rounds down, even below zero.import math x = 5 for k in range(3): x = x - 4 print(x / 2, math.floor(x / 2))Scroll the code for more ↓
Output
0.5 0 -1.5 -2 -3.5 -4xgoes1, -3, -7.-3 / 2is-1.5, and ACSL'sint(-1.5)is-2, one below, not-1. This is exactly where Python'sintwould give a wrong answer.Put it together: this program reads a grid of whole numbers and prints the column, counted from 1, with the largest total, and that total. The first input line holds the numbers of rows and columns; each following line is one row. If two columns tie, the one further left wins. It is saved as
assets/l3.py.Try it parts = input().split() rows = int(parts[0]) cols = int(parts[1]) grid = [] for r in range(rows): row = [] for piece in input().split(): row.append(int(piece)) grid.append(row) best_col = 0 best_total = 0 for c in range(cols): total = 0 for r in range(rows): total = total + grid[r][c] if c == 0 or total > best_total: best_col = c best_total = total print(best_col + 1, best_total)Scroll the code for more ↓
Run it from this unit's folder:
python assets/l3.py < assets/l3/1.inThe outer loop is over columns, because each total runs down one column.
best_totalstarts from the real first column (c == 0), never from a made-up0, so an all-negative grid (assets/l3/3.in) still works.-
ACSL's
int(x)is the greatest integer ≤ x:math.floor(-3.7)is-4, but Python'sint(-3.7)is-3. -
In an
IF … ELSE IFchain only the first true branch runs; separateIFs are each tested. -
&&is done before||, so bracket the&&parts when you trace. -
A trace table with one row per step makes the printed line easy to check. The opening program prints 15.
-
Intermediate and above: a
FORloop includes its end value, and ACSL substrings are not Python slices.
-
You can now trace a branching ACSL program and write its exact output.