(* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc. *)
(* This file is part of GNU Modula-2.
GNU Modula-2 is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GNU Modula-2 is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with gm2; see the file COPYING. If not, write to the Free Software
Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *)
IMPLEMENTATION MODULE Find ;
FROM NumberIO IMPORT WriteCard ;
FROM StrIO IMPORT WriteString, WriteLn ;
CONST
MaxX = 10 ;
MaxY = 20 ;
Infinity = 10000 ;
Wall = Infinity ;
Door = Infinity-1 ;
VAR
MapDist: ARRAY [0..MaxX], [0..MaxY] OF CARDINAL ;
Xoffset,
Yoffset: CARDINAL ;
(*
FindOptimumRoute - finds the optimum route between two points,
x1, y1, x2, y2. The directions are returned
in a string, Commands. A boolean is returned
if any commands were entered.
*)
PROCEDURE FindOptimumRoute (x1, y1, x2, y2: INTEGER;
VAR Commands: ARRAY OF CHAR) : BOOLEAN ;
BEGIN
IF IsOptimumRoutePossible(x1, y1, x2, y2)
THEN
InitMapDist(x1, y1, x2, y2) ;
RETURN( CalculateOptimumRoute(x1, y1, x2, y2, Commands) )
ELSE
RETURN( FALSE )
END
END FindOptimumRoute ;
(*
IsOptimumRoutePossible - returns true if we can use the optimum
route procedure to work out how to get
to position, x2, y2 from x1, y1.
*)
PROCEDURE IsOptimumRoutePossible (x1, y1, x2, y2: INTEGER) : BOOLEAN ;
BEGIN
RETURN( (Abs(x1, x2) <= MaxX) AND (Abs(y1, y2) <= MaxY) )
END IsOptimumRoutePossible ;
(*
Min - returns the minimum of two cardinals.
*)
PROCEDURE Min (a, b: CARDINAL) : CARDINAL ;
BEGIN
IF a>b
THEN
RETURN( b )
ELSE
RETURN( a )
END
END Min ;
(*
Abs - returns the absolute difference between two INTEGERs.
*)
PROCEDURE Abs (a, b: INTEGER) : INTEGER ;
BEGIN
IF a>b
THEN
RETURN( a-b )
ELSE
RETURN( b-a )
END
END Abs ;
(*
CalculateOptimumRoute - calculates the optimum route between
two points and putting the route into
the string Commands. TRUE is returned
if any commands are placed into Commands.
*)
PROCEDURE CalculateOptimumRoute (x1, y1, x2, y2: INTEGER;
VAR Commands: ARRAY OF CHAR) : BOOLEAN ;
VAR
Distance: CARDINAL ;
BEGIN
Distance := ScanBackwards(x1, y1, x2, y2, 0) ;
RETURN( FALSE )
END CalculateOptimumRoute ;
(*
ScanBackwards - fills in the DistMap with the distance values
from x2, y2 to x1, y1.
*)
PROCEDURE ScanBackwards (x1, y1, x2, y2: INTEGER;
Distance: CARDINAL) : CARDINAL ;
VAR
ShortDist: CARDINAL ;
BEGIN
IF ((MapDist[x2, y2]=0) OR (Distance < MapDist[x2, y2]))
THEN
ShortDist := Infinity ;
MapDist[x2, y2] := Distance ;
ShortDist := MoveVector(x1, y1, x2, y2, 0, 1, Distance) ;
ShortDist := MoveVector(x1, y1, x2, y2, 1, 0, Distance) ;
ShortDist := MoveVector(x1, y1, x2, y2, 0, -1, Distance) ;
ShortDist := MoveVector(x1, y1, x2, y2, -1, 0, Distance) ;
RETURN( ShortDist )
ELSE
RETURN( MapDist[x2, y2]+Distance )
END
END ScanBackwards ;
(*
MoveVector - returns a CARDINAL value indicating the distance between
x2, y2 and x1, y1. It moves one step from x2, y2 along
vector xv, yv. If this vector hits upon a door then
we increment the vector - we dont increment the
distance as one goes through a door using 1 unit
of distance (actually covering 2 units of space).
*)
PROCEDURE MoveVector (x1, y1, x2, y2: INTEGER ;
xv, yv : INTEGER ;
Distance: CARDINAL) : CARDINAL ;
VAR
ShortDist: CARDINAL ;
BEGIN
IF IsDoor(x2+xv, y2+yv)
THEN
xv := 2*xv ;
yv := 2*yv
END ;
INC(Distance) ;
y2 := y2+yv ;
x2 := x2+xv ;
IF CheckSquare(x2, y2)
THEN
ShortDist := ScanBackwards(x1, y1, x2, y2, Distance)
ELSE
ShortDist := Infinity
END ;
RETURN( ShortDist )
END MoveVector ;
(*
CheckSquare - checks to see whether square, x, y, is free.
If this square is free then true is returned.
*)
PROCEDURE CheckSquare (x, y: INTEGER) : BOOLEAN ;
BEGIN
IF InRange(x, y) AND (MapDist[x, y] # Wall)
THEN
RETURN( TRUE )
END ;
RETURN( FALSE )
END CheckSquare ;
(*
IsDoor - returns true if point, x, y, is legal and is
on a door.
*)
PROCEDURE IsDoor (x, y: INTEGER) : BOOLEAN ;
BEGIN
RETURN( InRange(x, y) AND (MapDist[x, y] = Door) )
END IsDoor ;
(*
InRange - returns a boolean result determining whether, x, y,
is a legal index for the MapDist array.
*)
PROCEDURE InRange (x, y: INTEGER) : BOOLEAN ;
BEGIN
RETURN( (x <= MaxX) AND (y <= MaxY) AND
(x >= 0) AND (y >= 0) )
END InRange ;
(*
InitMapDist - initializes the MapDist matrix.
*)
PROCEDURE InitMapDist (x1, y1, x2, y2: INTEGER) ;
VAR
i, j: CARDINAL ;
BEGIN
FOR i := 0 TO MaxX DO
FOR j := 0 TO MaxY DO
MapDist[i, j] := 0 (* Empty *)
END
END ;
(*
Work out the Xoffset and Yoffset. We require that
our x1, y1 and x2, y2 are as central as possible.
*)
Xoffset := (MaxX DIV 2) - (Abs(x1, x2) DIV 2) ;
Yoffset := (MaxY DIV 2) - (Abs(y1, y2) DIV 2) ;
OverlayAdvMap
END InitMapDist ;
PROCEDURE OverlayAdvMap ;
VAR
r, w, d: CARDINAL ;
BEGIN
END OverlayAdvMap ;
(*
DisplayMap - display the contents of the DistMap.
*)
PROCEDURE DisplayMap ;
VAR
x, y: CARDINAL ;
BEGIN
WriteString('------------------------------------------------------') ;
WriteLn ;
FOR y := 0 TO MaxY DO
FOR x := 0 TO MaxX DO
IF MapDist[x, y] = Wall
THEN
WriteString('######')
ELSIF MapDist[x, y] = Door
THEN
WriteString(' ')
ELSE
WriteCard(MapDist[x, y], 3) ; WriteString(' ')
END
END ;
WriteLn
END
END DisplayMap ;
(*
TestDistance - tests to see whether the ScanBackwards procedure
works.
*)
PROCEDURE TestDistance ;
VAR
MyDist: CARDINAL ;
x, y : CARDINAL ;
BEGIN
InitMapDist(0, 0, MaxX, MaxY) ;
FOR y := 0 TO MaxY DO
MapDist[4, y] := Wall
END ;
MapDist[4, 3] := Door ;
FOR y := 0 TO MaxY DO
MapDist[7, y] := Wall
END ;
MapDist[7, 7] := Door ;
FOR x := 0 TO MaxX DO
MapDist[x, 2] := Wall
END ;
MapDist[2, 2] := Door ;
DisplayMap ;
WriteString('Creating distance map between points 0,0 and MaxX, MaxY') ;
WriteLn ;
MyDist := ScanBackwards(0, 0, MaxX, MaxY, 1) ;
WriteString('Distance is') ;
WriteCard(MapDist[0,0], 6) ;
WriteLn ;
DisplayMap
END TestDistance ;
BEGIN
TestDistance
END Find.