How to forbid equal numbers - pascal

I started learning Pascal :) and I was interested on making a kind of Euromillion... However, I don't know how to forbid the same numbers or stars...
I thought this (below) would solve it... But it didn't... Help?
Program euromillion;
var num: array [1..5] of integer;
Procedure numbers;
var i, j: integer;
Begin
write ('Digite o número 1: ');
readln (num[1]);
for i:=2 to 5 do
for j:=1 to (i-1) do
Begin
repeat
write ('Digite o número ', i, ': ');
readln (num[i]);
until (num[i]>=1) and (num[i]<=50) and ((num[i]=num[j])=false);
End;
End;
Begin
numbers;
readln();
End.
Thanks guys :)

Although it is tempting to try and write a single block of code, as you have, it is better not to. Instead, a better way to write a program like this
is to think about splitting the task up into a number of procedures or functions
each of which only does a single part of the task.
One way to look at your task is to split it up into sub-tasks, as follows:
You prompt the user to enter a series of numbers
Once each number is entered, you check whether it is already in the array
If it isn't, you enter it in the array, otherwise prompt the user for another number
Once the array is filled, you output the numbers in the array
So, a key thing is that it would be helpful to have a function that checks whether
a new number is already in the array and returns True if it is and False otherwise. How to do that is the answer to your question.
You need to be careful about this because if you use the array a second time in the
program, you need to avoid comparing the new number with the array contents from
the previous time. I deliberately have not solved that problem in the example code below, to leave it as an exercise for the reader. Hint: One way would be to write a procedure which "clears" the array before each use of it, e.g. by filling it with numbers which are not valid lottery numbers, like negative numbers or zero. Another way would be to define a record which includes the NumberArray and a Count field which records how many numbers have been entered so far: this would avoid comparing the new number to all the elements in the
array and allow you to re-use the array by resetting the Count field to zero before calling ReadNumbers.
program LotteryNumbers;
uses crt;
type
TNumberArray = array[1..5] of Integer;
var
Numbers : TNumberArray;
Number : Integer;
function IsInArray(Number : Integer; Numbers : TNumberArray) : Boolean;
var
i : Integer;
begin
Result := False;
for i:= Low(Numbers) to High(Numbers) do begin
if Numbers[i] = Number then begin
Result := True;
break;
end;
end
end;
procedure ReadNumbers(var Numbers : TNumberArray);
var
i : Integer;
NewNumber : Integer;
OK : Boolean;
begin
// Note: This function needs to have a check added to it that the number
// the user enters is a valid lottery number, in other words that the
// number is between 1 and the highest ball number in the lottery
for i := Low(Numbers) to High(Numbers) do begin
repeat
OK := False;
writeln('enter a number');
ReadLn(NewNumber);
OK := not IsInArray(NewNumber, Numbers);
if not OK then
writeln('Sorry, you''ve already chosen ', NewNumber);
until OK;
Numbers[i] := NewNumber;
end;
end;
procedure ListNumbers(Numbers : TNumberArray);
var
i : Integer;
begin
for i := Low(Numbers) to High(Numbers) do
writeln(Numbers[i]);
end;
begin
ReadNumbers(Numbers);
ListNumbers(Numbers);
writeln('press any key');
readkey;
end.

Related

Delphi Function that takes Integer and returns a not-so-easily decoded Integer

