//======================================================================== // For this example solution I utilized Stefen Glienke's // open-source code library titled Spring4D. Latest // version is available here: https://bitbucket.org/sglienke/spring4d // Spring4D is not absolutely necessary, but it does greatly help // facilitate a much simpler solution. // // Spring4D does include a Tuple record type that I have purposely // not used in favor of my own, simple, TTuple that I declared in the // test runner, in order to remove Spring4D dependency for test execution //======================================================================== unit uSaddlePoints; interface uses uSaddlePointsTests; type ISaddlePoints = interface(IInvokable) ['{8C41B1A2-335D-4C6D-AF55-9F307F358227}'] function Calculate: TArray>; function getStatus: string; property ToString: string read getStatus; end; function newSaddlePoints(aValues: TArray>): ISaddlePoints; implementation uses SysUtils, Spring.Collections; type TSaddlePoints = class(TInterfacedObject, ISaddlePoints) private fValues: TArray>; fmaxRows: TArray; fminCols: TArray; fStatus: string; function getMaxRows: TArray; function getMinColumns: TArray; function Coordinates: IList>; function ColumnCount: integer; function RowCount: integer; function IsSaddlePoint(const coordinate: TTuple): boolean; function getStatus: string; public constructor create(aValues: TArray>); function Calculate: TArray>; property ToString: string read getStatus; end; function newSaddlePoints(aValues: TArray>): ISaddlePoints; begin result := TSaddlePoints.create(aValues); end; constructor TSaddlePoints.create(aValues: TArray>); begin fValues := copy(aValues); fmaxRows := getMaxRows; fminCols := getMinColumns; fStatus := 'Calculation not performed'; end; function TSaddlePoints.getStatus: string; begin result := fStatus; end; function TSaddlePoints.getMaxRows: TArray; var I: integer; J: integer; lRow: IList; begin lRow := TCollections.CreateList; SetLength(result, RowCount); for I := 0 to RowCount - 1 do begin for J := 0 to ColumnCount - 1 do lRow.Add(fValues[I,J]); result[I] := lRow.Max; lRow.Clear; end; end; function TSaddlePoints.getMinColumns: TArray; var I: integer; J: integer; lColumn: IList; begin lColumn := TCollections.CreateList; SetLength(result, ColumnCount); for I := 0 to ColumnCount - 1 do begin for J := 0 to RowCount - 1 do lColumn.Add(fValues[J,I]); result[I] := lColumn.Min; lColumn.Clear; end; end; function TSaddlePoints.Coordinates: IList>; var I, J: integer; begin result := TCollections.CreateList>; for I := 0 to RowCount - 1 do for J := 0 to ColumnCount - 1 do result.Add(TTuple.Create(I,J)); end; function TSaddlePoints.Calculate: TArray>; var lTuple: TTuple; begin result := Coordinates.Where(IsSaddlePoint).ToArray; if length(result) = 0 then fStatus := 'No saddle points' else begin fStatus := ''; for lTuple in result do fStatus := fStatus + format('(%d,%d),',[lTuple.Value1, lTuple.Value2]); fStatus := fStatus.Remove(fStatus.Length - 1); end; end; function TSaddlePoints.ColumnCount: integer; begin if RowCount > 0 then result := length(fValues[1]) else result := 0; end; function TSaddlePoints.RowCount: integer; begin result := length(fValues); end; function TSaddlePoints.IsSaddlePoint(const coordinate: TTuple): boolean; begin result := (fmaxRows[coordinate.Value1] = fValues[coordinate.Value1, coordinate.Value2]) and (fminCols[coordinate.Value2] = fValues[coordinate.Value1, coordinate.Value2]); end; end.