Загрузка данных
unit Parking;
{$mode objfpc}{$H+}
{$codepage UTF-8}
interface
uses
{$ifdef unix}cwstring,{$endif}
SysUtils;
type
{ --- Иерархия исключений --- }
EParkingError = class(Exception);
EParkingFull = class(EParkingError)
strict private
FCapacity: Integer;
public
constructor Create(ACapacity: Integer);
property Capacity: Integer read FCapacity;
end;
ESpotOccupied = class(EParkingError)
strict private
FSpotNumber: Integer;
FOccupiedBy: string;
public
constructor Create(ASpotNumber: Integer; const AOccupiedBy: string);
property SpotNumber: Integer read FSpotNumber;
property OccupiedBy: string read FOccupiedBy;
end;
EInvalidSpot = class(EParkingError)
strict private
FSpotNumber: Integer;
FCapacity: Integer;
public
constructor Create(ASpotNumber, ACapacity: Integer);
property SpotNumber: Integer read FSpotNumber;
property Capacity: Integer read FCapacity;
end;
ECarNotFound = class(EParkingError)
strict private
FLicensePlate: string;
public
constructor Create(const ALicensePlate: string);
property LicensePlate: string read FLicensePlate;
end;
{ --- Класс парковки --- }
TParkingLot = class
strict private
FSpots: array of string;
FCapacity: Integer;
function FindFreeSpot: Integer;
procedure OccupySpot(ASpotIndex: Integer; const ALicensePlate: string);
function GetCount: Integer;
function GetIsFull: Boolean;
public
constructor Create(ACapacity: Integer);
destructor Destroy; override;
function Park(const ALicensePlate: string): Integer;
procedure ParkAtSpot(ASpotNumber: Integer; const ALicensePlate: string);
procedure Leave(const ALicensePlate: string);
function TryFindCar(const ALicensePlate: string; out ASpotNumber: Integer): Boolean;
function FindCar(const ALicensePlate: string): Integer;
procedure MoveCar(const ALicensePlate: string; ANewSpotNumber: Integer);
procedure PrintStatus;
property Capacity: Integer read FCapacity;
property Count: Integer read GetCount;
property IsFull: Boolean read GetIsFull;
end;
implementation
{ EParkingFull }
constructor EParkingFull.Create(ACapacity: Integer);
begin
inherited Create(Format('парковка заполнена (вместимость: %d)', [ACapacity]));
FCapacity := ACapacity;
end;
{ ESpotOccupied }
constructor ESpotOccupied.Create(ASpotNumber: Integer; const AOccupiedBy: string);
begin
inherited Create(Format('место %d занято машиной %s', [ASpotNumber, AOccupiedBy]));
FSpotNumber := ASpotNumber;
FOccupiedBy := AOccupiedBy;
end;
{ EInvalidSpot }
constructor EInvalidSpot.Create(ASpotNumber, ACapacity: Integer);
begin
inherited Create(Format('номер места %d вне диапазона [1..%d]', [ASpotNumber, ACapacity]));
FSpotNumber := ASpotNumber;
FCapacity := ACapacity;
end;
{ ECarNotFound }
constructor ECarNotFound.Create(const ALicensePlate: string);
begin
inherited Create(Format('машина %s не найдена', [ALicensePlate]));
FLicensePlate := ALicensePlate;
end;
{ TParkingLot }
constructor TParkingLot.Create(ACapacity: Integer);
begin
if ACapacity <= 0 then
raise EParkingError.Create('Вместимость парковки должна быть больше нуля');
FCapacity := ACapacity;
SetLength(FSpots, FCapacity);
end;
destructor TParkingLot.Destroy;
begin
FSpots := nil;
inherited Destroy;
end;
{ Приватные контрактные методы }
function TParkingLot.FindFreeSpot: Integer;
var
I: Integer;
begin
Assert(not IsFull, 'Контракт нарушен: FindFreeSpot вызван при пустой парковке');
for I := 0 to FCapacity - 1 do
if FSpots[I] = '' then
Exit(I);
Result := -1;
end;
procedure TParkingLot.OccupySpot(ASpotIndex: Integer; const ALicensePlate: string);
begin
Assert((ASpotIndex >= 0) and (ASpotIndex < FCapacity),
Format('Контракт нарушен: индекс %d вне диапазона', [ASpotIndex]));
Assert(FSpots[ASpotIndex] = '',
Format('Контракт нарушен: место %d уже занято', [ASpotIndex + 1]));
FSpots[ASpotIndex] := ALicensePlate;
end;
{ Публичные защищенные методы }
function TParkingLot.Park(const ALicensePlate: string): Integer;
var
Index: Integer;
begin
if IsFull then
raise EParkingFull.Create(FCapacity);
Index := FindFreeSpot;
OccupySpot(Index, ALicensePlate);
Result := Index + 1;
end;
procedure TParkingLot.ParkAtSpot(ASpotNumber: Integer; const ALicensePlate: string);
var
SpotIndex: Integer;
begin
if (ASpotNumber < 1) or (ASpotNumber > FCapacity) then
raise EInvalidSpot.Create(ASpotNumber, FCapacity);
SpotIndex := ASpotNumber - 1;
if FSpots[SpotIndex] <> '' then
raise ESpotOccupied.Create(ASpotNumber, FSpots[SpotIndex]);
OccupySpot(SpotIndex, ALicensePlate);
end;
procedure TParkingLot.Leave(const ALicensePlate: string);
var
SpotNumber: Integer;
begin
SpotNumber := FindCar(ALicensePlate);
FSpots[SpotNumber - 1] := '';
end;
function TParkingLot.TryFindCar(const ALicensePlate: string; out ASpotNumber: Integer): Boolean;
var
I: Integer;
begin
for I := 0 to FCapacity - 1 do
begin
if FSpots[I] = ALicensePlate then
begin
ASpotNumber := I + 1;
Exit(True);
end;
end;
ASpotNumber := 0;
Result := False;
end;
function TParkingLot.FindCar(const ALicensePlate: string): Integer;
begin
if not TryFindCar(ALicensePlate, Result) then
raise ECarNotFound.Create(ALicensePlate);
end;
procedure TParkingLot.MoveCar(const ALicensePlate: string; ANewSpotNumber: Integer);
var
OldIndex, NewIndex: Integer;
begin
OldIndex := FindCar(ALicensePlate) - 1;
if (ANewSpotNumber < 1) or (ANewSpotNumber > FCapacity) then
raise EInvalidSpot.Create(ANewSpotNumber, FCapacity);
NewIndex := ANewSpotNumber - 1;
if (NewIndex <> OldIndex) and (FSpots[NewIndex] <> '') then
raise ESpotOccupied.Create(ANewSpotNumber, FSpots[NewIndex]);
if NewIndex <> OldIndex then
begin
FSpots[OldIndex] := '';
OccupySpot(NewIndex, ALicensePlate);
end;
end;
procedure TParkingLot.PrintStatus;
var
I: Integer;
begin
for I := 0 to FCapacity - 1 do
begin
Write(Format('Место %d: ', [I + 1]));
if FSpots[I] = '' then
WriteLn('свободно')
else
WriteLn(FSpots[I]);
end;
end;
function TParkingLot.GetCount: Integer;
var
I, Acc: Integer;
begin
Acc := 0;
for I := 0 to FCapacity - 1 do
if FSpots[I] <> '' then
Inc(Acc);
Result := Acc;
end;
function TParkingLot.GetIsFull: Boolean;
begin
Result := (GetCount = FCapacity);
end;
end.