Can anyone share what are some common Delphi examples of a function that takes a number
and returns a number that is not so obvious?
For example :
function GetNumber(const aSeed: Integer): Integer;
begin
Result := ((aSeed+5) * aSeed) + 15;
end;
So let's say the user knows that sending aSeed = 21 gives 561
and aSeed = 2, gives 29
and so on...
is there a function that makes it hard to reverse engineer the code,
even if one can generate a large number sets of Seed/Result ?
(hard : I do not mean impossible, just need to be non-trivial)
Preferably a function that does not allow in function result exceeding the
Integer result as well.
In any case, if you are not sure whether it's hard/impossible to reverse,
do feel free to share what you have.
some other requirements:
the same input always results in the same output; cannot have Random output
the same output regardless of platform: windows/android/mac/ios
won't result in some extraordinary big number (fit in Integer)
Using a hash is a very good way to achieve what you want. Here is an example that takes an integer, converts it to a string, appends it to a salt, computes the MD5 and returns the integer corresponding to the first 4 bytes:
uses
System.Hash;
function GetHash(const s: string): TBytes;
var
MD5: THashMD5;
begin
MD5 := THashMD5.Create;
MD5.Update(TEncoding.UTF8.GetBytes(s));
Result := MD5.HashAsBytes;
end;
function GetNumber(Input: Integer): Integer;
var
Hash: TBytes;
p: ^Integer;
begin
Hash := GetHash('secret' + IntToStr(Input));
P := #Hash[0];
Result := Abs(P^);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(GetNumber(1))); // 996659739
ShowMessage(IntToStr(GetNumber(2))); // 939216101
ShowMessage(IntToStr(GetNumber(3))); // 175456750
end;

So I need to sort alphabeticlly structure data in pascal, I improvised a sorting method, but has an error idk how to fix

sorting system and the main problem starts from the "Until" function. I would like to hear someones opinion about what I did wrong, and if there is an easier solution, I will appreciate if u told me about it.
The idea of the problem is: you have n number of people, and u need do introduce each one from the keyboard. Then, I need to sort them alphabeticlly
uses crt;
type Data = record
day : 1..31;
month : 1..12;
year : integer;
end;
Persoana = record
Name : string;
BirthDate : Data;
end;
ListaPersoane = array [1..50] of Persoana;
var x : ListaPersoane;
n:1..50;
i,z,j,l,a,v:integer;
y, k : longint;
aux : string;
begin
writeln('Program created on: 13/10/2020;');
writeln('give the number of people (max. 50):');
readln(n);
for i:=1 to n do begin
ClrScr;
writeln('Insert the name of person ', i, ': '); readln(x[i].Name);
writeln('Insert the date o birth:'); writeln('day:'); readln(x[i].BirthDate.day);
writeln('month:'); readln(x[i].BirthDate.month);
writeln('year:'); readln(x[i].BirthDate.year);
ClrScr;
end;
writeln('_______________________');
for i:=1 to n do begin
writeln(i, ') ', x[i].Name, ' ', x[i].BirthDate.day, '/', x[i].BirthDate.month, '/', x[i].BirthDate.year, ';');
writeln('_______________________');
end;
writeln();
repeat
k:=0;
for i:=1 to n do begin
j:=1;
repeat
Inc(j);
until (x[i].Name[j]>x[i].Name[j]) or (x[i].Name[j]<x[i].Name[j]);
if(x[i].Name[j]>x[i+1].Name[j]) then begin
aux:=x[i].Name;
x[i].Name:=x[i+1].Name;
x[i+1].Name:=aux;
z:=x[i].BirthDate.day;
x[i].BirthDate.day:=x[i+1].BirthDate.day;
x[i+1].BirthDate.day:=z;
l:=x[i].BirthDate.month;
x[i].BirthDate.month:=x[i+1].BirthDate.month;
x[i+1].BirthDate.month:=l;
a:=x[i].BirthDate.year;
x[i].BirthDate.year:=x[i+1].BirthDate.year;
x[i+1].BirthDate.year:=a;
Inc(k);
end;
end;
until (k=0);
writeln('_______________________');
for i:=1 to n do begin
writeln(i, ') ', x[i].Name, ' ', x[i].BirthDate.day, '/', x[i].BirthDate.month, '/', x[i].BirthDate.year, ';');
writeln('_______________________');
end;
writeln();
end.
I would expect that PascalABC can compare two strings and return which one is "smaller" or "bigger", without looping through the characters.
But to draw your attention to (at least) three issues in your sorting code, consider this code of yours:
j := 1;
repeat
Inc(j);
until (x[i].Name[j] > x[i].Name[j]) or (x[i].Name[j] < x[i].Name[j]);
Issue 1:
You initialize j := 1 before the loop. Then before you use j to index a character, you increment it. Thus you never attempt to compare the first character.
Issue 2:
Your repeat loop doesn't take into consideration that names have a limited, and often different length.
Issue 3:
Will either of these conditions, on the until row, ever be true:
(x[i].Name[j] > x[i].Name[j])
or this:
(x[i].Name[j] < x[i].Name[j])
In the subsequent code you correctly compare a character in x[i] with x[i+1]
I leave the correction of these errors for you, yourself, to correct. Consult with your tutor if needed.
You have a repeat .. until which terminates when k=0. You start with k assigned 0, then never change k. Perhaps your repeat is terminating because you don’t change k in the loop.

