How can I represent a coordinate grid in Delphi?
-
22-08-2019 - |
Question
I'm trying to represent a two-dimensional coordinate grid with a two-dimensional array. Problem is, declaring the array flips the X and Y coordinates because of the way Delphi allocates the array. This makes it difficult to read elements of the array. For example, the following program gives a range check error while trying to print:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
{$R+}
procedure play;
var
grid: array of array of boolean;
x, y: integer;
begin
try
setLength(grid, 3, 8);
grid[1, 5] := true;
for y := low(grid) to high(grid) do
begin
for x := low(grid[y]) to high(grid[y]) do
begin
if grid[x, y] then
write('X')
else write('.');
end;
writeln;
end;
readln;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end;
begin
play;
end.
I have to write the index backwards (if grid[y, x] then) to keep that from happening, but then the grid prints out sideways, with the X shown at (5, 1) instead of at (1, 5). If I try to change the shape of the grid by saying setLength(grid, 3, 8); then the assignment on the next line gives a range check error. I end up having to write all of my coordinates backwards, and any time I forget they're backwards, bad things end up happening in the program.
Does anyone know any tricks to make the coordinate order work intuitively?
Solution
You just need to give the proper bounds in the for statements. It's important to pay careful attention when applying the low and high functions to multi-dimensional arrays. For the current example (a 2-dimensional array), low(grid) and high(grid) will return the limits on the first dimension (row), whereas low(grid[0]) and high(grid[0]) will return the limits on the first column (assuming it exists). Note the changed for limits below:
program Play_console;
{$APPTYPE CONSOLE}
uses
SysUtils;
{$R+}
procedure play;
var
grid: array of array of boolean;
x, y: integer;
begin
try
setLength(grid, 3, 8);
grid[1, 5] := true;
for y := low(grid[0]) to high(grid[0]) do
begin
for x := low(grid) to high(grid) do
begin
if grid[x, y] then
write('X')
else write('.');
end;
writeln;
end;
readln;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end;
begin
play;
end.
I tested this and it seems to do exactly what you want.
OTHER TIPS
[y, x] is common and standard array access across most (all?) programming languages. It will be confusing for anyone looking at your code if you do it otherwise.
I'd say that the standard representation isn't only consistent with general programming convention, it's consistent with graphing in general. Plot [1,4] on graph paper and you'll get the same thing as in your second (actual result) example, with the exception that the y axis is flipped in screen coordinates, but you're not complaining about that.
More specifically, the x axis is consistently horizontal, and the y axis is consistently vertical. That's what your example shows. It's not reversed.
I'd say just get used to it.