I'm trying to make a Latin Square program that accepts a user-entered size of square (e.g. entering 5 will generate a Latin Square 5x5) and then output the formatted square to the user.
If you don't know what a Latin Square is or want to see the actual task I have been set, look no further.
I have slightly coded some of this, but I'm failing at the first hurdle. Teachers are providing no help, you lot are my only hope.
uses
System.SysUtils;
var
// Variables
// 2D array, size defined in main code
Square: array of array of integer;
// Integer holding the square size
SquareSize: integer;
begin
// Introduction
writeln('This program will generate a Latin Squar of a size designated by you.');
// Ask for user input, receive and store in a variable
write('Enter the size of the Latin Square (1 value): ');
readln(SquareSize);
// More user friendly garbage
writeln('Latin Square size: ', SquareSize, ' x ', SquareSize, '.');
// Calculations
// Set size of the 2D array to user designated dimensions
setlength(Square, SquareSize, SquareSize);
end.
After the last line of code (setlength) I want to set ALL values in my new 2D array to the user-entered number. I think.
Other than that, I have no clue what I'm doing.
If you want to help me, please can you try to keep it as simple as possible so I can understand it?
Sorry for any screw-ups made in this, first time on Stack Overflow.
The link you gave also gives the answer, see below the code.
program LatinSquare;
{$APPTYPE CONSOLE}
type
TSquare = array of array of Integer;
procedure WriteLatinSquare(var Square: TSquare; N: Integer);
var
X, Y: Integer;
begin
{ Allocate and fill the square array. }
SetLength(Square, N, N);
for Y := 0 to High(Square) do
for X := 0 to High(Square[Y]) do
Square[X, Y] := (Y + X) mod N + 1;
{ Display the Square array. }
for Y := 0 to High(Square) do
begin
for X := 0 to High(Square[Y]) do
Write(Square[X, Y]:3);
Writeln;
end;
Writeln;
end;
var
Square: TSquare;
SquareSize: Integer;
begin
SquareSize := 6;
WriteLatinSquare(Square, SquareSize);
Readln;
end.
As the link says: start with 1 2 3 4 5 6, then the next line, shift by one, so that becomes 2 3 4 5 6 1, etc... That is what the first part (with the X, Y loops) does: it fills the square.
Of course, Y + X can go over the limit of 0..5 (I add the 1 later on), so you use mod to wrap the values around, so 6 becomes 0, 7 becomes 1, etc. In effect:
1st line: 0+0=0 -> 0, 0+1=1 -> 1, 0+2=2 -> 2, 0+3=3 -> 3, 0+4=4 -> 4, 0+5=5 -> 5
2nd line: 1+0=1 -> 1, 1+1=2 -> 2, 1+2=3 -> 3, 1+3=4 -> 4, 1+4=5 -> 5, 1+5=6 -> 0
3rd line: 2+0=2 -> 2, 2+1=3 -> 3, 2+2=4 -> 4, 2+3=5 -> 5, 2+4=6 -> 0, 2+5=7 -> 1
etc...
Then you add the 1, so instead of 0 1 2 3 4 5you get 1 2 3 4 5 6.
The second part of the routine just prints the Square array.
If you don't need to save the square, it can be done in one part:
procedure WriteMagicSquare2(N: Integer);
var
X, Y: Integer;
begin
for Y := 0 to N - 1 do
begin
for X := 0 to N - 1 do
Write((Y + X) mod N + 1, ' ');
Writeln;
end;
Writeln;
end;
Output (for N = 6):
1 2 3 4 5 6
2 3 4 5 6 1
3 4 5 6 1 2
4 5 6 1 2 3
5 6 1 2 3 4
6 1 2 3 4 5
Assuming your in my school given this is the exact homework I have from the same book word for word. On note of the code above I will add one point, the Latin squares size should be user entered so in the last block of code change it to this:
var
Square: TSquare;
X, UserI, SquareSize: Integer;
begin
X := 0;
Writeln('type -1000 to stop the loop');
repeat
Writeln('What size square do you want?');
readln(UserI);
if UserI = -1000 then
begin
goto gotolable;
end
else
SquareSize := UserI;
WriteLatinSquare(Square, SquareSize);
writeln ('Press enter to do another Latin square');
readln;
until X = 1;
gotolable:
Related
I have an output txtfile with some float numbers and I like to print in different formats, y try with:
FormatFloat('00000;000.0;00.00', val)
FormatFloat('00.00;000.0;00000', val)
But I take wrong outputs. What I need is:
If val < 10 then output like '00.00'
If 10 < val < 100 then output like '000.0'
If val > 100 then output like '00000'
It's a huge amount of float values, so, I need a low processing solution and I think more conditionals will slow down the application. ¿Any advice?
Thank you
Using conditional tests to sort the values into separate outputs is not going to affect performance in a significant way. The format process is far more elaborate. One important thing about optimization is to only walk that path if you can measure a performance hit in the actual code.
if (val < 10) then
s := FormatFloat('00.00',val)
else
if (val < 100) then
s := FormatFloat('000.0',val)
else
s := FormatFloat('00000',val);
Also consider using the thread-safe FormatFloat with a supplied FormatSettings variable.
I suppose that conditionals would work faster, but consider this sketch (care about out-of-range values):
const
FormatString: array[-1..2] of string = ('0.000', '0.00', '0.0', '0');
var
x: Double;
i: integer;
begin
x := 0.314;
for i := 1 to 4 do begin
Memo1.Lines.Add(FormatFloat(FormatString[Floor(Log10(x))], x));
x := x * 10;
end;
0.314
3.14
31.4
314
Hello I cant write the combination algorithm. For example; I have 1 Red and 2 White balls and I want to write number red balls + number white balls. Like below;
R->Red
W->White
RWW
WRW
WWR
totally 3 combinasion I have. But How can I write it in Delpi? Because, may be I have 10 RED 8 White or 15 RED 20 White etc.. How can I oreder this kombination.
I have one rules .
1- I have to use all balls eveytime. My order, combination Length has to be total ball. In my example it has to be 2+1=3.
how can I do this?
procedure Combination( pLeft : string;pRedCount, pWhiteCount : integer; pResult : strings );
begin
if (pRedCount = 0) and (pWhiteCount = 0) then
begin
pResult.Add( pLeft );
exit;
end;
if pRedCount > 0 then Combination( pLeft + 'R', pRedCount - 1, pWhiteCount, pResult );
if pWhiteCount > 0 then Combination( pLeft + 'W', pRedCount, pWhiteCount - 1, pResult )
end;
For example if in your main program you had a TMemo called Memo, a spinedit called RCount and another called WCount, then on your action button you would execute
Memo.Lines.Clear
Combination( '', RCount.Value, WCount.Value, Memo.Lines );
Hi there =) And sorry for my English, in advance
I have a task to calculate hurst exponent by method of linear regression. And I have text description of solution. It looks very easy, but always i get values, that go out from range 0..1. Usually, value is 1.9 or something similar. Sometimes it gets negative value that is close to zero.
I have looked over code about thousand times but couldn't see a mistake.
var
max_z,min_z,x_m:real; //max and min of cumulative sum and mean value of X for every Tau
st,ss,sst,st2 :real;
Al, Herst: real;
x_vr:array of double; //a piece of array with length=tau
i, j, nach: integer;
begin
//file opening and getting values of X array are in another function
nach:=3; //initial value of tau
Setlength(ln_rs,l-nach); //length of ln(R/S) array
Setlength(ln_t,l-nach); //length of ln(tau) array
Setlength(r,l-nach); //length of R array
Setlength(s,l-nach); //length of S array
//Let's start
for tau:=nach to l do //we will change tau
begin
Setlength(x_vr,tau+1); //set new local array (length=tau)
for i:=0 to length(x_vr)-1 do
x_vr[i]:=x[i];
x_m:=Mean(x_vr); //mean value
Setlength(y,tau+1); //length of array of difference from mean value
Setlength(z,tau+1); //length of array of cumulative sum
for i:=0 to tau do
y[i]:=x_vr[i]-x_m; //difference from mean value
z[0]:=y[0];
for i:=1 to tau do //cumulative sum
for j :=i downto 0 do
z[i]:=z[i]+y[j];
max_z:=z[0];
for i:=1 to tau do //max of cumulative sum
max_z:=max(max_z,z[i]);
min_z:=z[0];
for i:=1 to tau do //min of cumulative sum
min_z:=min(min_z,z[i]);
r[tau-nach]:=max_z-min_z; //R value
s[tau-nach]:=0;
for i:=0 to tau do
s[tau-nach]:=power(y[i],2)+s[tau-nach]; //S value
s[tau-nach]:=sqrt(s[tau-nach]/(tau+1));
//new array values
ln_rs[tau-nach]:=Ln(R[tau-nach]/S[tau-nach]); // ln(R/S)
ln_t[tau-nach]:=ln(tau); // ln (tau)
end; //End of calculating
//Method of Least squares
for i:=0 to length(ln_rs)-1 do
st:=st+ln_t[i];
st:=(1/length(ln_rs))*st;
for i:=0 to length(ln_rs)-1 do
ss:=ss+ln_rs[i];
ss:=(1/length(ln_rs))*ss;
for i:=0 to length(ln_rs)-1 do
sst:=sst+ln_t[i]*ln_rs[i];
sst:=(1/length(ln_rs))*sst;
for i:=0 to length(ln_rs)-1 do
st2:=st2+ln_t[i]*ln_t[i];
st2:=(1/length(ln_rs))*st2;
Herst:=(sst-st*ss)/(st2-st*st); //coefficient of approximal function
al:=ss-st*Herst;
Thanks everybody =)
P.S.
for tau:=nach to l do
There is L, not 1. And L is Length of X array. And L>nach always besides last step, when l=nach.
P.P.S.
It works, guys. But values are not right. And they go out from range. Maybe, there is mistake in algorithm. Or maybe I skiped some step.
Last Update
It's mystic, but i only changed method of calculating array Z and it started works correctly....
Thanks all =)
First thing I see:
nach := 3;
for tau := nach to l do //w
This counts up. And because nach>1, the body of this loop won't be executed.
If you expect to count down. Use the downto variant. To count down:
for tau := nach downto l do //w
Given that the main loop (for tau) iterates from nach to l, the first four SetLength calls should set the length of l - nach + 1 instead of l - nach.
Should the line
z[i]:=z[i]+y[j];
not be
z[i]:=z[i - 1]+y[j];
?
I'm working on a programming problem.
Note: This is not a student project. I am working on this for a new Quest for the website Try My Quest Dot Com, for which i am the admin.
Problem:
Jenny just started work as a programmer for Justine's Java Workshop. She is paid $10
an hour, with a few exceptions. She earns an extra $1.50 an hour for any part of a day where she works more than 8 hours, and an extra $2.50 an hour for hours beyond 40 in any one week. Also, she earns a 125% bonus for working on Saturday, and a 50% bonus for working on Sunday. The bonuses for Saturday and Sunday are computed based on the hours worked those days; they are not used to calculate any bonus for working more than 40 hours in a week. You'll be given the number of hours Jenny worked each day in a week (Sunday, Monday, etc ), and you need to compute her salary for the week. The input will be positive integers, less than or equal to 24. The output must be formatted with a dollar sign and rounded up to the nearest penny. For example, $2" and $2.136666" are wrong answers; the correct versions are $2.00" and $2.14", respectively.
Anyway, i am trying to write this in Delphi (No form project). I pass the program a command line argument - timecard.dat
input
0, 8, 8, 8, 8, 8, 0
0, 10, 10, 10, 10, 10, 0
0, 0, 8, 8, 8, 8, 8
0, 0, 0, 10, 10, 10, 10
10, 10, 10, 9, 9, 9, 9
Output
Output #1: $400.00
Output #2: $540.00
Output #3: $500.00
Output #4: $540.75
Output #5: $905.88
My Out put however is:
Output #1: $400.00
Output #2: $540.00
Output #3: $500.00
Output #4: $537.00
Output #5: $902.50
The last two output values of mine are different from the actual results. Not sure why, and the more i stare at the code, the less i see it
Can anyone tell me what i have done wrong?
program ACSL_Time_Cards;
{assumes Sunday = 1, Monday 3, etc}
uses
SysUtils,
Dialogs;
const
HourlyWage = 10.00;
OverEightWage = 1.50;
OverFortyWage = 2.50;
var
F: TextFile;
I, ArrayIndex: Integer;
WeeklyHours: Array[0..6] of Integer; //weekly hours
HourStr, LineStr: String;
TotalHours, TotalOverFortyHours, TotalOverEightHours, TotalSatHours, TotalSunHours: Integer;
TotalWages: Real;
begin
//initialize variables
TotalHours:= 0;
TotalOverEightHours:= 0;
TotalOverFortyHours:= 0;
TotalSatHours:= 0;
TotalSunHours:= 0;
TotalWages:= 0.00;
ArrayIndex:= 0;
//open file "timecard.dat" for input
if FileExists(ParamStr(1)) then
begin
AssignFile(F, ParamStr(1));
Reset(F);
//step through file and extract each line and store in hoursStr
while not EOF(F) do
begin
Readln(F, LineStr);
//step through hours string and fill Array with weekly hours
for I:= 1 to length(LineStr) do
begin
//if character is not a ',' then add it to hourStr
if LineStr[I] <> ',' then
HourStr:= HourStr + LineStr[I]
else
begin
//add HourStr to Array
WeeklyHours[ArrayIndex]:= StrToInt(HourStr);
//reset the variable
HourStr:= '';
//increment Variable
Inc(ArrayIndex);
end; //else
end; //for I:= 1 to length(HoursStr) do
//clean up by adding the last remaining one
WeeklyHours[ArrayIndex]:= StrToInt(HourStr);
//step through array and figure out overtime Daily and Weekly
for I:= Low(WeeklyHours) to High(WeeklyHours) do
begin
TotalHours:= TotalHours + WeeklyHours[I];
if WeeklyHours[I] > 8 then
TotalOverEightHours:= TotalOverEightHours + WeeklyHours[I]-8;
//get sunday hours
if I + 1 = 1 then
TotalSunHours:= TotalSunHours + WeeklyHours[I];
//get saturday hours
if I + 1 = 7 then
TotalSatHours:= TotalSatHours + WeeklyHours[I];
end;
//get total over 40 hours
if TotalHours > 40 then
TotalOverFortyHours:= TotalHours-40;
//compute Regular Hours
TotalWages:= TotalWages + TotalHours * 10.00;
//compute overtime hours
TotalWages:= TotalWages + TotalOverEightHours * 1.50;
TotalWages:= TotalWages + TotalOverFortyHours * 2.50;
//compute bonuses
TotalWages:= TotalWages + (TotalSatHours * 10.00) * 1.25;
TotalWages:= TotalWages + (TotalSunHours * 10.00) * 0.50;
ShowMessage('TotalWages: ' + FormatFloat('$0.00', TotalWages));
//reset variables
TotalWages:= 0.00;
TotalHours:= 0;
TotalOverEightHours:= 0;
TotalOverFortyHours:= 0;
TotalSatHours:= 0;
TotalSunHours:= 0;
HourStr:= '';
ArrayIndex:= 0;
end; //while not EOF(F) do
CloseFile(F);
end
else
ShowMessage('File does not exist!');
end.
I'm sure there are many ways that this could have been written better. I really am just interested in why my values different from the expected values. Thanks!
For a simple problem like this, you might want to write it out by hand and then see if your code follows the same steps you did.
For Output 4, the 125% bonus for Saturday is not including the $1.50 per hour extra after 8:
she should earn
Wed: $103 | $100 for 10 hours plus $3 for 2 hours over 8
Thu: $103 | $100 for 10 hours plus $3 for 2 hours over 8
Fri: $103 | $100 for 10 hours plus $3 for 2 hours over 8
Sat: $231.75 | ($100 for 10 hours, $3 for 2 hours over 8), $128.75 for 125% bonus
for a total of 540.75
The code would benefit from the I/O and the calculation being separated. You problems are with the calculation. I'd write it something like this:
uses
Math;
type
TDay = (
daySunday,
dayMonday,
dayTuesday,
dayWednesday,
dayThursday,
dayFriday,
daySaturday
);
TDayArray = array [TDay] of Integer;
function Wage(const Hours: TDayArray): Double;
const
BasicRate = 10.0;
DailyOvertimeRate = 1.5;
WeeklyOvertimeRate = 2.5;
DailyOvertimeThreshold = 8;
WeeklyOvertimeThreshold = 40;
DailyBonus: array [TDay] of Double = (1.5, 1.0, 1.0, 1.0, 1.0, 1.0, 2.25);
var
Day: TDay;
DailyOvertimeHours, WeeklyOvertimeHours, TotalHours: Double;
DailyPay: array [TDay] of Double;
begin
TotalHours := 0.0;
for Day := low(Day) to high(Day) do begin
TotalHours := TotalHours + Hours[Day];
DailyOvertimeHours := Max(Hours[Day]-DailyOvertimeThreshold, 0.0);
DailyPay[Day] := Hours[Day]*BasicRate;
DailyPay[Day] := DailyPay[Day] + DailyOvertimeHours*DailyOvertimeRate;
DailyPay[Day] := DailyPay[Day]*DailyBonus[Day];
end;
WeeklyOvertimeHours := Max(TotalHours-WeeklyOvertimeThreshold, 0.0);
Result := Sum(DailyPay) + WeeklyOvertimeHours*WeeklyOvertimeRate;
end;
This is still a little unpolished and I'm not very happy with the variable names for pay rates, overtime etc.
Once have such a utility function available, then putting it together with the rest of your program becomes a lot easier.
The biggest weakness in your current program is that everything is housed in one giant routine. Break it down into small pieces and you'll be able to verify those small pieces more readily than hunting for problems in a single large routine.
Find this by yourself by learning How to debug a Delphi program.
Pay atention to this parts:
Watches - you add a watch to track the values of program variables or expressions as you step over or trace into code.
Breakpoints - when pressing the F5 button or clicking on the left bar in your editor you can add a red line to your source. This line of source will have a breakpoint. When running the program, the execution will stop when it passes the source line. Now you can trace into your source by using some function keys.
I am using a multi-dimensional dynamic array in delphi and am trying to figure this out:
I have 2 seperate values for the first index and second index that are totally seperate of each other.
As new values come I want to grow the array if that new value is outside of either bound.
For new values x, y
I check:
if Length(List) < (x + 1) then
SetLength(List, x + 1);
if Length(List[0]) < (y + 1) then
SetLength(List, Length(List), y + 1);
Is this the correct way to do this or is there a better way to grow the array as needed?
It looks fine to me - if you change the last line to
SetLength(List, Length(List), y + 1);
I think you forgot to use the second index on the second dimension;
Your code should probably read like this :
if Length(List) < (x + 1) then
SetLength(List, x + 1);
if Length(List[x]) < (y + 1) then
SetLength(List[x], y + 1);
Note the use of 'x' as the first dimension index when growing the second dimension.
One caution though :
You should be aware of the fact that Delphi uses reference-counting on dynamic arrays too (just like how it's done with AnsiString).
Because of this, growing the array like above will work, but any other reference to it will still have the old copy of it!
The only way around this, is keeping track of these array's with one extra level of indirection - ie. : Use a pointer to the dynamic array (which is also a pointer in itself, but that's okay).
Also note that any of those 'external' pointers should be updated in any situation that the address of the dynamic array could change, as when growing/shrinking it using SetLength().
#PatrickvL:
Sorry, but that is just plain wrong. Your code does not even compile because it tries to set two dimensions for the single-dimensional element List[x]. (PatrickvL updated his code so this part of the answer is no longer valid.)
The following code demonstrates multidimensional array resizing.
program TestDimensions;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
List: array of array of integer;
begin
//set both dimensions
SetLength(List, 3, 2);
Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 3, Y = 2
//set main dimension to 4, keep subdimension untouched
SetLength(List, 4);
Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 4, Y = 2
//set subdimension to 3, keep main dimenstion untouched
SetLength(List, Length(List), 3);
Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 4, Y = 3
//all List[0]..List[3] have 3 elements
Writeln(Length(List[0]), Length(List[1]), Length(List[2]), Length(List[3])); //3333
//you can change subdimension for each List[] vector
SetLength(List[0], 1);
SetLength(List[3], 7);
//List is now a ragged array
Writeln(Length(List[0]), Length(List[1]), Length(List[2]), Length(List[3])); //1337
//this does not even compile because it tries to set dimension that does not exist!
// SetLength(List[0], Length(List[0]), 12);
Readln;
end.
The Delphi help also explains this quite nicely (Structured Types, Arrays).
Multidimensional Dynamic Arrays
To declare multidimensional dynamic arrays, use iterated array of ... constructions. For example,
type TMessageGrid = array of array of string;
var Msgs: TMessageGrid;
declares a two-dimensional array of strings. To instantiate this array, call SetLength with two integer arguments. For example, if I
and J are integer-valued variables,
SetLength(Msgs,I,J);
allocates an I-by-J array, and Msgs[0,0] denotes an element of that array.
You can create multidimensional dynamic arrays that are not rectangular. The first step is to call SetLength, passing it parameters for the first n dimensions of the array. For example,
var Ints: array of array of Integer;
SetLength(Ints,10);
allocates ten rows for Ints but no columns. Later, you can allocate the columns one at a time (giving them different lengths); for example
SetLength(Ints[2], 5);
makes the third column of Ints five integers long. At this point (even if the other columns haven't been allocated) you can assign values to the third column - for example, Ints[2,4] := 6.
The following example uses dynamic arrays (and the IntToStr function declared in the SysUtils unit) to create a triangular matrix of strings.
var
A : array of array of string;
I, J : Integer;
begin
SetLength(A, 10);
for I := Low(A) to High(A) do
begin
SetLength(A[I], I);
for J := Low(A[I]) to High(A[I]) do
A[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' ';
end;
end;