Recent

Author Topic: Repeat Until combo is met  (Read 20066 times)

Harlequin

  • New Member
  • *
  • Posts: 10
Repeat Until combo is met
« on: November 05, 2013, 08:24:55 pm »
I had a rly long introducing message but while I was writting and organising things I kept finding errors and other stuff in the program that I ended up solving so now after several minutes I'm a bit tired so I'll be fast with the new problem! :D

Code: [Select]
repeat
(...)
until (ch='qqw' or 'qwq' or 'wqq');

The order doesn't matter, as long as there are two Q's and one W in the string it can come out of the loop. Anyone knows how can I accomplish that? :P

(I don't wanna be writting - or - or - or - or) any command to check for letters inside string?

Bart

  • Hero Member
  • *****
  • Posts: 5721
    • Bart en Mariska's Webstek
Re: Repeat Until combo is met
« Reply #1 on: November 05, 2013, 09:00:19 pm »
Assuming two q's and 1 w and the length of the string is always 3, the possible combinations are:
wqq
qwq
qqw
So there are only 3 combinations possible.

Yes you can make some algoritme to detect this, but in this case I would just go for the
Code: [Select]
(ch='qqw') or (ch='qwq') or (ch='wqq') (note the brackets).
Fancy function (untested):

Code: [Select]
function Has2QsAnd1W(Ch: String) Boolean;
var
  q,w,i: Integer;
begin
  q := 0;
  w := 0;
  for i := 1 to length(ch) do
  begin
    case ch[i] of
      'q': Inc(q);
      'w': Inc(w);
    end;//case
  end;
  Result := (Length(ch) = 3) and (q = 2) and (w = 1);
end;

Bart

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Repeat Until combo is met
« Reply #2 on: November 05, 2013, 09:03:46 pm »
I see Bart's post while i was typing mine, but this is very different...

For the 'w' you can use pos('w', ch)>0, but 'q' could have new function. Something like:
Code: [Select]
function CountLetters(s: string; letter: char; caseSensitive: boolean): integer;
var i: integer;
begin
  result:=0;
  if not caseSensitive then begin
    s:=lowercase(s);
    letter:=lowercase(letter);
  end;
  for i:=1 to length(s) do
    if s[i]=letter then inc(result);
end;

Of course after that them both are combined with 'and'...
Code: [Select]
repeat
(...)
until (pos('w', ch)>0) and (CountLetters(ch, 'q', true)=2) and (Length(ch)=3);
« Last Edit: November 06, 2013, 06:10:44 am by User137 »

eny

  • Hero Member
  • *****
  • Posts: 1665
Re: Repeat Until combo is met
« Reply #3 on: November 05, 2013, 10:01:16 pm »
Code: [Select]
  with TStringList.Create do
  begin
    Text := 'qqw' + LineEnding + 'qwq' + LineEnding + 'wqq';
    repeat
      //......
    until IndexOf(ch) >= 0;
    Free
  end;
All posts based on: Win11; stable Lazarus 4_4  (x64) 2026-02-12 (unless specified otherwise...)

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Repeat Until combo is met
« Reply #4 on: November 05, 2013, 11:11:58 pm »
Since ord(q) is $71 and ord(w) is $77:

Code: [Select]
var
  B: PByte;
..
repeat
(...)
  B := @ch[1];
until ((B[0] xor B[1] xor B[2])=$77);

sam707

  • Guest
Re: Repeat Until combo is met
« Reply #5 on: November 05, 2013, 11:15:57 pm »
Another different approach

Code: [Select]
function checkwq(Value: string): boolean;
const
  wq: set of char = ['q', 'w'];
var
  t: set of char;
  i: integer;
begin
  t := [];
  Result := False;
  if Length(Value) <> 3 then
    Exit;

  for i := 1 to 3 do
    include(t, LowerCase(Value[i]));

  if t - wq = [] then
    Result := True;
end;

fast(!) written, match any 'wq' combination in a 3 length long string. at least 1 'w" AND 1 'q' MUST be present in value for the function to return True
« Last Edit: November 05, 2013, 11:41:20 pm by sam707 »

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Repeat Until combo is met
« Reply #6 on: November 06, 2013, 12:14:47 am »
Quote
The order doesn't matter, as long as there are two Q's and one W in the string
@sam707
Your checkwq() function does not meet this criterion, since it does not count individual characters, and so accepts strings such as 'wwq'.

@engkin
A neat observation. I think your function should be like this though:
Code: [Select]
function checkQW(const s: string): boolean;
begin
  if Length(s) <> 3 then Exit(False);
  Result:=Byte(s[1]) xor Byte(s[2]) xor Byte(s[3]) = $77;
end;
« Last Edit: November 06, 2013, 12:48:39 am by howardpc »

sam707

  • Guest
Re: Repeat Until combo is met
« Reply #7 on: November 06, 2013, 12:22:16 am »
@howardpc

yep, I saw that after I did quickly write the function, that is why I explained its purpose below it, thanks.

It is however easily possible to add a 'w' counter inside loop and return False if it counts 2
« Last Edit: November 06, 2013, 12:30:29 am by sam707 »

sam707

  • Guest
Re: Repeat Until combo is met
« Reply #8 on: November 06, 2013, 01:55:30 am »
@engkin

77 xor 77 = 0

0 xor 77 = 77

'www' returns True

73 xor 77 xor 77 = 73
77 xor 73 xor 77 = 73
77 xor 77 xor 73 = 73

so the value to compare with is not 77 but 73

indeed 73 xor 73 xor 73 is also equal to 73 'qqq' works, LOL

73 xor 254 xor 254 too
« Last Edit: November 06, 2013, 02:20:26 am by sam707 »

sam707

  • Guest
Re: Repeat Until combo is met
« Reply #9 on: November 06, 2013, 02:28:30 am »
this modified one, by mixing @engkin idea to mine should work properly :

Code: [Select]
function checkwq(Value: string): boolean;
const
  wq: set of char = ['q', 'w'];
var
  t: set of char;
  i: integer;
  c: Byte;
begin
  t := [];
  c:=0;
  Result := False;
  if Length(Value) <> 3 then
    Exit;

  for i := 1 to 3 do begin
    c:=c xor Byte(LowerCase(Value[i]));
    include(t, LowerCase(Value[i]));
  end;

  if (t = wq) and (c = 73) then
    Result := True;
end;

string contains at least 1 'w', at least 1 'q' due to the set usage, and xoring its chars returns 73, meaning it surely contains 2 'q', annihilating themselves

sets are fast, they don't use huge amount of mem like strings or TStringList.
« Last Edit: November 06, 2013, 03:17:27 am by sam707 »

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Repeat Until combo is met
« Reply #10 on: November 06, 2013, 03:36:04 am »
@howardpc,
Thank you. Here is another solution borrows a little from a code, I believe, you posted recently.

Code: [Select]
repeat
(...)
until (Check2q1w[ch[1],ch[2],ch[3]]<>0);

Of course Check2q1w is a magical array:

Code: [Select]
var
  Check2q1w: array['a'..'z','a'..'z','a'..'z'] of byte; // possibly global
..
// initialize it once
  ZeroMemory(@Check2q1w['a','a','a'], 26*26*26);     // might not be needed, if global
  Check2q1w['q','q','w'] := 1;
  Check2q1w['q','w','q'] := 1;
  Check2q1w['w','q','q'] := 1;


@sam707,
Thanks for the correction, :-[ and thanks for sharing your solution. Somehow I do learn when I see different code. If I may correct my solution:

Code: [Select]
var
  B: PByte;
..
repeat
(...)
  B := @ch[1];
until ((B[0] and B[1] and B[2])=$71) and ((B[0] xor B[1] xor B[2])=$77);

Would you agree with this solution?

sam707

  • Guest
Re: Repeat Until combo is met
« Reply #11 on: November 06, 2013, 04:17:23 am »

Code: [Select]
repeat
(...)
until (ch='qqw' or 'qwq' or 'wqq');

anyway, the initial code/problem is eroneous and not pascal compliant :

it should be
Code: [Select]
  until (ch='qqw') or (ch='qwq') or (ch='wqq');

The form @Harlequin wrote, might compile properly on a Marsian compiler, or something. I don't know. Certainly not on FPC.

Maybe, it was the only fix that he was looking for, lol

Regards
« Last Edit: November 06, 2013, 04:34:10 am by sam707 »

sam707

  • Guest
Re: Repeat Until combo is met
« Reply #12 on: November 06, 2013, 06:03:44 am »
Code: [Select]
var
  B: PByte;
..
repeat
(...)
  B := @ch[1];
until ((B[0] and B[1] and B[2])=$71) and ((B[0] xor B[1] xor B[2])=$77);

Would you agree with this solution?

I won't check that sir, I did never play any lottery (kidding). thanks a lot for your efforts tho. You are welcome.
« Last Edit: November 06, 2013, 06:10:02 am by sam707 »

Bart

  • Hero Member
  • *****
  • Posts: 5721
    • Bart en Mariska's Webstek
Re: Repeat Until combo is met
« Reply #13 on: November 06, 2013, 05:37:55 pm »
it should be
Code: [Select]
  until (ch='qqw') or (ch='qwq') or (ch='wqq');

I already pointed that out to him in my first reply  O:-)

Bart

sam707

  • Guest
Re: Repeat Until combo is met
« Reply #14 on: November 06, 2013, 05:52:56 pm »
sure you did, bro :)

hmm may I ... a comment on your code :

Code: [Select]
  Result := (Length(ch) = 3) and (q = 2) and (w = 1);

I used an 'IF then Result :=' that is more fast as $BOOLEVAL optimization is turned OFF by default because the compiled code is then supposed to give up the checks as soon as one of the conditional members is false

Code: [Select]
  if (t = wq) and (c = 73) then
    Result := True;

and in my code I could  use a temp variable here

Code: [Select]
    c:=c xor Byte(LowerCase(Value[i]));
    include(t, LowerCase(Value[i]));

to avoid the compiler to compute index twice. But I guess that if {$OPTIMIZATION CSE} is set, the compiler would do it internaly by reusing the "C"ommon "S"ub"E"xpression. (not sure lol, I'd have to debug it in asm and I've no time for it).

I decided to pick up and answer this post as an abstract exercice around sets to renew some old knowledge. sorry if my coding is obscure to beginners...
« Last Edit: November 06, 2013, 06:10:42 pm by sam707 »

 

TinyPortal © 2005-2018