In this program when I try to put the code blocks [1] and [2] in procedures they don't work properly when calling them, and when I keep them in the main program only the first one works properly and the second doesn't and when I comment out the first one the second one works as it's supposed...can you please spot the error, I think it's with getting the files names from the user cause when I choose the file's name it works properly
program Linked_lists_files;
type
Node = ^T;
T = record
num : integer;
next : Node;
End;
var
File1 : Text;
N, i, j, cmp, y, x, Num, matrixvalue : integer;
Head, Tail, Head2, Tail2, Head3, Tail3 : Node;
s : string;
matrix : array [1..20, 1..20] of Integer;
// procedures
// [1]
Procedure fillFile();
Begin
write('Input file name to create : ');
readln(s);
assign(File1,s);
rewrite(File1);
Repeat
write('Enter a number : ');
readln(N);
if (N>=0) then
writeln(File1, N);
Until (N<0);
close(File1);
End;
// [2]
Procedure GetFromFile();
Begin
cmp := 0;
write('Enter file name to read from : ');
readln(s);
assign(File1, s);
reset(File1);
while not eof(File1) Do
Begin
readln(File1, N);
if (Head = Nil) then
Begin
new(Head);
Tail := Head;
End
Else
Begin
new(Tail^.next);
Tail := Tail^.next;
End;
Tail^.num := N;
Tail^.next := Nil;
cmp := cmp + 1;
End;
Close(File1);
Write('Elements of the list : ');
Tail := Head;
if (Head<>nil) then
Begin
while(Tail <> nil) Do
Begin
write('[',Tail^.num,']', ' ');
Tail := Tail^.next;
End;
End
Else
Writeln('[!] The list is empty');
writeln;
writeln('Number of elements in the list : ', cmp);
End;
// [3]
Procedure SaveFromFile();
Begin
Head := Nil;
write('Enter file name to read from : '); readln(s);
writeln('[+] Fill in your list');
Repeat
write('+ Enter an integer : ');
read(y);
if (y>=0) then
Begin
if (Head = Nil) then
Begin
new(Head);
Tail := Head;
End
Else
Begin
new(Tail^.next);
Tail := Tail^.next;
End;
Tail^.num := y;
Tail^.next := Nil;
End;
Until y<0;
assign(File1, s);
rewrite(File1);
Tail := Head;
while(Tail <> nil) Do
Begin
Num := Tail^.num;
Tail := Tail^.next;
Writeln(File1, Num);
End;
Close(File1);
Writeln('[+] Elements of the lists have been successfully added to the new file');
End;
// [4]
Procedure SquareMatrix();
Begin
cmp := 0;
x := 0;
writeln('[+] Fill in your list');
Repeat
write('+ Enter an integer : ');
read(y);
if (y>=0) then
Begin
if (Head3 = Nil) then
Begin
new(Head3);
Tail3 := Head3;
End
Else
Begin
new(Tail3^.next);
Tail3 := Tail3^.next;
End;
Tail3^.num := y;
Tail3^.next := Nil;
cmp := cmp + 1;
End;
Until y<0;
while (cmp<>1) Do
Begin
if (cmp mod 2 <> 0) and (cmp <> 1) then
x := x + 1;
cmp := cmp div 2;
End;
if (x>0) then
writeln('[-] False')
Else
writeln('[+]True');
End;
// [5]
Procedure ElementsOfSM();
Begin
cmp := 0;
x := 0;
writeln('[+] Fill in your list');
Repeat
write('+ Enter an integer : ');
read(y);
if (y>=0) then
Begin
if (Head = Nil) then
Begin
new(Head);
Tail := Head;
End
Else
Begin
new(Tail^.next);
Tail := Tail^.next;
End;
Tail^.num := y;
Tail^.next := Nil;
cmp := cmp + 1;
End;
Until y<0;
Tail := Head;
i := 1;
j := 1;
while(Tail <> nil) Do
Begin
matrixvalue := Tail^.num;
matrix[i,j] := matrixvalue;
Tail := Tail^.next;
j := j + 1;
if (j = sqrt(cmp)+1) then
Begin
i := i + 1;
j := 1;
End;
End;
for i:=1 to cmp Do
for j:=1 to cmp Do
Begin
if (matrix[i,j]<>0) then
writeln('[',matrix[i,j],']',' : ','[',i,',',j,']');
End;
End;
// [6]
Procedure Element();
Begin
write('Enter the number of the line : ');
read(i);
write('Enter the number of the column : ');
read(j);
write('The element corresponding to ','[',i,',',j,'] is : ','[',matrix[i,j],']');
writeln;
End;
// [7]
Procedure WriteP();
Begin
write('Enter the number of the line : ');
read(i);
write('Enter the number of the column : ');
read(j);
write('Enter the value you want to pass in : ');
read(N);
matrix[i,j] := N;
writeln('The new matrix');
for i:=1 to cmp Do
for j:=1 to cmp Do
Begin
if (matrix[i,j]<>0) then
writeln('[',matrix[i,j],']',' : ','[',i,',',j,']');
End;
writeln;
End;
// [8]
Procedure Content();
Begin
write('Enter the number of the line : ');
read(i);
write('Enter the number of the column : ');
read(j);
writeln('The value stored inn this cell is : ','[', matrix[i,j],']');
End;
// Start of main program
Begin
Head := Nil;
Repeat
writeln('*********** MENU ***********');
writeln('[1] fillFile');
writeln('[2] GetFromFile');
writeln('[3] SaveFromFile');
writeln('[4] SquareMatrix');
writeln('[5] ElementsOfSM');
writeln('[6] Element');
writeln('[7] WriteP');
writeln('[8] Content');
writeln('*********** End ***********');
write('Choose one : ');
read(N);
case N of
1 : fillFile();
2 : GetFromFile();
3 : SaveFromFile();
4 : SquareMatrix();
5 : ElementsOfSM();
6 : Element();
7 : WriteP();
8 : Content();
End;
Until (N<>1) and (N<>2) and (N<>3) and (N<>4) and (N<>5) and (N<>6) and (N<>7) and (N<>8) and (N<>9);
End.
The problem you describe is being caused by the known behaviour of the Read statement; basically, the second (and subsequent) times you call it, it returns immediately, without waiting for any keyboard input and without reading anything.
This happen because FPC is closely based on Object Pacal in the commercial Delphi development package, and in Delphi's case, this is the officially documented behaviour.
From the Delphi (v7) online help:
Delphi syntax:
Text files:
procedure Read( [ var F: Text; ] V1 [, V2,...,Vn ] );
Description
The Read procedure can be used in Delphi code in the following ways.
[...]
With a type string variable:
Read reads all characters up to, but not including, the next end-of-line
marker or until Eof(F) becomes true; it does not skip to the next line after reading. If the resulting string is longer than the maximum length of the string variable, it is truncated.
After the first Read, each subsequent Read sees the end-of-line marker and returns a zero-length string (emphasis added).
Use multiple Readln calls to read successive string values.
Fortunately, the solution is simple, use readln, instead of read, as in
readln(s);
Update Make sure you replace all instances of read by readln, as you have left a number of them unchanged, as #TomBrunberg has commented.
After that, run your code again and select 1 from the menu and you will find that fillFile executes, but the program terminates on the until ... line. And that's because it is a very bad idea to use the same global variable, in this case N for several different purposes throughout the program. So, you should edit your code further (and carefully) so that as far as possible it only uses global variables for global purposes. Turn all all the other variables into local variables, preferably with different names than the global ones. If after that you are still having problems, submit a new question focused on that.
Related
I've been trying to learn the procedure for merging two arrays in merge sort, and I've been given a fixed code which I have to strictly follow .The following is a program for sorting a list of numbers in ascending/ descending order depending on the user's choice is as follows:
const
max = 200000;
MaxDisp = 20;
type
list = array[1..max] of real;
var
a: list;
na: longint;
is_asc:boolean;
procedure GenList(var L: list; n: longint);
var
i: longint;
begin
randomize;
for i := 1 to n do begin
L[i] := random;
end;
end;
procedure DispList(L: list; n: longint);
var
i: longint;
begin
for i := 1 to MaxDisp do begin
if i <= n then begin
writeln(i:10, ' - ', L[i]:0:10);
end;
end;
if n > MaxDisp then begin
writeln(n - MaxDisp, ' more ...');
end;
end;
procedure sort(var L: list; n: longint;is_asc:boolean);
procedure Merge(L1,L2,R1,R2:longint);
var
M:list;//this is C
i1,i2,iM,i,j:longint;
begin
i1:=L1;
i2:=L2;
j:=1;
while (i1<=R1) and (i2<=R2) do begin
if (is_asc and (L[i1]<L[i2])) or not is_asc and (L[i1]<L[i2]) then begin
M[j]:=L[i1];
j:=j+1;
i1:=i1+1;
end
else begin
M[j]:=L[i2];
j:=j+1;
i2:=i2+1;
end;
j:=________;
end;
if(i1>R1) and (i2<=R2) then
for i:=________ do begin
M[j]:=_______;
end
else if (i2>R2) and (i1<=R1) then
for i:=1 to _______ do begin
_________;
end;
num:=_______;
i:=______;
for j:=1 to num do begin
_________;
end
end;
procedure MSort(LL,RR:longint);
var mid:integer;
begin
if LL<RR then begin
mid:=(LL+RR) div 2;
MSort(LL,mid);
MSort(mid+1,RR);
Merge(LL,mid,mid+1,RR);
end
end;
begin
MSort(1,n);
end;
function is_sorted(L: list; n:longint;is_asc:boolean): boolean;
var
i: longint;
flag: boolean;
begin
flag := true;
i := 1;
while flag and (i < n) do begin
flag := ((L[i]<=L[i+1]) and (is_asc)) or (not(is_asc) and (L[i]>=L[i+1]));
i := i + 1;
end;
is_sorted := flag;
end;
begin
na := MaxDisp;
GenList(a, na);
writeln(na, ' random items:');
DispList(a, na);
writeln('Press <Enter> to sort the list in ascending order ...');
readln;
sort(a, na,is_asc);
DispList(a, na);
writeln('Sorted in ascending order: ', is_sorted(a, na,is_asc));
write('Press <Enter> to continue ...');
readln;
end.
Except for the blank parts, I understand what the other parts of the code are doing, including the first part of the procedure Merge, which I think is just merging the arrays in L into M, and I think the following part is writing about the cases in case i1 and i2 are larger than L1 and L2, but I don't understand what the problem if this happens or what should be done. After this the following parts of the procedure Merge I have no idea what it is supposed to be doing.
I don't know this language (indexes start at 1?), but this is what I think needs changing:
i1:=L1;
i2:=L2;
j:=1;
while (i1<=R1) and (i2<=R2) do begin
if (is_asc and (L[i1]<L[i2])) or not is_asc and (L[i1]<L[i2]) then begin
M[j]:=L[i1];
j:=j+1;
i1:=i1+1;
end
else begin
M[j]:=L[i2];
j:=j+1;
i2:=i2+1;
end;
// j:=________; // don't change j
end;
while(i1 <= R1) do begin // copy rest of run 1 if any elements
M[j]:=L[i1];
j:=j+1;
i1:=i1+1;
end
while(i2 <= R2) do begin // copy rest of run 2 if any elements
M[j]:=L[i2];
j:=j+1;
i2:=i2+1;
end
for(i = 1 to j) do begin // copy M back into L
L[i+L1-1] := M[j]; // I'm not sure about the -1
end
end;
I'm learning algorithms and I'm trying to make an algorithm that extracts numbers lets say n in [1..100] from a string. Hopefully I get an easier algorithm.
I tried the following :
procedure ReadQuery(var t : tab); // t is an array of Integer.
var
x,v,e : Integer;
inputs : String;
begin
//readln(inputs);
inputs:='1 2 3';
j:= 1;
// make sure that there is one space between two integers
repeat
x:= pos(' ', inputs); // position of the space
delete(inputs, x, 1)
until (x = 0);
x:= pos(' ', inputs); // position of the space
while x <> 0 do
begin
x:= pos(' ', inputs); //(1) '1_2_3' (2) '2_3'
val(copy(inputs, 1, x-1), v, e); // v = value | e = error pos
t[j]:=v;
delete(inputs, 1, x); //(1) '2_3' (2) '3'
j:=j+1; //(1) j = 2 (2) j = 3
//writeln(v);
end;
//j:=j+1; // <--- The mistake were simply here.
val(inputs, v, e);
t[j]:=v;
//writeln(v);
end;
I get this result ( resolved ) :
1
2
0
3
expected :
1
2
3
PS : I'm not very advanced, so excuse me for reducing you to basics.
Thanks for everyone who is trying to share knowledge.
Your code is rather inefficient and it also doesn't work for strings containing numbers in general.
A standard and performant approach would be like this:
type
TIntArr = array of Integer;
function GetNumbers(const S: string): TIntArr;
const
AllocStep = 1024;
Digits = ['0'..'9'];
var
i: Integer;
InNumber: Boolean;
NumStartPos: Integer;
NumCount: Integer;
procedure Add(Value: Integer);
begin
if NumCount = Length(Result) then
SetLength(Result, Length(Result) + AllocStep);
Result[NumCount] := Value;
Inc(NumCount);
end;
begin
InNumber := False;
NumCount := 0;
for i := 1 to S.Length do
if not InNumber then
begin
if S[i] in Digits then
begin
NumStartPos := i;
InNumber := True;
end;
end
else
begin
if not (S[i] in Digits) then
begin
Add(StrToInt(Copy(S, NumStartPos, i - NumStartPos)));
InNumber := False;
end;
end;
if InNumber then
Add(StrToInt(Copy(S, NumStartPos)));
SetLength(Result, NumCount);
end;
This code is intentionally written in a somewhat old-fashioned Pascal way. If you are using a modern version of Delphi, you wouldn't write it like this. (Instead, you'd use a TList<Integer> and make a few other adjustments.)
Try with the following inputs:
521 cats, 432 dogs, and 1487 rabbits
1 2 3 4 5000 star 6000
alpha1beta2gamma3delta
a1024b2048cdef32
a1b2c3
32h50s
5020
012 123!
horses
(empty string)
Make sure you fully understand the algorithm! Run it on paper a few times, line by line.
I got this error when trying to compile.
left side cannot be assign to, ./number 21,22 in pastebin
here is my code
Program urut;
Uses Wincrt;
Const N = 5;
data: Array [1..N] Of Integer = (2,4,5,3,1);
Var
j,k,temp : Integer;
Begin
Clrscr;
Writeln ('Data sebelum diurutkan');
For j:=1 To N Do
Begin
Writeln('data[' ,j, ']= ',data [j]);
End;
For j:=1 To N-1 Do
Begin
For k :=N Downto j+1 Do
Begin
If data[k] < data[k-1] Then
Begin
temp := data[k];
data[k] := data[k-1]; //left side cannot be assigned to
data[k-1] := temp; //left side cannot be assigned to
End;
End;
End;
Writeln;
Writeln ('Data setelah diurutkan ');
For j:=1 To N Do
Begin
Writeln ('data[' ,j, '] = ',data[j]);
End;
Writeln;
End.
sorry for uncorrectly pattern post
, thank you so much.
Like tom Tom Brunberg says, my array is const, it can't be changed. Therefore I need to remove that const.
So it should be
data: Array [1..5] Of Integer = (value);
without const, and put it under var with another variable
what I am trying to do, is determine, whether brackets are in correct order. For example ([][[]]<<>>) is vallid, but ][]<<(>>) is not.
I got a working version, but it has terrible efficiency and when it gets 1000+ brackets, its just crazy slow. I was hoping someone might suggest some possible improvements or another way to do it.
Here is my code:
program Codex;
const
C_FNAME = 'zavorky.in';
var TmpChar : char;
leftBrackets, rightBrackets : string;
bracketPos : integer;
i,i2,i3 : integer;
Arr, empty : array [0..10000] of String[2];
tfIn : Text;
result : boolean;
begin
leftBrackets := ' ( [ /* ($ <! << ';
rightBrackets := ' ) ] */ $) !> >> ';
i := 0;
result := true;
Assign(tfIn, C_FNAME);
Reset(tfIn);
{ load data into array }
while not eof(tfIn) do
begin
while not eoln(tfIn) do
begin
read(tfIn, TmpChar);
if (TmpChar <> ' ') then begin
if (TmpChar <> '') then begin
Arr[i] := Arr[i] + TmpChar;
end
end
else
begin
i := i + 1;
end
end;
i2 := -1;
while (i2 < 10000) do begin
i2 := i2 + 1;
{if (i2 = 0) then
writeln('STARTED LOOP!');}
if (Arr[i2] <> '') then begin
bracketPos := Pos(' ' + Arr[i2] + ' ',rightBrackets);
if (bracketPos > 0) then begin
if (i2 > 0) then begin
if(bracketPos = Pos(' ' + Arr[i2-1] + ' ',leftBrackets)) then begin
{write(Arr[i2-1] + ' and ' + Arr[i2] + ' - MATCH ');}
Arr[i2-1] := '';
Arr[i2] := '';
{ reindex our array }
for i3 := i2 to 10000 - 2 do begin
Arr[i3 - 1] := Arr[i3+1];
end;
i2 := -1;
end;
end;
end;
end;
end;
{writeln('RESULT: ');}
For i2:=0 to 10 do begin
if (Arr[i2] <> '') then begin
{write(Arr[i2]);}
result := false;
end;
{else
write('M');}
end;
if (result = true) then begin
writeln('true');
end
else begin
writeln('false');
end;
result := true;
{ move to next row in file }
Arr := empty;
i := 0;
readln(tfIn);
end;
Close(tfIn);
readln;
end.
The input data in the file zavorky.in look for example like this:
<< $) >> << >> ($ $) [ ] <! ( ) !>
( ) /* << /* [ ] */ >> <! !> */
I determine for each row whether it is valid or not. Max number of brackets on a row is 10000.
You read chars from your file. File read in byte-by-byte mode is very slow. You need to optimize the way to read the strings (buffers) instead or load the file in memory first.
Hereunder I propose the other way to process the fetched string.
First I declare the consts that will state the brackets that you might have:
const
OBr: array [1 .. 5{6}] of string = ('(', '[', '/*', '<!', '<<'{, 'begin'});
CBr: array [11 .. 15{16}] of string = (')', ']', '*/', '!>', '>>'{, 'end'});
I decided to do this as now you are not limited to the length of the brackets expression and/or number of brackets' types. Every closing and corresponding opening bracket has index difference equal to 10.
And here is the code for the function:
function ExpressionIsValid(const InputStr: string): boolean;
var
BracketsArray: array of byte;
i, Offset, CurrPos: word;
Stack: array of byte;
begin
result := false;
Setlength(BracketsArray, Length(InputStr) + 1);
for i := 0 to High(BracketsArray) do
BracketsArray[i] := 0; // initialize the pos array
for i := Low(OBr) to High(OBr) do
begin
Offset := 1;
Repeat
CurrPos := Pos(OBr[i], InputStr, Offset);
if CurrPos > 0 then
begin
BracketsArray[CurrPos] := i;
Offset := CurrPos + 1;
end;
Until CurrPos = 0;
end; // insert the positions of the opening brackets
for i := Low(CBr) to High(CBr) do
begin
Offset := 1;
Repeat
CurrPos := Pos(CBr[i], InputStr, Offset);
if CurrPos > 0 then
begin
BracketsArray[CurrPos] := i;
Offset := CurrPos + 1;
end;
Until CurrPos = 0;
end; // insert the positions of the closing brackets
Setlength(Stack, 0); // initialize the stack to push/pop the last bracket
for i := 0 to High(BracketsArray) do
case BracketsArray[i] of
Low(OBr) .. High(OBr):
begin
Setlength(Stack, Length(Stack) + 1);
Stack[High(Stack)] := BracketsArray[i];
end; // there is an opening bracket
Low(CBr) .. High(CBr):
begin
if Length(Stack) = 0 then
exit(false); // we can not begin an expression with Closing bracket
if Stack[High(Stack)] <> BracketsArray[i] - 10 then
exit(false) // here we do check if the previous bracket suits the
// closing bracket
else
Setlength(Stack, Length(Stack) - 1); // remove the last opening
// bracket from stack
end;
end;
if Length(Stack) = 0 then
result := true;
end;
Perhaps, we do an extra work by creating a byte array, but it seems that this method is i) more easy to understand and ii) is flexible as we can change the length of brackets expressions for example use and check begin/end brackets etc.
Appended
As soon as I see that the major problem is in organizing block reading of file I give here an idea of how to do it:
procedure BlckRead;
var
f: file;
pc, pline: { PChar } PAnsiChar;
Ch: { Char } AnsiChar;
LngthLine, LngthPc: word;
begin
AssignFile(f, 'b:\br.txt'); //open the file
Reset(f, 1);
GetMem(pc, FileSize(f) + 1); //initialize memory blocks
inc(pc, FileSize(f)); //null terminate the string
pc^ := #0;
dec(pc, FileSize(f)); //return the pointer to the beginning of the block
GetMem(pline, FileSize(f)); //not optimal, but here is just an idea.
pline^ := #0;//set termination => length=0
BlockRead(f, pc^, FileSize(f)); // read the whole file
//you can optimize that if you wish,
//add exception catchers etc.
LngthLine := 0; // current pointers' offsets
LngthPc := 0;
repeat
repeat
Ch := pc^;
if (Ch <> #$D) and (Ch <> #$A) and (Ch <> #$0) then
begin // if the symbol is not string-terminating then we append it to pc
pline^ := Ch;
inc(pline);
inc(pc);
inc(LngthPc);
inc(LngthLine);
end
else
begin //otherwise we terminate pc with Chr($0);
pline^ := #0;
inc(LngthPc);
if LngthPc < FileSize(f) then
inc(pc);
end;
until (Ch = Chr($D)) or (Ch = Chr($A)) or (Ch = Chr($0)) or
(LngthPc = FileSize(f));
dec(pline, LngthLine);
if LngthLine > 0 then //or do other outputs
Showmessage(pline + #13#10 + Booltostr(ExpressionIsValid(pline), true));
pline^ := #0; //actually can be skipped but you know your file structure better
LngthLine := 0;
until LngthPc = FileSize(f);
FreeMem(pline); //free the blocks and close the file
dec(pc, FileSize(f) - 1);
FreeMem(pc);
CloseFile(f);
end;
You are saving all the data into memory (even couple of times) and then you have a lot of checks. I think you are on the right track but there are much easier steps you could follow.
Make an array of integers (default = 0) with length the number of brackets you have (e.g. ' ( [ /* ($ <! << ' ==> 6)
Now to make sure that you are following the requirements. Read the file line by line and take into account only the first 10000. This could help.
Every time you find an element from the first array (e.g. leftBrackets) add +1 to the value of the coresponding index of the array of step 1. Example would be:
'[' ==> checkArray[1] += 1
Do the same for rightBrackets but this time check if the value is larger than 0. If yes then subtract 1 the same way (e.g. ']' ==> checkArray[1] -= 1) otherwise you just found invalid bracket
I hope this helps and Good luck.
I think the following should work, and will be order O(n), where n is the length of the string. First build two function.
IsLeft(bra : TBracket) can determine if a bracket is a left bracket or a right bracket, so IsLeft('<') = TRUE, IsLeft('>>') = FALSE.
IsMatchingPair(bra, ket : TBracket) can determine if two brackets are of the same 'type', so IsMatchingPair('(',')') =TRUE, but IsMatchingPair('{','>>') = FALSE.
Then build a stack TBracketStack with three functions procedure Push(bra : TBracket), and function Pop : TBracket, and function IsEmpty : boolean.
Now the following algorithm should work (with a little extra code required to ensure you don't fall off the end of the string unexpectedly):
BracketError := FALSE;
while StillBracketsToProcess(BracketString) and not BracketError do
begin
bra := GetNextBracket(BracketString);
if IsLeft(bra) then
Stack.Push(bra)
else
BracketError := Stack.IsEmpty or not IsMatchingPair(Stack.Pop,bra)
end;
I have written a recursive Tree Function in pascal ( or delphi ) but i had an 'Out of Memory' message when I ran it.
I need to turn the Calculate recursive function in this code to non-recursive function, can you tell me how please :
program testing(input, output);
type
ptr = ^tr;
tr = record
age: byte;
left, right: ptr;
end;
var
topper: ptr;
total, day: longint;
procedure mycreate(var t: ptr);
var
temp:ptr;
begin
new(temp);
temp^.age := 1;
temp^.left := nil;
temp^.right := nil;
t := temp;
end;
procedure gooneday(var t: ptr);
begin
if t^.age <> 5 then
begin
if t^.age = 2 then
mycreate(t^.left)
else if t^.age = 3 then
mycreate(t^.right);
t^.age := t^.age + 1;
total := total + 1;
end;
end;
procedure calculate(var crnt: ptr);
begin
if crnt <> nil then
begin
gooneday(crnt);
calculate(crnt^.left);
calculate(crnt^.right);
end;
end;
begin
total := 0;
mycreate(topper);
day := 0;
while total < 1000000000000 do
begin
total := 0;
day := day + 1;
calculate(topper);
end;
writeln(day);
writeln(total);
end.
Recursive functions use a stack to keep the state of the recursion.
When converting to a loop, you must actually create an explicit stack. You must push and pop elements off the stack within the loop.