Really DRY
The observant reader will notice two translation lookup instances into pair[] in that code snippet.
Instead of pushing "opens" onto the stack, this would be a time to push its required "close" mate. The popping operations are, already, tricky to think about:
stack = [ '$' ] # Best guess in my ignorance of Python
corrupted_ch = None
for ch in line.strip():
if ch in pairs: # Opening bracket
stack.append( pairs[ch] ) # Push its mate
else: # Closing bracket
if stack.pop() != ch: # Mismatched! corrupted
corrupted_ch = ch
break # end of the road, corrupt or '$' depleted stack
if corrupted_ch:
total_score += points[corrupted_ch]
else: # instead of 'continue'. Avoid explicit flow control if possible!
score = 0
while stack:
top = stack.pop()
if top != '$':
score = score * 5 + values[top]
if score: # Only record non-zero results...
scores.append(score)
(I believe guidelines probably discourage too much density (dangling comments on the same line as code statements. This is presented, as-is, to illustrate replacing two lookups with only one lookup.)
The calculation of "points" no longer needs to translate "opens" to "closes" when looking-up the value of each character.
Maybe?:
When calculating "points" perhaps more could be done simply using the index of each closing bracket character in a simpler string (".)]}>") to give 1, 2, 3, or 4.