General
- Try the tips from CGSE - Pascal and Delphi.
- Prioritise the usage of functions and procedures from the 'System' unit, as it's implicitly imported.
- Check out "Tips to get smaller code" in the official doc. /s
Types
- Use
int8/16/32/64instead oninteger/longint. - Use
wordinstead ofint16if only unsigned integers are needed. - Use
realorcompinstead ofextended. - Use a type instead of a range to define indices of an array, for example,
array[word] of wordinstead ofarray[0..99] of word. - Use
integerarrayinstead ofarray[word] of word. - All variables of primitive data types are implicitly set to zero/null/empty state when defined globally.
Numbers and keywords
- Sometimes, you can shorten your code by deleting whitespace and/or semicolon between a const number value and a keyword (usually,
do,to,end,thenanduntil). - FPC reads code from left to right greedily char-by-char and can't process decimal numbers glued together with the keyword
end(see example III), as it could be parsed as a prefix of a constant written in scientific notation. - The same error appears when a hexadecimal number is concatenated with keywords that start with a-f, for example,
do.
Example I (for-to)
for i:=1 to 100 do doSomething(i);
for i:=1to 100do doSomething(i);
Example II (repeat-until)
i:=0;repeat doSomething(i);i+=1;until i=100;
i:=0;repeat doSomething(i);i+=1until i=100;
Example III (end)
begin i:=0;repeat i+=1;doSomething(i)until i=100;end.
begin i:=0;repeat i+=1;doSomething(i)until i=100end.
{❌ ERROR, parsed as 100e and expecting the exponent}
begin i:=0;repeat i+=1;doSomething(i)until i=1e2end.
{✅ NO ERROR}
HEX and OCT integers
- Use hex or oct representation of any integer to win one or more bytes in combination with the previous idea (number+keyword concatenation).
- For hexadecimal values use
$as a prefix ($32 = 50). - For octal values use
&as a prefix (&62 = 50). - Both hex and oct values are distinguishable from the keyword on the left (because of prefix), so you don't need a space between a keyword and a value.
Example I (hex superiority)
begin doSomething(x);x:=x div 10;end;
begin doSomething(x);x:=x div$a;end;
Example II (oct superiority)
begin doSomething(x);x:=x div 500;end;
begin doSomething(x);x:=x div$1f4;end;
begin doSomething(x);x:=x div$1f4end;
{❌ ERROR, FPC is trying to parse "$1f4e" as a hex integer}
begin doSomething(x);x:=x div&764;end;
begin doSomething(x);x:=x div&764end;
{✅ NO ERROR, oct values don't have 'e' in the range of digits and can't be represented in scientific notation}
Loops
- There are four different loops in Pascal:
for-to(andfor-downto),for-in,while-doandrepeat-until. - Try all of them as they could help to shorten the code.
Forandwhileloops are useful for short, one-operation blocks.Repeat-untilis usually used when the loop body consists of 2 or more operations, as it's the only type that naturally defines the start and end of the body.
Example I (one operation)
for i:=1to 100do doSomething(i);
i:=0;repeat i+=1;doSomething(i)until i=100;
Example II (two operations)
for i:=1to 100do begin doSomething(i);doSomethingElse(i)end;
i:=0;repeat i+=1;doSomething(i);doSomethingElse(i)until i=100;
Example III (two operations with a variable implicitly set to 0)
var i:word;{...}for i:=1to 100do begin doSomething(i);doSomethingElse(i)end;
var i:word;{...}repeat i+=1;doSomething(i);doSomethingElse(i)until i=100;
Functions and procedures
- If a function/procedure doesn't take any arguments, parentheses are not required and can be skipped.
- Function's name is a valid variable (of the return type) and can be used inside of the function body.
Example I (no args)
begin writeln()end.
begin writeln;end.
Example II (func name)
function f(x:word):word;
var i:word;
begin
for i:=1to x do doSomething(i);
f:=x*x;
end;
function f(x:word):word;
begin
for f:=1to x do doSomething(f);
f:=x*x;
end;
Arguments number
argcis an integer variable (not a constant), which is always available, even if a hole doesn't need arguments to extract (in this case,argc = 1).- If you need only one integer variable and you use it three (or fewer) times, consider
argcas it's already predefined, and there is no need to write thevarsection.
Example
var i:word;begin for i:=1 to 100 do doSomething(i);end.
begin for argc:=1 to 100 do doSomething(argc);end.
CTRL-format for characters
- In Pascal, you may use
ctrl+<char>as an alternative way to represent some characters. - In code, you write it as
^<char>, for instance,^j. - This may shorten your code by 1 byte as you don't need to use quotation marks.
Example (^` vs ' ')
{$H+}
uses sysutils;begin writeln('code golf'.split(' ')[1]);end.
{$H+}
uses sysutils;begin writeln('code golf'.split(^`)[1]);end.
Most useful replacements
^@ → '\0'
^i → '\t'
^j → '\n'
^m → '\r'
^` → ' '
^< → '|'
^> → '~'
^a..^z → char(1)..char(26)
^0..^9 → 'p'..'y'
Argument Iteration
For holes with inputs, this is the most common pattern:
var i:word;begin repeat i+=1;...;until i=argc-1;end.
When the body code is one line, you can use this (7b shorter):
var i:word;begin for i:=1to argc-1do ...;end.
Hardcoding Argc
Find your hole here. If you don't found the hole or seen (TO-DO), just use this code and run few times to ensure argc is hardcoded:
begin
writeln(argc);
end.
Then, you can replace argc-1 with the specified argc, and this works.
For example, if the argc is said to be 128, then replace argc-1 with 128.
Keep in mind when the hole's argc is edited, it's possible to break your code - just update argc.
Overshooting Argc
You can often overshoot argc by using a larger constant than the actual argument count.
This can save bytes because some numeric literals are shorter than the exact argc value.
For example, if argc is 128, 2e2 may be usable instead of 128 if the extra iterations do not affect the output.
This can also work for random-argc holes when a sufficiently large constant is safe. For example, 5e4 can current replace argc-1 in all holes.
Be careful: this is only valid when the extra iterations are harmless.
For example, when your code contains ReadStr, then you'd get a EInOutError error.
Variant
- Use
variantdata type when you need to store values of different types in the same variable. - Sometimes, it could help to replace expensive (in golf context) writing or value transformation.
Example (FizzBuzz mock)
{n bytes}
var i:word;s:string;
begin
for i:=1 to 100 do begin
s:=getFizzBuzzString(i);
if s=''then write(i);
writeln(s);
end;
end.
{n-3 bytes}
var i:word;s:variant;
begin
for i:=1 to 100 do begin
s:=getFizzBuzzString(i);
if s=''then s:=i;
writeln(s);
end;
end.
String to Number parsing
- There are at least 6 different ways to parse a string as an integer:
Valis the simplest way to do this. This procedure lives insystemunit, so you don't need to import anything. The main difference, it saves the result of parsing in the second argument and returns nothing (because of the "procedural" nature).StrToIntis a function insysutilswhich transforms a string to a single integer value.TStringHelper.toInt64()is a string method, available when the directive for long strings is enabled ({$H ON}or{$H+}).Numb2Decis a function instrutils, does the same asStrToIntbut also requires an integer base.Variantdata type. Throw a string into avariantvariable and hope for implicit conversion to be correct.Sscanfis a function insysutils, works in the same way as in C and C++. It is longer than the other methods, but it allows you to parse complex strings and simultaneously initialise more than one variable.
- To decide what procedure, function or method to use, consider a few things:
- Do you need the result of this parsing returned from a function and available immediately to process or should it be stored in a variable?
- What units are already imported? Are long strings already available?
- How many values are need to be parsed from one line/string?
Example
var x:int32;s:string='69419';begin val(s,x);writeln(x+1)end.
uses sysutils;var s:string='69418';begin writeln(strtoint(s)+2)end.
uses{$H+}sysutils;var s:string='69417';begin writeln(s.toint64+3)end.
uses strutils;var s:string='69416';begin writeln(numb2dec(s,10)+4)end.
var v:variant;x:int32;s:string='69415';begin v:=s;x:=v;writeln(x+5)end.
uses sysutils;var x:int32;s:string='69414';begin sscanf(s,'%d',[@x]);writeln(x+6)end.
Packer
2:1
- Compress your Pascal code with the following script [tio.run] (The logic is the same as the JavaScript 2:1 packer).
- Paste the compressed output in the following unpacker, make it a bit shorter by removing newlines and submit it.
- The overhead is quite big (158 chars), so it makes sense to use this packer for solutions written in more than 316 bytes.
- Note: the first argument is dropped
- Note: to understand what's on Earth is ^0, check out the CTRL-format for characters section.
uses baseunix;
var f:text;c:wchar;
begin
assign(f,^0);rewrite(f);
for c in'PACKED_CODE'do write(f,chr(lo(ord(c))));
reset(f);fpdup2(3,0);
fpexecv('/usr/bin/pascal',argv)
end.