General
Types
- Use
int8/16/32/64
instead on integer/longint
.
- Use
word
instead of int16
if only unsigned integers are needed.
- Use
real
or comp
instead of extended
.
- Use a type instead of a range to define indices of an array, for example,
array[word] of word
instead of array[0..99] of word
.
- Use
integerarray
instead of array[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
, then
and until
).
- 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
(and for-downto
), for-in
, while-do
and repeat-until
.
- Try all of them as they could help to shorten the code.
For
and while
loops are useful for short, one-operation blocks.
Repeat-until
is 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
argc
is 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
argc
as it's already predefined, and there is no need to write the var
section.
Example
var i:word;begin for i:=1 to 100 do doSomething(i);end.
begin for argc:=1 to 100 do doSomething(argc);end.
- 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'
Variant
- Use
variant
data 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:
Val
is the simplest way to do this. This procedure lives in system
unit, 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).
StrToInt
is a function in sysutils
which 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+}
).
Numb2Dec
is a function in strutils
, does the same as StrToInt
but also requires an integer base.
Variant
data type. Throw a string into a variant
variable and hope for implicit conversion to be correct.
Sscanf
is a function in sysutils
, 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 to utf-16 as usual (for example, with the following script: [tio.run]).
- Paste your utf-16 output in the following unpacker, make it a bit shorter by removing newlines and submit it.
- The overhead is quite big (204 bytes), so it makes sense to use this packer for solutions written in more than 400 bytes.
- Note: to understand what's on Earth is ^0, check out the CTRL-format for characters section.
uses sysutils;
var f:text;c:wchar;
begin
assign(f,^0);rewrite(f);
for c in utf8decode('PACKED_CODE_UTF16')do write(f,chr(ord(c)and$FF)+chr(ord(c)>>8));
close(f);
executeprocess('/usr/bin/fpc','p -v1');
executeprocess(^0,'')
end.