I keep getting the full alphabet with this program when I only want the letter.
How do I get the specific letter?
var
Form1: TForm1;
mysq : array[1..26] of TPanel;
implementation
…
procedure TForm1.mySqMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
i, a: integer;
begin
a := StrToInt(lab_leftn.Caption);
lab_leftn.Caption := IntToStr(a - 1);
if lab_leftn.Caption = IntToStr(0) then
begin
ShowMessage('You have lost');
lab_leftn.Caption := IntToStr(0);
end;
for i := 1 to 26 do
ed_guessed.Text := ed_guessed.Text + mysq[i].Caption;
end;
Assuming mySqMouseDown has been assigned to all TPanel OnMouseDown event, then the correct code is this one:
procedure TForm1.mySqMouseDown(
Sender : TObject;
Button : TMouseButton;
Shift : TShiftState;
X, Y : Integer);
var
i, a: integer;
begin
a := StrToInt(lab_leftn.Caption);
lab_leftn.Caption := IntToStr(a - 1);
if lab_leftn.Caption = IntToStr(0) then begin
ShowMessage('You have lost');
lab_leftn.Caption := IntToStr(0);
end;
ed_guessed.Text := (Sender as TPanel).Caption;
end;
Related
I am studying Pascal and have a problem.
My code needs to make combinations of four numbers, from left to right but I want to prevent those combinations from repeating the same thing being the numbers in positions, but worth the same thing from right to left.
Does anyone have any idea how to do that?
program mistureba;
type
placa = array [1..4] of integer;
var
a4num : array [1..24] of placa; // a4num : array [1..24,1..4] of integer
linha : integer;
const
MAXDIG = 4;
procedure mistura(input : placa; index : integer);
// input tem a série de digitos da placa
// index indica a posição que inicia o arranjo
var
output : placa;
p, i : integer;
begin
if index = MAXDIG then
begin // mostra / insere a sequencia que está em input
//for i := 1 to MAXDIG do
//write(input);
//writeln;
a4num[linha] := input;
linha := linha + 1;
end
else
begin
output := input;
for p := index to MAXDIG do
begin
output[index] := input[p];
for i := index to p - 1 do
output[i + 1] := input;
for i := p + 1 to MAXDIG do
output := input;
mistura(output,index + 1);
end;
end;
end;
var
//a4num : placa;
p, i : integer;
begin
linha := 1;
for i := 1 to MAXDIG do
readln(a4num[linha, i]);
mistura(a4num[linha], 1);
// vou mostrar o conteúdo do meu conjunto de placas
for linha := 1 to 24 do
if [i, 1] = [i, 4] then
begin
for i := 1 to MAXDIG do
write(a4num[linha, i]);
writeln;
end
else
begin
writeln('0');
end;
if [i,2] = [i,3] then
begin
for i := 1 to MAXDIG do
write(a4num[linha, i]);
writeln;
end
else
begin
writeln('0');
end;
end.
It was still not very clear what you wanted, so here are four solutions. You can choose the one you like:
program license;
uses
classes;
type
tIntegers = array of integer;
procedure BuildPermutation(aInput : string; aUsedCharacters : tIntegers; aBuild : string; var aOutput : tStringList);
var
i, j : integer;
Used : boolean;
begin
for i := 1 to length(aInput) do
begin
Used := false;
for j := 0 to length(aBuild) -1 do
if aUsedCharacters[j] = i then
begin
Used := true;
break;
end;
if not Used then
begin
aUsedCharacters[length(aBuild)] := i;
aBuild := aBuild + aInput[i];
if length(aBuild) = length(aInput) then
aOutput.Add(aBuild)
else
BuildPermutation(aInput, aUsedCharacters, aBuild, aOutput);
SetLength(aBuild, length(aBuild) - 1);
end;
end;
end;
function AllPermutations(aInput : string) : tStringList;
var
UsedCharacters : tIntegers = nil;
i : integer;
begin
result := tStringList.Create;
SetLength(UsedCharacters, length(aInput));
for i := 0 to length(UsedCharacters) - 1 do
UsedCharacters[i] := 0;
BuildPermutation(aInput, UsedCharacters, '', result);
end;
function WithoutDuplicatesSorted(aInput : tStringList) : tStringList;
// very easy using a built in feature of tStringList
var
OnePlate : string;
begin
result := tStringList.Create;
result.Sorted := true;
result.Duplicates := dupIgnore;
for OnePlate in aInput do
result.Add(OnePlate);
end;
function WithoutDuplicatesUnsorted(aInput : tStringList) : tStringList;
var
OnePlate : string;
begin
result := tStringList.Create;
for OnePlate in aInput do
if result.IndexOf(OnePlate) = -1 then
result.Add(OnePlate);
end;
function WithoutMirrors(aInput : tStringList) : tStringList;
var
OnePlate : string;
Mirror : string;
i : integer;
begin
result := tStringList.Create;
for OnePlate in aInput do
begin
Mirror := '';
for i := 1 to length(OnePlate) do
Mirror := OnePlate[i] + Mirror;
if result.IndexOf(Mirror) = -1 then
result.Add(OnePlate);
end;
end;
function WithoutMirrorsAndDuplicates(aInput : tStringList) : tStringList;
var
OnePlate : string;
Mirror : string;
i : integer;
begin
result := tStringList.Create;
for OnePlate in aInput do
if result.IndexOf(OnePlate) = -1 then
begin
Mirror := '';
for i := 1 to length(OnePlate) do
Mirror := OnePlate[i] + Mirror;
if result.IndexOf(Mirror) = -1 then
result.Add(OnePlate);
end;
end;
procedure PrintResult(aTitle : string; aInput : tStringList);
var
OnePlate : string;
begin
writeln(aTitle);
for OnePlate in aInput do
writeln(OnePlate);
end;
procedure Solve;
var
Input : string = '';
Intermediate : tStringList = nil;
FinalResult : tStringList = nil;
begin
// get one version of the license plate
// please note that it allows non-numeric characters
// if you want, you can insert a filtering, or any other mechanism to ensure only numeric license plates
writeln('Input one version of the license plate:');
readln(Input);
// make all possible permutations and print them
Intermediate := AllPermutations(Input);
PrintResult('All permutations', Intermediate);
// option 1 - filter identical ones (and also sorting them to make it easy)
FinalResult := WithoutDuplicatesSorted(Intermediate);
PrintResult('Without duplicates sorted', FinalResult);
FinalResult.Free;
// option 2 - filter identical ones (without sorting them, i.e. more complicated)
FinalResult := WithoutDuplicatesUnsorted(Intermediate);
PrintResult('Without duplicates unsorted', FinalResult);
FinalResult.Free;
// option 3 - filter mirrors (be careful, it is not defined which one of 123 and 321 will be shown!!!)
FinalResult := WithoutMirrors(Intermediate);
PrintResult('Without mirrors', FinalResult);
FinalResult.Free;
// option 3 - filter mirrors and duplicates
FinalResult := WithoutMirrorsAndDuplicates(Intermediate);
PrintResult('Without mirrors and duplicates', FinalResult);
FinalResult.Free;
Intermediate.Free;
end;
begin
Solve;
end.
When creating a procedural data type, Free Pascal throws a strange error. But I'm passing one parameter, why is the number of parameters incorrect?
Type
Func = Function (x:Real):Real;
Function middlfunc(a, b:Real; n:Integer; f:Func): Real;
Var
x,s,d: Real; k:Integer;
Begin
d:=(b-a)/n;
s:=0;
For k:=0 To n Do
Begin
x:=a+k*d;
s:=s+f(x);
End;
middlfunc:=s/(n+1);
End;
Function f1(x:Real):Real; {There is the error}
Begin
f1:=x*x;
End;
Var
mf1:Real;
a, b: real;
n: integer;
Begin
a := 0;
b := 3.1415;
n := 100;
mf1 := middlfunc(a,b,n,f1); {ERROR :((((((((}
WriteLn(mf1)
End.
USE PASCAL PROCEDURE INSTEAD OF FUNCTION for suitability
If you want to use a Function as a parameter to another function, then you have to do it like this:
Type
TFunctionParameter = function(x: Real): Real;
Function middlfunc(a, b:Real; n:Integer; f:TFunctionParameter): Real;
Var
x,s,d: Real; k:Integer;
Begin
d:=(b-a)/n;
s:=0;
For k:=0 To n Do
Begin
x:=a+k*d;
s:=s+f(x);
End;
middlfunc:=s/(n+1);
End;
function RaiseToSecondPower(x: Real): Real;
begin
result := x*x;
end;
Var
mf1:Real;
a, b: real;
n: integer;
Begin
a := 0;
b := 3.1415;
n := 100;
mf1 := middlfunc(a,b,n,RaiseToSecondPower);
WriteLn(mf1)
End.
Huge amount of numeric data (from a database) is stored in a Tstringlist variable. the Data may look like:
4
4 1/2
12.006
13 3/8
1.05
13.25
5 1/2
2.25
13 5/8
By setting the sort property of the Tstringlist to true, they are sorted as texts and as a result, 13.25 shows up before 4.
How can these data be sorted numerically (and efficiently)?
(Delphi, Rad Studio 10.4)
Here is a solution:
// Conversion accepting input like '4', '4.003', '4 1/2' or '1/4'
// No leading or trailing space allowed (use trim if required).
function MyStrToFloat(const S : String) : Double;
var
I, J : Integer;
FS : TFormatSettings;
begin
I := Pos('/', S);
if I > 0 then begin
// We have a fractional part
J := Pos(' ', S);
if J > 0 then
// Both integer and fractional parts
Result := StrToInt(Trim(Copy(S, 1, J - 1)))
else
Result := 0;
Result := Result + StrToInt(Trim(Copy(S, J + 1, I - J - 1))) /
StrToInt(Trim(Copy(S, I + 1)));
end
else begin
FS.DecimalSeparator := '.';
Result := StrToFloat(S, FS);
end;
end;
function StringListSortProc(
List : TStringList;
Index1 : Integer;
Index2 : Integer): Integer;
var
N1, N2: Double;
begin
N1 := MyStrToFloat(List[Index1]);
N2 := MyStrToFloat(List[Index2]);
if N1 > N2 then
Result := 1
else if N1 < N2 then
Result := -1
else
Result := 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
SL : TStringList;
S : String;
begin
SL := TStringList.Create;
try
SL.Add('4');
SL.Add('1/2');
SL.Add('4 1/2');
SL.Add('12.006');
SL.Add('13 3/8');
SL.Add('1.05');
SL.Add('13.25');
SL.Add('5 1/2');
SL.Add('2.25');
SL.Add('13 5/8');
Memo1.Lines.Add('Raw:');
for S in SL do
Memo1.Lines.Add(S);
SL.CustomSort(StringListSortProc);
Memo1.Lines.Add('Sorted:');
for S in SL do
Memo1.Lines.Add(S);
finally
SL.Free;
end;
end;
The conversion is done in the sorting which is not very efficient. It is probably better to create a new list with converted values and then sort it. Or convert when loading the list from database. You've got the idea...
Two components solve your problem:
StrCmpLogical is your friend. It uses Natural sorting - Digits in the strings are considered as numerical content rather than text.
And this SO post How do I enter fractions in Delphi?
I put it together below:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
ButtonSort: TButton;
Memo2: TMemo;
procedure ButtonSortClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
//Natural sorting - Digits in the strings are considered as numerical content rather than text. This test is not case-sensitive.
function StrCmpLogicalW(P1, P2: PWideChar): Integer; stdcall; external 'Shlwapi.dll';
function StrCmpLogical(const S1, S2: string): Integer;
var
Form1: TForm1;
implementation
{$R *.dfm}
function StrCmpLogical(const S1, S2: string): Integer;
begin
result := StrCmpLogicalW(PChar(S1), PChar(S2));
end;
function CustomNbrSort(List: TStringList; Index1, Index2: Integer): Integer;
begin
result := StrCmpLogical(List[index1], List[index2]);
end;
procedure DoCustomSort(const List : TStringList);
begin
List.CustomSort(CustomNbrSort);
end;
// https://stackoverflow.com/questions/18082644/how-do-i-enter-fractions-in-delphi
function FractionToFloat(const S: string): real;
var
BarPos: integer;
numStr, denomStr: string;
num, denom: real;
begin
BarPos := Pos('/', S);
if BarPos = 0 then
Exit(StrToFloat(S));
numStr := Trim(Copy(S, 1, BarPos - 1));
denomStr := Trim(Copy(S, BarPos + 1, Length(S)));
num := StrToFloat(numStr);
denom := StrToFloat(denomStr);
result := num/denom;
end;
function FullFractionToFloat(S: string): real;
var
SpPos: integer;
intStr: string;
frStr: string;
int: real;
fr: real;
begin
S := Trim(S);
SpPos := Pos(' ', S);
if SpPos = 0 then
Exit(FractionToFloat(S));
intStr := Trim(Copy(S, 1, SpPos - 1));
frStr := Trim(Copy(S, SpPos + 1, Length(S)));
int := StrToFloat(intStr);
fr := FractionToFloat(frStr);
result := int + fr;
end;
procedure TForm1.ButtonSortClick(Sender: TObject);
begin
var MyList : TStrings := TStringList.Create;
try
//MyList.Assign(Memo1.Lines);
var MyFormatSettings : TFormatSettings := FormatSettings; //Make a copy of the global variable;
MyFormatSettings.DecimalSeparator := '.'; //The system's seporator may be a comma ','
for var i : integer := 0 to Memo1.Lines.Count - 1 do begin
var s : string := Memo1.Lines[i];
if not s.Contains('.') then
s := FloatToStr(FullFractionToFloat(s), MyFormatSettings);
MyList.AddObject(s, TObject(i));
end;
TStringList(MyList).CustomSort(CustomNbrSort);
Memo2.Lines.Clear;
for var i : integer := 0 to Memo1.Lines.Count - 1 do
Memo2.Lines.Add(Memo1.Lines[Integer(MyList.Objects[i])]);
finally
MyList.Free;
end;
end;
end.
I have to read and modify some JSON files. The file encoding must be UTF8 without BOM or the JSON file will be not accepted.
I tried the following Code:
const
Utf8Bom = #$EF#$BB#$BF;
Utf16BomLE = #$FF#$FE; // little endian //
Utf16BomBE = #$FE#$FF; // big endian //
Utf16Bom = Utf16BomBE;
CP_UTF16 = 1200;
CP_UTF8 = 65001;
function WideStringToString (const wStr: string; codePage: Word): string;
var
len: Integer;
begin
len := WideCharToMultiByte (codePage, 0, wStr, -1, '', 0, 0, 0);
if len > 0 then
begin
SetLength (Result, len-1);
WideCharToMultiByte (codePage, 0, wStr, -1, Result, Length (Result), 0, 0);
end;
end;
function ClearBom(const s, sig: string): string;
var
i, n, len: Integer;
begin
Result := s;
len := Length (sig);
n := 0;
if (len> 0) and (Length (Result)> len) then
repeat
for i := 1 to len do
if Result [1] = sig [i] then
begin
Delete (Result, 1, 1);
Break;
end;
n := n + 1;
until (n = len) or (Result = '');
end;
function ConvertUtf16(const SourceStr: string; codePage: Word): string;
var
wStr: string;
begin
try
wStr := ClearBom(SourceStr, Utf16Bom);
Result := WideStringToString(wStr, codePage);
finally
SetLength(wStr, 0);
end;
end;
function Utf16ToUtf8(const SourceStr: string): string;
begin
Result := ConvertUtf16(SourceStr, CP_UTF8);
end;
function JSONSaveFile(const Filename: String; s: String): Boolean;
var
fs: TFileStream;
i, len : Integer;
begin
i := 1;
len := Length(s)
If len > 0 then
begin
try
try
fs := TFileStream.Create(Filename, fmCreate or f mShareExclusive);
fs.Seek(0, 0);
while (s[i] <> #0) and (i < len) do
begin
fs.WriteBuffer(s[i],CharLength(s,i));
i := i + CharLength(s,i);
end;
Result := True;
except
Log('EXCEPTION RAISED in JSONSaveFile: '+Filename);
end;
finally
fs.free;
end;
end;
end;
I get only a ANSI coded files. Build-in functions like SaveStringsToUTF8File() function will not work, cause the BOM is added by default.
Or is the a better way to save/create this text file with SaveStringToFile()?
How to solve it?
Use the WideCharToMultiByte function to convert the string to UTF-8 and just save it:
const
CP_UTF8 = 65001;
function WideCharToMultiByte(CodePage: UINT; dwFlags: DWORD;
lpWideCharStr: string; cchWideChar: Integer; lpMultiByteStr: AnsiString;
cchMultiByte: Integer; lpDefaultCharFake: Integer;
lpUsedDefaultCharFake: Integer): Integer;
external 'WideCharToMultiByte#kernel32.dll stdcall';
function GetStringAsUtf8(S: string): AnsiString;
var
Len: Integer;
begin
Len := WideCharToMultiByte(CP_UTF8, 0, S, Length(S), Result, 0, 0, 0);
SetLength(Result, Len);
WideCharToMultiByte(CP_UTF8, 0, S, Length(S), Result, Len, 0, 0);
end;
function SaveStringToUTF8FileWithoutBOM(FileName: string; S: string): Boolean;
var
Utf8: AnsiString;
begin
Utf8 := GetStringAsUtf8(S);
Result := SaveStringToFile(FileName, Utf8, False);
end;
You have to use Unicode version of Inno Setup (the only version as of Inno Setup 6).
See also:
LoadStringFromFileInCP and LoadStringsFromFileInCP functions in:
Inno Setup - Convert array of string to Unicode and back to ANSI
Inno Setup replace a string in a UTF-8 file without BOM
this is my simple code to generate
all possible combinations of a set for
example
1,2,3:
Display:
123
132
213
231
312
321
i want to create variable number of for loops to let the user determine the length of given string...
does anyone have an idea...
thank's in advance.
type
TNumber = '0'..'9';
procedure TForm1.Button1Click(Sender: TObject);
var
Numbers: array[0..3] of TNumber;
a, b, c, d: Integer;
s: string;
begin
Numbers[0] := '1';
Numbers[1] := '8';
Numbers[2] := '7';
Numbers[3] := '2';
for a := low(Numbers) to High(Numbers) do
for b := low(Numbers) to High(Numbers) do
for c := low(Numbers) to High(Numbers) do
for d := low(Numbers) to High(Numbers) do
begin
s := Numbers[a] + Numbers[b] + Numbers[c] + Numbers[d];
if
(Occurrences('1', s) > 1 ) or
(Occurrences('8', s) > 1 ) or
(Occurrences('7', s) > 1 ) or
(Occurrences('2', s) > 1 )
then
Continue
else
Memo1.Lines.Add(s);
end;
end;
function TForm1.Occurrences(const Substring, Text: string): Integer;
var
Offset: Integer;
begin
Result := 0;
Offset := PosEx(Substring, Text, 1);
while Offset <> 0 do
begin
Inc(Result);
Offset := PosEx(Substring, Text, offset + length(Substring));
end;
end;
end.
Here is some code that produces the output you desire. You'd need to work it around a bit for your needs, but the concept expressed in this recursive solution is the important thing:
program Permuatations;
{$APPTYPE CONSOLE}
type
TElements = '1'..'3';
procedure EnumerateCombinations(const Stem: string; Len: Integer);
var
i: Integer;
el: TElements;
Used: set of TElements;
begin
if Len=0 then
exit;
Used := [];
for i := 1 to Length(Stem) do
Include(Used, Stem[i]);
for el := low(el) to high(el) do
begin
if el in Used then
continue;
if Len=1 then
Writeln(Stem+el)
else
EnumerateCombinations(Stem+el, Len-1)
end;
end;
procedure Main;
begin
EnumerateCombinations('', 1+ord(high(TElements))-ord(low(TElements)));
end;
begin
Main;
Readln;
end.
Output:
123
132
213
231
312
321
If you change the definition of TElements, for example to '1'..'4' then you will see the 24 possible permutations.