Delphi - Sort TList<TObject> based on the object's properties [duplicate]

I'm kinda a Delphi-newbie and I don't get how the Sort method of a TList of Records is called in order to sort the records by ascending integer value.
I have a record like the following:
type
TMyRecord = record
str1: string;
str2: string;
intVal: integer;
end;
And a generic list of such records:
TListMyRecord = TList<TMyRecord>;
Have tried to find a code-example in the help files and found this one:
MyList.Sort(#CompareNames);
Which I can't use, since it uses classes. So I tried to write my own compare function with a little different parameters:
function CompareIntVal(i1, i2: TMyRecord): Integer;
begin
Result := i1.intVal - i2.intVal;
end;
But the compiler always throws a 'not enough parameters' - error when I call it with open.Sort(CompareIntVal);, which seems obvious; so I tried to stay closer to the help file:
function SortKB(Item1, Item2: Pointer): Integer;
begin
Result:=PMyRecord(Item1)^.intVal - PMyRecord(Item2)^.intVal;
end;
with PMyRecord as PMyRecord = ^TMyRecord;
I have tried different ways of calling a function, always getting some error...
The Sort overload you should be using is this one:
procedure Sort(const AComparer: IComparer<TMyRecord>);
Now, you can create an IComparer<TMyRecord> by calling TComparer<TMyRecord>.Construct. Like this:
var
Comparison: TComparison<TMyRecord>;
....
Comparison :=
function(const Left, Right: TMyRecord): Integer
begin
Result := Left.intVal-Right.intVal;
end;
List.Sort(TComparer<TMyRecord>.Construct(Comparison));
I've written the Comparison function as an anonymous method, but you could also use a plain old style non-OOP function, or a method of an object.
One potential problem with your comparison function is that you may suffer from integer overflow. So you could instead use the default integer comparer.
Comparison :=
function(const Left, Right: TMyRecord): Integer
begin
Result := TComparer<Integer>.Default.Compare(Left.intVal, Right.intVal);
end;
It might be expensive to call TComparer<Integer>.Default repeatedly so you could store it away in a global variable:
var
IntegerComparer: IComparer<Integer>;
....
initialization
IntegerComparer := TComparer<Integer>.Default;
Another option to consider is to pass in the comparer when you create the list. If you only ever sort the list using this ordering then that's more convenient.
List := TList<TMyRecord>.Create(TComparer<TMyRecord>.Construct(Comparison));
And then you can sort the list with
List.Sort;
The concise answer:
uses
.. System.Generics.Defaults // Contains TComparer
myList.Sort(
TComparer<TMyRecord>.Construct(
function(const Left, Right: TMyRecord): Integer
begin
Result := Left.intVal - Right.intVal;
end
)
);
I want to share my solution (based on the input I have gathered here).
It's a standard setup. A filedata class that holds data of a single file in a generic TObjectList. The list has the two private attributes fCurrentSortedColumn and fCurrentSortAscending to control the sort order. The AsString-method is the path and filename combined.
function TFileList.SortByColumn(aColumn: TSortByColums): boolean;
var
Comparison: TComparison<TFileData>;
begin
result := false;
Comparison := nil;
case aColumn of
sbcUnsorted : ;
sbcPathAndName: begin
Comparison := function(const Left, Right: TFileData): integer
begin
Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString);
end;
end;
sbcSize : begin
Comparison := function(const Left, Right: TFileData): integer
begin
Result := TComparer<int64>.Default.Compare(Left.Size,Right.Size);
if Result = 0 then
Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString);
end;
end;
sbcDate : begin
Comparison := function(const Left, Right: TFileData): integer
begin
Result := TComparer<TDateTime>.Default.Compare(Left.Date,Right.Date);
if Result = 0 then
Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString);
end;
end;
sbcState : begin
Comparison := function(const Left, Right: TFileData): integer
begin
Result := TComparer<TFileDataTestResults>.Default.Compare(Left.FileDataResult,Right.FileDataResult);
if Result = 0 then
Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString);
end;
end;
end;
if assigned(Comparison) then
begin
Sort(TComparer<TFileData>.Construct(Comparison));
// Control the sort order
if fCurrentSortedColumn = aColumn then
fCurrentSortAscending := not fCurrentSortAscending
else begin
fCurrentSortedColumn := aColumn;
fCurrentSortAscending := true;
end;
if not fCurrentSortAscending then
Reverse;
result := true;
end;
end;
I found a much simpler modified sort function to alphabetize a TList of records or nonstandard list of items.
Example
PList = ^TContact;
TContact = record //Record for database of user contact records
firstname1 : string[20];
lastname1 : string[20];
phonemobile : Integer; //Fields in the database for contact info
phonehome : Integer;
street1 : string;
street2 : string;
type
TListSortCompare = function (Item1,
Item2: TContact): Integer;
var
Form1: TForm1;
Contact : PList; //declare record database for contacts
arecord : TContact;
Contacts : TList; //List for the Array of Contacts
function CompareNames(i1, i2: TContact): Integer;
begin
Result := CompareText(i1.lastname1, i2.lastname1) ;
end;
and the function to call to sort your list
Contacts.Sort(#CompareNames);

pass two difference arrays for same array

I was trying to use same printing procedure for two types of arrays(1st arry length was 10, 2nd array length was 15).
I could not find any solution over internet. Did any one have any solution for this problem.
this is the Two arrays
program pp1;
const
m=10;
n=15;
type
matrix1=array[1..m] of integer;
matrix2=array[1..n] of integer;
var
m1:matrix1;
m2:matrix2;
this is the method which it tried. in method 'x' mens the length of the array.
procedure writeMatrix(var data: array of integer ;x:integer);
var
j:integer;
begin
for j:=1 to x do
begin
write(data[j]:3);
end;
end;
my main method
begin
writeMatrix(m1,10);
writeMatrix(m2,10);
end.
How can i use the same this writeMatrix method to print both of the arrays.. Is there any stranded way to do it.
As I said in my comment before, your implementation is fine, but you have to put something in your matrix before printing it, or you will get a bunch of zeroes in the screen (in the best).
Try this:
program pp1;
const
m=10;
n=15;
type
matrix1=array[1..m] of integer;
matrix2=array[1..n] of integer;
var
m1:matrix1;
m2:matrix2;
procedure fillMatrix(var data:array of integer; x:integer);
var
j:integer;
begin
for j:= 1 to x do begin
data[j]:=j;
end;
end;
procedure writeMatrix(var data: array of integer; x:integer);
var
j:integer;
begin
for j:=1 to x do
begin
write(data[j]:3);
end;
end;
begin
fillMatrix(m1,10);
fillMatrix(m2,10);
writeMatrix(m1,10);
writeMatrix(m2,10);
readln;
readln;
end.
Hint: consider avoid using global variables, m1 and m2 in this case should be declared in the main program.
How can i use the same this writeMatrix method to print both of the arrays.. Is there any stranded way to do it.
Yes, there is a standard way to this. It is called conformant-array parameters. It is standardized in (level 1) of the ISO standard 7185 (Standard “Unextended” Pascal). It looks like this:
procedure print(protected matrix: array[
columnMinimum..columnMaximum: integer;
rowMinimum..rowMaximum: integer
] of integer);
const
totalWidth = 6;
var
x: type of columnMinimum;
y: type of rowMinimum;
begin
for y := rowMinimum to rowMaximum do
begin
for x := columnMinimum to columnMaximum do
begin
write(matrix[x, y]:totalWidth);
end;
writeLn;
end;
end;
It’s as if there were additional const values, but they are dynamic depending on the passed matrix. This code furthermore uses type inquiries (type of …) and the protected modifier, both defined in ISO 10206 (Extended Pascal) which builds on top of ISO 7185. In EP you could and would also consider schemata to pass such data as parameters.

Different result of the program than was expected, maybe because of index of arrays

i have to do the following thing.
Make a program in Pascal that after has read a text with a list of nums., it will return the numb. of the nums that appear less than one times in the text.
The text that will be read from the program should be like that.
In the first line there are two nums. seperated by a space, n and m. N is the number of nums that exist, like if the text contains the numbers 1,2,3,4, n is 4 (1..n). M is how many lines follow. Every line has a couple of nums, a,b, (1=b) a and b are separated by a space.
The file that the program will make will have written on it a num., that says how many nyms are appeared less than two tims in the text.
All the nums. are Integer.
0=
I have finished it, but the problem is that at the new text that p has to be written, p is always 1, For me the problem is at the place that i have the bold letters, it might be because i in count and i in a arrays are different, how can i correct this???
Thank you in advance.
program MyProgr;
var
F: text;
t:Textfile;
a,count:array of Integer;
b:Integer;
i,int:Integer;
countnums:Integer;
n,m:String;
lin,nums:Integer;
Small,Big:Integer;
procedure DoWhatEver(S: string);
begin
val(s,int);
Write(s,' ');
for i:=Small to Big do
if (a[i]=int) then
count[i]:=count[i]+1;
end;
procedure FilltheArray;
begin
for i:=Small to Big do
a[i]:=i+1 ;
end;
procedure ProcessString;
var
Strng, S: string;
Last, P: integer;
begin
readln(F,Strng);
Last:=0;
while Last<length(Strng) do
begin
P:=Last+1;
while (P<=length(Strng)) and (Strng[P]<>' ') do
inc(P);
S:=copy(Strng,Last+1,(P-Last-1));
DoWhatEver(S);
Last:=P;
end
end;
procedure ProcessStringA;
var
Strng: string;
Last, P: integer;
begin
readln(F,Strng);
Last:=0;
while Last<length(Strng) do
begin
P:=Last+1;
while (P<=length(Strng)) and (Strng[P]<>' ') do
inc(P);
n:=copy(Strng,Last+1,(P-Last-1));
Val(n,nums);
Last:=P;
end
end;
procedure ProcessStringB;
var
Strng: string;
Last, P: integer;
begin
readln(F,Strng);
Last:=0;
while Last<length(Strng) do
begin
P:=Last+1;
while (P<=length(Strng)) and (Strng[P]<>' ') do
inc(P);
m:=copy(Strng,Last+1,(P-Last-1));
Val(m,lin);
Last:=P;
end
end;
begin
assign(F,'myfile.txt');
reset(F);
ProcessStringA;
Writeln(nums);
ProcessStringB;
Writeln(lin);
setlength(a,nums);
Small:=Low(a);
Big:=High(a);
for i:= Small to big do
count[i]:=0;
FillTheArray;
while not eof(F) do
ProcessString;
for i:=Small to Big do
begin
if count[i]=2 then
countnums:=countnums+1;
end;
Close(f);
Assign(t,'fileout.txt');
Rewrite(t);
Writeln(t,countnums);
close(t);
end.

Resources