program words;
uses crt;
type
T2DArray = array[1..100, 1..100] of string;
var
ch:char;
x,y:integer;
MapArray: T2DArray;
begin
x:=0;
y:=0;
repeat
MapArray[10, 10] := 'you are at a tree';
writeln(MapArray[x,y]);
write('current positon is ');
write(x);write(',');write(y);
ch:=ReadKey;
case ch of
#0 : begin
ch:=ReadKey; {Read ScanCode}
case ch of
'w' : y:=y+1;
'a' : x:=x-1;
's' : y:=y-1;
'd' : x:=x+1;
end;
end;
#27 : WriteLn('ESC');
end;
until ch=#27;
readln;
end.
i have this simple piece of code that will allow me to assign things to XY coordinates of a 2d array. the code compiles and closes straight away despite the readln; at the bottom.
All the best Arran.
Always enable range-checking {$R+} during development. You have a 1-based array but your x and y values are zero the first time you read from it.
Related
I'm embarrassed to admit that I cannot understand why in this very simple example that the "readln(age);" statement in the "else if" clause ignores the first integer entered in response to the "writeln('How old are you ',name:length(name),'?');" statement around line 16.
It seems clear that the culprit is the "ch := readkey;" statement on line 18.
To enter a valid age, some key must first be pressed (other than (ASCII 13) which is trapped by the "if ch = #13 then" statement.
It does not seem to matter if the "age" variable is typed as a string or integer.
What happens is that if one enters two characters or integers, only the second is stored in the "age" variable. For example, to input an age of "25", I must first press some other key on the keyboard first, then enter "25" for "25" to be stored in the "age" variable.
Any help understanding this would be sincerely appreciated. Perhaps the entire approach is incorrect?
PROGRAM t5;
uses crt;
var
name,age : string;
ch : char;
procedure greet;
begin
clrscr;
writeln('What''s your name? ');
readln(name);
clrscr;
writeln('Hi, ',name:length(name));
writeln('How old are you ',name:length(name),'?');
ch := readkey;
if ch = #13 then
begin
writeln('Please enter a valid age!');
writeln ('You pressed the ','"','Enter','"',' key ','("',ord(ch),'")');
readln;
writeln('Bye!');
readln;
end
else if ch <> #13 then
begin
readln(age);
writeln('Gee, ',age,', - that''s really old!');
readln;
end;
end;
BEGIN
greet;
END.
ReadKey() reads one character (and removes it) from the keyboard buffer.
The problem is in this sequence:
ch := ReadKey; // the first digit is now in `ch`
if ch = #13 then // this condition is false
...
else if ch <> #13 then // this condition is true
begin
readln(age) // user types the second digit and <Enter>
// then you use age, but you have omitted the first character which is in `ch`
end;
Instead, use only ReadLn() and check that the returned characters are a proper number.
Im having problems with this code, I have two file of char, one is filed with information about books, and the other is empty, i have to write in SAL some information from S and then show the total of how many books match the first 2 digits of the code and how many are R and how many are T. The code, does write the information form S to Sal, but when its supposed to show the totals it appears ERORR 100 on screen. I read about it and it says that it is a problem with 'Disk read error' and that *This error typically occurs, if you "seed" a non-existent record of a typed file and try to read/write it. *, i really dont undertand.
I've benn trying to figure it out, but I haven't been able to. I notice that if I dont put 'WHILE NOT EOF(S) DO' the error does not appear, but of course i need the while, if someone is able to point out my mistakes i would really apreciate it.
This is the code:
uses crt;
var
i : byte;
s,sal: file of char;
v,l1,l2: char;
cs,cn,cl: integer;
pn,ps,tot: integer;
BEGIN
cs:=0; cn:=0; i:=0; cl:=0;
Assign (s, 'C:\Users\te\Documents\s.txt');
{$I-}
Reset (s);
{$I+}
if IOResult <> 0 then
begin
writeln('Error');
halt(2);
end;
Assign (sal, 'C:\Users\te\Documents\sal.txt');
{$I-}
Rewrite (sal);
IOResult;
{$I+}
if IOResult <> 0 then
halt(2);
writeln('Please write the code of the book, only 2 digits');
read(L1);read(L2);
read(s,v);
while (not eof(s)) do
begin
for i:=1 to 2 do
read(s,v);
if (v = '0') then
begin
read(s,v);
if (v = '1') or (v = '2') then
begin
for i:=1 to 5 do
read(s,v);
if (v = 'R') then
begin
read(s,v);
cs:= cs + 1;
end
else
begin
if (v = 'T') then
begin
cn:= cn + 1;
read(s,v);
end;
end;
while (v <> '-') do
read(s,v);
while (v = '-') do
read(s,v);
if (v = L1) then
begin
write(sal, v);
read(s,v);
if (v = L2) then
begin
write(sal,v);
read(s,v);
cl:= cl + 1;
end;
end;
while ( v <> '/') do
begin
write(sal,v);
read(s,v);
end;
write(sal, '-');
end
else
begin
for i:= 1 to 5 do
read(s,v);
if (v = 'R') then
cs:= cs + 1
else
cn:= cn + 1;
if (v = L1) then
read(s,v);
if (v = L2) then
begin
cl:= cl + 1;
read(s,v);
end;
end;
end
else
begin
for i:= 1 to 5 do
read(s,v);
if (v = 'R') then
cs:= cs + 1
else
cn:= cn + 1;
if (v = L1) then
read(s,v);
if (v = L2) then
begin
cl:= cl + 1;
read(s,v);
end;
end;
end;
tot:= cs + cn;
ps:= (cs * 100) div tot;
pn:= (cn * 100) div tot;
writeln('TOTAL ',cl);
writeln();
writeln(ps,'% and',pn,'%');
The file S content:
02022013Rto kill a mockingbird-1301/02012014Tpeter pan-1001/02032013Thowto-2301/02012012Tmaze runner-1001/02012012Tmaze runner-1001/02012012Tmaze runner-1001/$
I really just need someone else's point of view on this code, I think maybe the algorithm is flawed.
Thanks
(After your edit, i see that your code now compiles w/o error in FPC, so I'm glad you've managed to fix the error yourself)
As this is obviously coursework, I'm not going to fix your code for you and in any case the wayEven so, I'm afraid you are going about this is completely wrong.
Basically, the main thing wrong with your code is that you are trying to control what happens as your read the source file character by character. Quite frankly, that's a hopeless way of trying to do it, because it makes the execution flow unnecessarily complicated and littered with ifs, buts and loops. It also requires you to keep mental track of what you are trying to do at any given step, and the resulting code is inherently not self-documenting - imagine if you came back to your code in six months, could you tell at a glance how it works and what it does? I certsinly couldn't personally.
You need to break the task down in a different way. Instead of analysing the problem from the bottom up ("If I read this character next, then what I need to do next is ...') do it from the top down: Although your input file is a file of char, it contains a series of strings, separated by a / character and finally terminated by a $ (but this terminator does not really matter). So what you need to do is to read these strings one-by-one; once you've got one, check whether it's the one you're looking for: if it is. process it however you need to, otherwise read the next one until you reach the end of the file.
Once you have successfully read one of the book strings, you can then split it up into the various fields it's composed of. The most useful function for doing this splitting is probably Copy, which lets you extract substrings from a string - look it up in the FPC help. I've included functions ExtractTitle and ExtractPreamble which show you what you need to do to write similar functions to extract the T/R code and the numeric code which follows the hyphen. Btw, if you need to ask a similar q in the future, it would be very helpful if you include a description of the layout and meaning of the various fields in the file.
So, what I'm going to show you is how to read the series of strings in your S.Txt by building them character-by-character. In the code below, I do this using a function GetNextBook which I hope is reasonable self-explanatory. The code uses this function in a while loop to fill the BookRecord string variable. Then, it simply writes the BookRecord to the console. What your code should do, of course, is to process the BookRecord contents to see if it is the one you are looking for and then do whether the remainder of your task is.
I hope you will agree that the code below is a lot clearer, a lot shorter and will be a lot easier to extend in future than the code in your q. They key to structuring a program this way is to break the program's task into a series of functions and procedures which each perform a single sub-task. Writing the program that way makes it easier to "re-wire" the program to change what it does, without having to rewrite the innards of the functions/procedures.
program fileofcharproject;
uses crt;
const
sContents = '02022013Rto kill a mockingbird-1301/02012014Tpeter pan-1001/02032013Thowto-2301/02012012Tmaze runner-1001/02012012Tmaze runner-1001/02012012Tmaze runner-1001/$';
InputFileName = 'C:\Users\MA\Documents\S.Txt';
OutputFileName = 'C:\Users\MA\Documents\Sal.Txt';
type
CharFile = File of Char; // this is to permit a file of char to be used
// as a parameter to a function/procedure
function GetNextBook(var S : CharFile) : String;
var
InputChar : Char;
begin
Result := '';
InputChar := Chr(0);
while not Eof(S) do begin
Read(S, InputChar);
// next, check that the char we've read is not a '/'
// if it is a '/' then exit this while loop
if (InputChar <> '/') then
Result := Result + InputChar
else
Break;
end;
end;
function ExtractBookTitle(BookRecord : String) : String;
var
p : Integer;
begin
Result := Copy(BookRecord, 10, Length(BookRecord));
p := Pos('-', Result);
if p > 0 then
Result := Copy(Result, 1, p - 1);
end;
procedure AddToOutputFile(var OutputFile : CharFile; BookRecord : String);
var
i : Integer;
begin
for i := 1 to Length(BookRecord) do
write(OutputFile, BookRecord[i]);
write(OutputFile, '/');
end;
function ExtractPreamble(BookRecord : String) : String;
begin
Result := Copy(BookRecord, 1, 8);
end;
function TitleMatches(PartialTitle, BookRecord : String) : Boolean;
begin
Result := Pos(PartialTitle, ExtractBookTitle(BookRecord)) > 0;
end;
var
i : Integer; //byte;
s,sal: file of char;
l1,l2: char;
InputChar : Char;
BookFound : Boolean;
cs,cn,cl: integer;
pn,ps,tot: integer;
Contents : String;
BookRecord : String;
PartialTitle : String;
begin
// First, create S.Txt so we don't have to make any assumptions about
// its contents
Contents := sContents;
Assign(s, InputFileName);
Rewrite(s);
for i := 1 to Length(Contents) do begin
write(s, Contents[i]); // writes the i'th character of Contents to the file
end;
Close(s);
cs:=0; cn:=0; i:=0; cl:=0;
// Open the input file
Assign (s, InputFileName);
{$I-}
Reset (s);
{$I+}
if IOResult <> 0 then
begin
writeln('Error');
halt(2);
end;
// Open the output file
Assign (sal, OutputFileName);
{$I-}
Rewrite (sal);
IOResult;
{$I+}
if IOResult <> 0 then
halt(2);
// the following reads the BookRecords one-by-one and copies
// any of them which match the partial title to sal.txt
writeln('Enter part of a book title, followed by [Enter]');
readln(PartialTitle);
while not Eof(s) do begin
BookRecord := GetNextBook(S);
writeln(BookRecord);
writeln('Preamble : ', ExtractPreamble(BookRecord));
writeln('Title : ', ExtractBookTitle(BookRecord));
if TitleMatches(PartialTitle, BookRecord) then
AddToOutputFile(sal, BookRecord);
end;
// add file '$' to sal.txt
write(sal, '$');
Close(sal);
Close(s);
writeln('Done, press any key');
readln;
end.
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.
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.
I'm using Pascal. I have a problem when dealing with reading file.
I have a file with integer numbers. My pascal to read the file is:
read(input, arr[i]);
if my file content is 1 2 3 then it's good but if it is 1 2 3 or 1 2 3(enter here) (there is a space or empty line at the end) then my arr will be 1 2 3 0.
From what I can recall read literally reads the file as a stream of characters, of which a blank space and carriage return are, but I believe these should be ignored as you are reading into an integer array. Does your file actually contain a space character between each number?
Another approach would be to use readLn and have the required integers stored as new lines in the file, e.g.
1
2
3
I have tested the problem on Delphi 2009 console applications. Code like this
var
F: Text;
A: array[0..99] of Integer;
I, J: Integer;
begin
Assign(F, 'test.txt');
Reset(F);
I:= -1;
while not EOF(F) do begin
Inc(I);
Read(F, A[I]);
end;
for J:= 0 to I do write(A[J], ' ');
Close(F);
writeln;
readln;
end.
works exactly as you have written. It can be improved using SeekEOLN function that skips all whitespace characters; the next code does not produce wrong additional zero:
var
F: Text;
A: array[0..99] of Integer;
I, J: Integer;
begin
Assign(F, 'test.txt');
Reset(F);
I:= -1;
while not EOF(F) do begin
if not SeekEOLN(F) then begin
Inc(I);
Read(F, A[I]);
end
else Readln(F);
end;
for J:= 0 to I do write(A[J], ' ');
Close(F);
writeln;
readln;
end.
Since all that staff is just a legacy in Delphi, I think it must work in Turbo Pascal.
You could read the string into a temporary and then trim it prior to converting it.
It doesnt hurt to mention basics like what type of Pascal on what platform you're using in order that people can give a specific answer (as the article notes, there isnt a nice way OOTB in many Pascals)
If I recall there was a string function called Val that converts a string to a number...my knowledge of Pascal is a bit rusty (Turbo Pascal v6)
var
num : integer;
str : string;
begin
str := '1234';
Val(str, num); (* This is the line I am not sure of *)
end;
Hope this helps,
Best regards,
Tom.