I'm making a number-to-speech program. I have all of the voice samples all recorded, and working, but every time the input has the numbers in sequential order (012... etc.), it will begin playing the rest of the numbers to 9, against the input.
For example, if 24601 is typed, it will say:
2..4..6..0..1..2..3..4..5..6..7..8..9..0..
It's not supposed to do that. It will even over-ride the remaining numbers with the sequence, if there are any.
Full code: http://pastebin.com/vFfBRYUu
Here's the offending code block. If you need the remaining pieces, I'll put them up:
procedure TForm1.Button1Click(Sender: TObject);
begin
for i := 0 to Length(input.Text) do
begin
case var1[i] of
'0': PlaySound('zero.wav',0,SND_SYNC);
'1': PlaySound('one.wav',0,SND_SYNC);
'2': PlaySound('two.wav',0,SND_SYNC);
'3': PlaySound('three.wav',0,SND_SYNC);
'4': PlaySound('four.wav',0,SND_SYNC);
'5': PlaySound('five.wav',0,SND_SYNC);
'6': PlaySound('six.wav',0,SND_SYNC);
'7': PlaySound('seven.wav',0,SND_SYNC);
'8': PlaySound('eight.wav',0,SND_SYNC);
'9': PlaySound('nine.wav',0,SND_SYNC);
'-': Delay(400);
'&': PlaySound('start.wav',0,SND_SYNC);
'*': PlaySound('call to mess.wav',0,SND_SYNC);
end;
Delay(100);
end;
The input-to-array:
procedure TForm1.inputChange(Sender: TObject);
begin
y := y+1;
var1[y-1] := input.Text[y]
end;
y variable seems to never reset, which means you append the text to a var1. But you play the text-length of elements from var1 always starting from the 0 element.
Input Text | Stored text | Played text
0123 0123 0123
876 0123876 012
12345678 012387612345678 01238761
111 012387612345678111 012
Sounds like a bug.
Also there is number of mistakes:
Seeing it always plays much too many numbers, input.Text length is not reset properly
You iterate over input.Text but you play from var1 variable. You should always iterate and access the same array/string!
The loop should be for i := 1 to Length(input.Text) do if you iterate over a string
Relying on hidden knowledge of text start position in var1
Might be just your example, but you haven't closed the for loop with a end;
Meaningless / non-speaking variable names
Formatting (I have fixed it in your question, plz check)
You might also do some debugging on your own, to isolate the bug, by outputting the var1 to display before "speaking" it. E.g. by ShowMessage(var1) or alike;
Related
I have to find out the biggest number from a txt file. Numbers are for example:
9 8 7 6 5
Someone told me, that it should works, but it didn't, and I have no clue how to work with file bcs.
program file;
uses crt;
var i,count,help:integer;
numb:array [1..9] of integer;
f:text;
begin
clrscr;
assign(f,'file1.txt');
reset(f);
readln(f,count);
for i:=1 to count do
readln(f,numb[i]);
close(f);
for i:=2 to count do
begin
if (numb[i-1] < numb[i]) then
help:=numb[i-1];
numb[i-1]:=numb[i];
numb[i]:=help;
end;
for i:=1 to count do
begin
write(numb[i]);
end;
readln;
end.
If you only want to know the highest number, you can use a running maximum while reading the numbers in the file.
As a user you don't have to know how many numbers there are in the file. The program should determine that.
I wrote a little test file, called file1.txt:
9 8 7 6 3 11 17
32 11 13 19 64 11 19 22
38 6 21 0 37
And I only read the numbers, comparing them with Max. That is all you need.
No need to read the data into an array and
no need to (try to) sort the data. You only want the highest number, right?
And there is also no need for the user to know or enter the number of numbers in the text file.
program ReadMaxNumber;
uses
Crt;
var
Max, Num: Integer;
F: Text;
begin
ClrScr;
Assign(F, 'file1.txt');
Reset(F);
Max := -1;
while not Eof(F) do
begin
Read(F, Num);
if Num > Max then
Max := Num;
end;
Close(F);
Writeln('Maximum = ', Max);
Readln;
end.
When I run this, the output is as expected:
Maximum = 64
There are a few mistakes in the code provided:
The program name is file. The program name cannot be a keyword;
You read from the file the variable count, but the actual value cannot be found in the file, so count=0. For this reason, the for loop which reads the data from the file is never executed. You either read it from a file or from the keyboard (in the solution below, I chose the second option);
You use readln when you read from the file. readln moves the cursor on the next line after it reads the data. This means that only the first number, 9, is stored into numb. Replace readln with read;
At the second for loop, you say that if ... then. If you want all the three instructions to be executed (and I think you do, because it's an exchange of values), put them between begin and end. Otherwise, only the first instruction is executed if the condition is true, the others are always been executed;
The method to determine the maximum is an overkill. Better if you take a variable, max, which initially gets the value of the first element in the array, then you cycle in the remaining values to see if a value is higher than max.
The final code looks like this:
program file1;
uses crt;
var i,count,help, max:integer;
numb:array [1..9] of integer;
f:text;
begin
clrscr;
assign(f,'file1.txt');
reset(f);
writeln('Please input a number for count :');
readln(count);
for i:=1 to count do
read(f,numb[i]);
close(f);
max:=numb[1];
for i:=2 to count do
if numb[i]>max then
max:=numb[i];
write('The result is: ',max);
readln;
end.
I need to construct a matrix; a number of columns and rows are also in the first row of the matrix, I'll make an example so its more clearer.
4 3
1 2 3
5 6 7
9 10 8
1 11 13
Where m=4 (number of rows) and n=3 (number of columns)
This is an example of a text file. Is something like this even possible?
Program Feb;
const
max=100;
type
Matrix=array[1..max,1..max] of integer;
var datoteka:text;
m,n:integer;
counter:integer;
begin
assign(datoteka,'datoteka.txt');
reset(datoteka);
while not eoln(datoteka) do
begin
read(datoteka, m);
read(datoteka, n);
end;
repeat
read eoln(n)
until eof(datoteka)
write (m,n);
end.
My code isn't a big help, cause I don't know how to write it.
First, have a look at the code I wrote to do the task, and then look at my explanation below.
program Matrixtest;
uses
sysutils;
var
NoOfCols,
NoOfRows : Integer;
Source : TextFile;
Matrix : array of array of integer;
FileName : String;
Row,
Col : Integer; // for-loop iterators to access a single cell of the matrix
Value : Integer;
begin
// First, construct the name of the file defining the matrix
// This assumes that the file is in the same folder as this app
FileName := ExtractFilePath(ParamStr(0)) + 'MatrixDef.Txt';
writeln(FileName); // echo it back to the screen so we can see it
// Next, open the file
Assign(Source, FileName);
Reset(Source);
read(Source, NoOfRows, NoOfCols);
writeln('Cols: ', NoOfCols, 'Rows: ', NoOfRows);
SetLength(Matrix, NoOfCols, NoOfRows);
readln(source); // move to next line in file
// Next, read the array data
for Row := 1 to NoOfRows do begin
for Col := 1 to NoOfCols do begin
read(Source, Value);
Matrix[Col - 1, Row - 1] := Value;
end;
end;
// Display the array contents
for Row := 1 to NoOfRows do begin
for Col := 1 to NoOfCols do begin
writeln('Row: ', Row, ' contents', Matrix[Col - 1, Row - 1]);
end;
end;
Close(Source); // We're done with the file, so close it to release OS resources
readln; // this waits until you press a key, so you can read what's been displayed
end.
In your program, you can use a two-dimensional array to represent your matrix. Free Pascal supports multi-dimensional arrays; see https://wiki.lazarus.freepascal.org/Multidimensional_arrays for more information.
This is a complex task, so it helps to know how to do more basic things like reading an array of a size known at compile-time from a text file.
The wrinkle in this task is that you are supposed to read the dimensions (numbers of rows and columns) of the matrix at run-time from the file which contains the matrix's contents.
One inefficient way to do this would be to declare the matrix array with huge dimensions, larger than anything you would expect in practice, using the type of array declaration in the Wiki page linked above.
A better way is to use dynamic arrays, whose dimensions you can set at run-time. To use this, you need to know:
How to declare a dynamic array in Free Pascal
How to set the dimensions of the array at run-time, once you've picked them up from your matrix-definition file (hint: SetLength is the way to do this)
The fact that a Free Pascal dynamic array is zero-based
The easiest way of managing zero-based arrays is to write your code (in terms of Row and Column variables) as if the matrix were declared as array[1..NoOfRows, 1..NoOfColumns] and subtract one from the array indexes only when you actually access the array, as in:
Row := 3;
Column := 4;
Value := Matrix[Row - 1, Column - 1];
PROGRAM approvedapplicants(input,output);
uses crt;
var
applcntname,housingcomm,clarendon_court,providence_gardens,
sangre_grande_villas:string;
slry,spcslry:integer;
c_qual_sal,s_qual_sal,p_qual_sal,qualifying_salary:integer;
BEGIN
writeln('enter applicant name, salary, spouce salary');
readln(applcntname,slry,spcslry);
writeln('enter housing community');
readln(housingcomm);
BEGIN
qualifying_salary:=0;
IF(housingcomm=clarendon_court)
then
qualifying_salary:=$12500;
writeln('you have selected clarendon court!');
readln(c_qual_sal) ;
end if ;
else if(housingcomm=sangre_grande_villas)then
qualifying_salary:=$9500;
writeln('you have selected sangre grande villas!');
readln(s_qual_sal);
end if ;
else(housingcomm=providence_gardens)then;
qualifying_salary:=$7500;
writeln('you have selected providence gardens!');
readln(p_qual_sal);
end if;
END.
Ordinarily, on SO, we don't post answers to homework/coursework, but your code is so far wide of the mark that I think it's ok to make an exception in this case.
Try compiling and running this program, which I think does pretty much what I think you are intending, then I'll explain a few things about it:
program approvedapplicants(input,output);
uses crt;
var
ApplicantName,
HousingCommunity,
ClarendonCourt,
ProvidenceGardens,
SangreGrandVillas :string;
Salary,
SpouseSalary,
QualifyingSalary : Integer;
CQualSal,
PQualSal,
SQualSal : Integer;
slry,spcslry:integer;
begin
ClarendonCourt := 'Clarendon Court';
ProvidenceGardens := 'Providence Gardens';
SangreGrandVillas := 'Sangre Grand Villas';
QualifyingSalary := 0;
writeln('enter applicant name');
readln(ApplicantName);
writeln('enter salary');
readln(Salary);
writeln('enter spouse salary');
readln(SpouseSalary);
writeln('enter housing community');
readln(HousingCommunity);
if (HousingCommunity = ClarendonCourt) then begin
QualifyingSalary := $12500;
writeln('you have selected clarendon court!');
readln(CQualSal);
end
else
if(HousingCommunity = SangreGrandVillas)then begin
QualifyingSalary := $9500;
writeln('you have selected sangre grande villas!');
readln(SQualSal);
end
else
if HousingCommunity = ProvidenceGardens then begin
QualifyingSalary :=$7500;
writeln('you have selected providence gardens!');
readln(CQualSal);
end;
end.
Firstly, notice how much easier it is to read and follow its logic. This is mainly
because of
The use of a layout (including indented blocks) which reflects the logical
structure of the code.
The use of consistent, lower case for keywords like program, begin, end, etc.
Keywords are usually the least interesting contents of source code, and it is distracting
to have them SHOUTing at you.
The avoidance of arbitrarily dropping characters from variable names (like the "i"
and second "a" of "applicant". In the days of interpreted code running on slow machines there was
argubably some justification for this, but not any more imo. Likewise, the avoidance
of underscores in variable names - admittedly this is more of a personal preference, but
why have you used them everywhere except the applicant's name?
Secondly, you still have quite a bit of work to do.
Having 3 different variables for the salary (?) numbers you prompt the user
for, one for each of the 3 communities, is probably a bad idea unless you will
subsequently want to work with all 3 figures at the same time. Also, you haven't provided text prompts to tell the user what information to enter for the readln(c_qual_sal) etc statements. It wasn't obvious to me what you intend, so I have not tried to guess.
The way you echo the user's choice of community is just creating you a maintenance
headache (what if you want to add more communities later?). It would be better
to have a variable which you set to whichever of the community names matches
what the user has entered.
You have 3 statements to execute for each community, which are duplicated for
each community. The only one you actually need is the QualifyingSalary one -
the others can execute regardless of the inputted community.
I have more of a 'problem solving' question than a syntax related problem.
Briefly, I'm creating a program that will read a text file full of words (that may feasibly be a list of passwords), one word per line - I'll be using ReadLn for that bit in a loop. For every word it finds, I want it to add "an amount" of obfuscation in line with how users these days will use '3' instead of 'E' in their passwords, or '1' instead of 'I'. I work in the IT security field and password breaking is often part of it and that's what the program is for.
I have managed to create the program so far that it generates a LEET table full of many different values for each letter of the alphabet and stacks them in a StringGrid that I can access as part of the process (and it is also outputted visually to a table).
type
TLetters = 'A'..'Z';
TLeet = array[TLetters] of TStringList;
var
SourceFileName, str : string;
StartIndexFile : TextFile;
i : TLetters;
leet : TLeet;
s : string;
n, o, ColumnSize : integer;
begin
for i in TLetters do
leet[ i ] := TStringList.Create;
// The next sequence of loops populates the string grid by counting the number of characters for each letter of the alphabet and then inserting them down, column by column and row by row...
//Letter A:
s := '4 # /-\ /\ ^ aye ∂ ci λ Z';
ColumnSize := wordcount(s,[' ']);
o := 0;
for n := 0 to ColumnSize do
leet['A'].Add(ExtractWord(n,s,[' ']));
for o := 0 to ColumnSize do
StringGrid1.Cells[1,o] := Leet['A'][o];
// And so on for B - Z
// ... then an OpenDialog that opens the source text file to read. Got that sorted
// A load of file opening stuff and then the obsfucation
repeat
Readln(StartIndexFile, Str);
LblProgress.Caption := ('Parsing Index File...please wait');
OBSFUCATE THE WORDS HERE TO SOME EXTENT
// but now I have hit a barrier....
until(EOF(StartIndexFile));
My problem is this : given the word 'Edward', for example, how do I decide to what level I should obfuscate it? Just the first letter 'E' to be replaced with a '3', and nothing more perhaps? Or the first two letters 'E' and 'd' to be replaced with ALL the values in the LEET table for both of the letters E and d (meaning dozens of new words would be generated from 'Edward', and so on), or all the values for 'E' but nothing else...the list goes on. Potentially, for every word, I could create thousands of additional one's! A 100Gb source file would soon become terabytes!
In other words, I need to set "a level" for which the program will function, that the user can decide. But I'm not sure how to structure that level?
So I'm not sure how to make it work? I didn't really think it through enough before I started. My initial thoughts were "It would be cool to have a program that would take an index of words from a computer, and then generate variations of every word to account for people who obfuscate characters." but having come to code it, I've realised it's a bigger job than I thought and I am now stuck at the section for actually 'LEETing my input file'!
You could use a level (0-10) as input.
0: replace nothing
10: replace all letters with LEET letters.
Depending on the length of the word, you calculate how many letters to replace and just replace random letters in the word, so that you not always replace the first letter for level 1 etc.
This snippet not only causes a runtime error, it makes FPC close if I run it using the debugger.
procedure sortplayersbyscore(var vAux:tplayers);
procedure swap(var a:trplayers;var b:trplayers);
var
rAux:trplayers;
begin
rAux:=a;
a:=b;
b:=rAux;
end;
var
i,j:integer;
sorted:boolean;
begin
vAux:=playersarray;
i:=1;
sorted:=false;
while (i <= MAXPLAYERS -1) and not sorted do
begin
j:=1;
sorted:=true;
while (j <= MAXPLAYERS -i) do
begin
if (vAux[j].score < vAux[j+1].score) then
begin
swap(vAux[j],vAux[j+1]);
sorted:=false;
end;
inc(j);
end;
inc(i);
end;
end;
The code itself is part of a really big source file, I can post the whole thing but the responsible for the error is just that bunch of lines. The debugger terminates at line:
swap(vAux[j],vAux[j+1]);
tplayers is just a type defined as an array of records that contain score (an integer) among a bunch of other variables. trplayers is the type of the aforementioned records. I'm at a total loss; FPC (while not under debugging mode) spits an out-of-range error but under my watches I see that the variables I'm trying to read exist. Any help is really appreciated!
rAux:trplayers; have you typed a wrong symbol or the type here really contains "r" in its name?
It looks valid (other than typos) ... so let's try something simple.
What's the value of "j" when you abort?
If the debugger won't tell you, try adding:
writeln ('j = ', j);
just before the "swap" call.
As Yochai's question implied, your array needs to be dimensioned at least from
1 (or lower) to MAXPLAYERS (or larger). (I.e.: 0..MAXPLAYERS-1 would not work,
but 1..MAXPLAYERS should.)