This will give you all the dates that have a unique set of digits 1900 to 9999 - probably more efficient ways to do it but this runs sub second on my machine and spits out 44,640 values. Have not done any testing or checking but it'll give you at least an idea.
CREATE CURSOR w_dates (uniquedate D)
FOR lnYear = 1900 TO 9999
STORE 0 TO lnCheck STORE .F. TO llDuplicate
*- Check the year part for duplicate number usage STORE STR(m.lnYear, 4) TO lcYear FOR n = 1 TO 4
STORE VAL(SUBSTR(m.lcYear, n, 1)) TO lnVal
IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIF
ENDFOR
IF m.llDuplicate LOOP ENDIF
STORE m.lnCheck TO lnCheckYr
*------------------------------------------- *- Process Months *------------------------------------------- FOR lnMth = 1 TO 12
*- Check the mth + year part for duplicate number usage STORE .F. TO llDuplicate
STORE PADL(m.lnMth, 2, "0") TO lcMth FOR n = 1 TO 2
STORE VAL(SUBSTR(m.lcMth, n, 1)) TO lnVal
IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIF
ENDFOR
IF m.llDuplicate
STORE m.lnCheckYr TO lnCheck && Restore baseline to the year value LOOP
ENDIF
STORE m.lnCheck TO lnCheckYrMth
*------------------------------------------- *- Process Days *-------------------------------------------
*- How many days in the month ? lnDays = ICASE(; INLIST(m.lnMth, 1, 3, 5, 7, 8, 10, 12), 31, ; m.lnMth = 2, 28, ; 30)
*- Is this a leap Year ? IF m.lnMth = 2 AND MOD(m.lnYear, 4) = 0 AND IIF(MOD(m.lnYear, 100) = 0, IIF(MOD(m.lnYear, 400) = 0, .T., .F.), .T.) STORE 29 TO lnDays ENDIF
FOR lnDay = 1 to m.lnDays
*- Check the mth + year + day parts for duplicate number usage STORE .F. TO llDuplicate
STORE PADL(m.lnDay, 2, "0") TO lcDay FOR n = 1 TO 2
STORE VAL(SUBSTR(m.lcDay, n, 1)) TO lnVal
IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIF
ENDFOR
IF NOT m.llDuplicate
INSERT INTO w_dates (; uniquedate) ; VALUES (; DATE(m.lnYear, m.lnMth, m.lnDay))
ENDIF
STORE m.lnCheckYrMth TO lnCheck && Restore baseline to the year + month value - check next day in month.
ENDFOR
STORE m.lnCheckYr TO lnCheck && Check Next Mth in Year
ENDFOR
ENDFOR
-----Original Message----- From: ProfoxTech [mailto:profoxtech-bounces@leafe.com] On Behalf Of Gene Wirchenko Sent: Monday, 18 July 2016 2:29 AM To: profoxtech@leafe.com Subject: Checking for All-Different Characters
Hello:
I write a logic/math puzzle each week. They appear in my blog (http://genew.ca/) and two local newspapers.
Here is the latest problem:
"Consider a date in YYYY-MM-DD format. What is the next date where all eight digits will be different?"
I solved this by hand. I decided to verify my solution with a program. I often cook up something in GW-BASIC, but since VFP has date functions, I decided to go with it.
It was very easy to set up the framework of the loop. What threw me for a loop is how to check that all of the digits are different. I ended up converting the date to string with dtos() and then testing the string with a rather ugly-looking condition. Is there something faster?
***** Start of Code ***** * 16s-16.prg * Date Puzzle * Last Modification: 2016-07-17 * * Consider a date in YYYY-MM-DD format. What is the next date where all * eight digits will be different?
? "*** Execution begins." ? program() close all clear all
set talk off set exact on set century on set date ansi
*
local startdate startdate=date()
? "Start Date: "+transform(startdate)
local trydate, looping trydate=startdate looping=.t. do while looping
local trydtos trydtos=dtos(trydate) if right(trydtos,4)="0101" ? "Working on year "+left(trydtos,4) endif
if; iif("0"$trydtos,1,0)+; iif("1"$trydtos,1,0)+; iif("2"$trydtos,1,0)+; iif("3"$trydtos,1,0)+; iif("4"$trydtos,1,0)+; iif("5"$trydtos,1,0)+; iif("6"$trydtos,1,0)+; iif("7"$trydtos,1,0)+; iif("8"$trydtos,1,0)+; iif("9"$trydtos,1,0)#8 trydate=trydate+1 else && solution looping=.f. endif
enddo
? "Solution is "+transform(trydate)+"."
*
close all clear all ? "*** Execution ends." return ***** End of Code *****
Sincerely,
Gene Wirchenko
[excessive quoting removed by server]
Here is a simple brute force approach with the same count
m.cnt = 0 m.Cdate = {^1900-01-01} DO WHILE m.Cdate < {^9999-12-31} m.str = dtos(m.cdate) FOR m.x = 1 TO 8 IF OCCURS(SUBSTR(m.str, m.x, 1), m.str) > 1 EXIT ENDIF ENDFOR IF m.x = 9 m.cnt = m.cnt + 1 * WAIT window m.Cdate ENDIF m.cdate = m.cdate + 1 ENDDO ?m.cnt
It takes a little over 6 seconds on my machine so it's not faster - just simpler.
Joe
On Sun, Jul 17, 2016 at 9:06 PM, Darren foxdev@ozemail.com.au wrote:
This will give you all the dates that have a unique set of digits 1900 to 9999 - probably more efficient ways to do it but this runs sub second on my machine and spits out 44,640 values. Have not done any testing or checking but it'll give you at least an idea.
CREATE CURSOR w_dates (uniquedate D)
FOR lnYear = 1900 TO 9999
STORE 0 TO lnCheck STORE .F. TO llDuplicate
*- Check the year part for duplicate number usage STORE STR(m.lnYear, 4) TO lcYear FOR n = 1 TO 4
STORE VAL(SUBSTR(m.lcYear, n, 1)) TO lnVal IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIFENDFOR
IF m.llDuplicate LOOP ENDIF
STORE m.lnCheck TO lnCheckYr
*------------------------------------------- *- Process Months *------------------------------------------- FOR lnMth = 1 TO 12
*- Check the mth + year part for duplicate number usage STORE .F. TO llDuplicate STORE PADL(m.lnMth, 2, "0") TO lcMth FOR n = 1 TO 2 STORE VAL(SUBSTR(m.lcMth, n, 1)) TO lnVal IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIF ENDFOR IF m.llDuplicate STORE m.lnCheckYr TO lnCheck && Restore baseline to the year value LOOP ENDIF STORE m.lnCheck TO lnCheckYrMth *------------------------------------------- *- Process Days *------------------------------------------- *- How many days in the month ? lnDays = ICASE(; INLIST(m.lnMth, 1, 3, 5, 7, 8, 10, 12), 31, ; m.lnMth = 2, 28, ; 30) *- Is this a leap Year ? IF m.lnMth = 2 AND MOD(m.lnYear, 4) = 0 AND IIF(MOD(m.lnYear, 100) = 0,IIF(MOD(m.lnYear, 400) = 0, .T., .F.), .T.) STORE 29 TO lnDays ENDIF
FOR lnDay = 1 to m.lnDays *- Check the mth + year + day parts for duplicate number usage STORE .F. TO llDuplicate STORE PADL(m.lnDay, 2, "0") TO lcDay FOR n = 1 TO 2 STORE VAL(SUBSTR(m.lcDay, n, 1)) TO lnVal IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIF ENDFOR IF NOT m.llDuplicate INSERT INTO w_dates (; uniquedate) ; VALUES (; DATE(m.lnYear, m.lnMth, m.lnDay)) ENDIF STORE m.lnCheckYrMth TO lnCheck && Restore baseline to the year +month value - check next day in month.
ENDFOR STORE m.lnCheckYr TO lnCheck && Check Next Mth in YearENDFOR
ENDFOR
-----Original Message----- From: ProfoxTech [mailto:profoxtech-bounces@leafe.com] On Behalf Of Gene Wirchenko Sent: Monday, 18 July 2016 2:29 AM To: profoxtech@leafe.com Subject: Checking for All-Different Characters
Hello:
I write a logic/math puzzle each week. They appear in my blog(http://genew.ca/) and two local newspapers.
Here is the latest problem: "Consider a date in YYYY-MM-DD format. What is the next date whereall eight digits will be different?"
I solved this by hand. I decided to verify my solution with aprogram. I often cook up something in GW-BASIC, but since VFP has date functions, I decided to go with it.
It was very easy to set up the framework of the loop. What threw mefor a loop is how to check that all of the digits are different. I ended up converting the date to string with dtos() and then testing the string with a rather ugly-looking condition. Is there something faster?
***** Start of Code *****
16s-16.prg
Date Puzzle
Last Modification: 2016-07-17
Consider a date in YYYY-MM-DD format. What is the next date where all
eight digits will be different?
? "*** Execution begins." ? program() close all clear all
set talk off set exact on set century on set date ansi
local startdate startdate=date()
? "Start Date: "+transform(startdate)
local trydate, looping trydate=startdate looping=.t. do while looping
local trydtos trydtos=dtos(trydate) if right(trydtos,4)="0101" ? "Working on year "+left(trydtos,4) endif if; iif("0"$trydtos,1,0)+; iif("1"$trydtos,1,0)+; iif("2"$trydtos,1,0)+; iif("3"$trydtos,1,0)+; iif("4"$trydtos,1,0)+; iif("5"$trydtos,1,0)+; iif("6"$trydtos,1,0)+; iif("7"$trydtos,1,0)+; iif("8"$trydtos,1,0)+; iif("9"$trydtos,1,0)#8 trydate=trydate+1 else && solution looping=.f. endif enddo? "Solution is "+transform(trydate)+"."
close all clear all ? "*** Execution ends." return
***** End of Code *****
Sincerely,
Gene Wirchenko
[excessive quoting removed by server]
How about 3456-01-23
The month can only be 01-12 and the day can only be 01-31 so I would start there since the year can be almost anything.
On 7/17/2016 11:11 PM, Joe Yoder wrote:
Here is a simple brute force approach with the same count
m.cnt = 0 m.Cdate = {^1900-01-01} DO WHILE m.Cdate < {^9999-12-31} m.str = dtos(m.cdate) FOR m.x = 1 TO 8 IF OCCURS(SUBSTR(m.str, m.x, 1), m.str) > 1 EXIT ENDIF ENDFOR IF m.x = 9 m.cnt = m.cnt + 1 * WAIT window m.Cdate ENDIF m.cdate = m.cdate + 1 ENDDO ?m.cnt
It takes a little over 6 seconds on my machine so it's not faster - just simpler.
Joe
On Sun, Jul 17, 2016 at 9:06 PM, Darren foxdev@ozemail.com.au wrote:
This will give you all the dates that have a unique set of digits 1900 to 9999 - probably more efficient ways to do it but this runs sub second on my machine and spits out 44,640 values. Have not done any testing or checking but it'll give you at least an idea.
CREATE CURSOR w_dates (uniquedate D)
FOR lnYear = 1900 TO 9999
STORE 0 TO lnCheck STORE .F. TO llDuplicate
*- Check the year part for duplicate number usage STORE STR(m.lnYear, 4) TO lcYear FOR n = 1 TO 4
STORE VAL(SUBSTR(m.lcYear, n, 1)) TO lnVal IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIFENDFOR
IF m.llDuplicate LOOP ENDIF
STORE m.lnCheck TO lnCheckYr
*------------------------------------------- *- Process Months *------------------------------------------- FOR lnMth = 1 TO 12
*- Check the mth + year part for duplicate number usage STORE .F. TO llDuplicate STORE PADL(m.lnMth, 2, "0") TO lcMth FOR n = 1 TO 2 STORE VAL(SUBSTR(m.lcMth, n, 1)) TO lnVal IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIF ENDFOR IF m.llDuplicate STORE m.lnCheckYr TO lnCheck && Restore baseline to the year value LOOP ENDIF STORE m.lnCheck TO lnCheckYrMth *------------------------------------------- *- Process Days *------------------------------------------- *- How many days in the month ? lnDays = ICASE(; INLIST(m.lnMth, 1, 3, 5, 7, 8, 10, 12), 31, ; m.lnMth = 2, 28, ; 30) *- Is this a leap Year ? IF m.lnMth = 2 AND MOD(m.lnYear, 4) = 0 AND IIF(MOD(m.lnYear, 100) = 0,IIF(MOD(m.lnYear, 400) = 0, .T., .F.), .T.) STORE 29 TO lnDays ENDIF
FOR lnDay = 1 to m.lnDays *- Check the mth + year + day parts for duplicate number usage STORE .F. TO llDuplicate STORE PADL(m.lnDay, 2, "0") TO lcDay FOR n = 1 TO 2 STORE VAL(SUBSTR(m.lcDay, n, 1)) TO lnVal IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIF ENDFOR IF NOT m.llDuplicate INSERT INTO w_dates (; uniquedate) ; VALUES (; DATE(m.lnYear, m.lnMth, m.lnDay)) ENDIF STORE m.lnCheckYrMth TO lnCheck && Restore baseline to the year +month value - check next day in month.
ENDFOR STORE m.lnCheckYr TO lnCheck && Check Next Mth in YearENDFOR
ENDFOR
-----Original Message----- From: ProfoxTech [mailto:profoxtech-bounces@leafe.com] On Behalf Of Gene Wirchenko Sent: Monday, 18 July 2016 2:29 AM To: profoxtech@leafe.com Subject: Checking for All-Different Characters
Hello:
I write a logic/math puzzle each week. They appear in my blog(http://genew.ca/) and two local newspapers.
Here is the latest problem: "Consider a date in YYYY-MM-DD format. What is the next date whereall eight digits will be different?"
I solved this by hand. I decided to verify my solution with aprogram. I often cook up something in GW-BASIC, but since VFP has date functions, I decided to go with it.
It was very easy to set up the framework of the loop. What threw mefor a loop is how to check that all of the digits are different. I ended up converting the date to string with dtos() and then testing the string with a rather ugly-looking condition. Is there something faster?
***** Start of Code *****
16s-16.prg
Date Puzzle
Last Modification: 2016-07-17
Consider a date in YYYY-MM-DD format. What is the next date where all
eight digits will be different?
? "*** Execution begins." ? program() close all clear all
set talk off set exact on set century on set date ansi
local startdate startdate=date()
? "Start Date: "+transform(startdate)
local trydate, looping trydate=startdate looping=.t. do while looping
local trydtos trydtos=dtos(trydate) if right(trydtos,4)="0101" ? "Working on year "+left(trydtos,4) endif if; iif("0"$trydtos,1,0)+; iif("1"$trydtos,1,0)+; iif("2"$trydtos,1,0)+; iif("3"$trydtos,1,0)+; iif("4"$trydtos,1,0)+; iif("5"$trydtos,1,0)+; iif("6"$trydtos,1,0)+; iif("7"$trydtos,1,0)+; iif("8"$trydtos,1,0)+; iif("9"$trydtos,1,0)#8 trydate=trydate+1 else && solution looping=.f. endif enddo? "Solution is "+transform(trydate)+"."
close all clear all ? "*** Execution ends." return
***** End of Code *****
Sincerely,
Gene Wirchenko
[excessive quoting removed by server]
Hey, spoiler alert!
Guess you'll need to subscribe to Gene's newspapers to find the solution.
By inspection, I can come up with at least one date closer than that.
So, let's think about the *algorithm* to solve the problem in minimal time, rather than the answer.
On Mon, Jul 18, 2016 at 12:20 PM, Ken McGinnis kamcginnis@gmail.com wrote:
How about 3456-01-23
The month can only be 01-12 and the day can only be 01-31 so I would start there since the year can be almost anything.
On 7/17/2016 11:11 PM, Joe Yoder wrote:
Here is a simple brute force approach with the same count
m.cnt = 0 m.Cdate = {^1900-01-01} DO WHILE m.Cdate < {^9999-12-31} m.str = dtos(m.cdate) FOR m.x = 1 TO 8 IF OCCURS(SUBSTR(m.str, m.x, 1), m.str) > 1 EXIT ENDIF ENDFOR IF m.x = 9 m.cnt = m.cnt + 1 * WAIT window m.Cdate ENDIF m.cdate = m.cdate + 1 ENDDO ?m.cnt
It takes a little over 6 seconds on my machine so it's not faster - just simpler.
Joe
On Sun, Jul 17, 2016 at 9:06 PM, Darren foxdev@ozemail.com.au wrote:
This will give you all the dates that have a unique set of digits 1900 to 9999 - probably more efficient ways to do it but this runs sub second on my machine and spits out 44,640 values. Have not done any testing or checking but it'll give you at least an idea.
CREATE CURSOR w_dates (uniquedate D)
FOR lnYear = 1900 TO 9999
STORE 0 TO lnCheck STORE .F. TO llDuplicate
*- Check the year part for duplicate number usage STORE STR(m.lnYear, 4) TO lcYear FOR n = 1 TO 4
STORE VAL(SUBSTR(m.lcYear, n, 1)) TO lnVal IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIFENDFOR
IF m.llDuplicate LOOP ENDIF
STORE m.lnCheck TO lnCheckYr
*------------------------------------------- *- Process Months *------------------------------------------- FOR lnMth = 1 TO 12
*- Check the mth + year part for duplicate number usage STORE .F. TO llDuplicate STORE PADL(m.lnMth, 2, "0") TO lcMth FOR n = 1 TO 2 STORE VAL(SUBSTR(m.lcMth, n, 1)) TO lnVal IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIF ENDFOR IF m.llDuplicate STORE m.lnCheckYr TO lnCheck && Restore baseline to the yearvalue LOOP
ENDIF STORE m.lnCheck TO lnCheckYrMth *------------------------------------------- *- Process Days *------------------------------------------- *- How many days in the month ? lnDays = ICASE(; INLIST(m.lnMth, 1, 3, 5, 7, 8, 10, 12), 31, ; m.lnMth = 2, 28, ; 30) *- Is this a leap Year ? IF m.lnMth = 2 AND MOD(m.lnYear, 4) = 0 AND IIF(MOD(m.lnYear, 100) =0, IIF(MOD(m.lnYear, 400) = 0, .T., .F.), .T.) STORE 29 TO lnDays ENDIF
FOR lnDay = 1 to m.lnDays *- Check the mth + year + day parts for duplicate number usage STORE .F. TO llDuplicate STORE PADL(m.lnDay, 2, "0") TO lcDay FOR n = 1 TO 2 STORE VAL(SUBSTR(m.lcDay, n, 1)) TO lnVal IF BITTEST(m.lnCheck, m.lnVal) STORE .T. TO llDuplicate EXIT ELSE lnCheck = BITSET(m.lnCheck, m.lnVal) ENDIF ENDFOR IF NOT m.llDuplicate INSERT INTO w_dates (; uniquedate) ; VALUES (; DATE(m.lnYear, m.lnMth, m.lnDay)) ENDIF STORE m.lnCheckYrMth TO lnCheck && Restore baseline to the year +month value - check next day in month.
ENDFOR STORE m.lnCheckYr TO lnCheck && Check Next Mth in YearENDFOR
ENDFOR
-----Original Message----- From: ProfoxTech [mailto:profoxtech-bounces@leafe.com] On Behalf Of Gene Wirchenko Sent: Monday, 18 July 2016 2:29 AM To: profoxtech@leafe.com Subject: Checking for All-Different Characters
Hello:
I write a logic/math puzzle each week. They appear in my blog(http://genew.ca/) and two local newspapers.
Here is the latest problem: "Consider a date in YYYY-MM-DD format. What is the next datewhere all eight digits will be different?"
I solved this by hand. I decided to verify my solution with aprogram. I often cook up something in GW-BASIC, but since VFP has date functions, I decided to go with it.
It was very easy to set up the framework of the loop. What threwme for a loop is how to check that all of the digits are different. I ended up converting the date to string with dtos() and then testing the string with a rather ugly-looking condition. Is there something faster?
***** Start of Code *****
16s-16.prg
Date Puzzle
Last Modification: 2016-07-17
Consider a date in YYYY-MM-DD format. What is the next date where all
eight digits will be different?
? "*** Execution begins." ? program() close all clear all
set talk off set exact on set century on set date ansi
local startdate startdate=date()
? "Start Date: "+transform(startdate)
local trydate, looping trydate=startdate looping=.t. do while looping
local trydtos trydtos=dtos(trydate) if right(trydtos,4)="0101" ? "Working on year "+left(trydtos,4) endif if; iif("0"$trydtos,1,0)+; iif("1"$trydtos,1,0)+; iif("2"$trydtos,1,0)+; iif("3"$trydtos,1,0)+; iif("4"$trydtos,1,0)+; iif("5"$trydtos,1,0)+; iif("6"$trydtos,1,0)+; iif("7"$trydtos,1,0)+; iif("8"$trydtos,1,0)+; iif("9"$trydtos,1,0)#8 trydate=trydate+1 else && solution looping=.f. endif enddo? "Solution is "+transform(trydate)+"."
close all clear all ? "*** Execution ends." return
***** End of Code *****
Sincerely,
Gene Wirchenko
[excessive quoting removed by server]
Ted Roche wrote on 2016-07-18:
Hey, spoiler alert!
Guess you'll need to subscribe to Gene's newspapers to find the solution.
By inspection, I can come up with at least one date closer than that.
So, let's think about the *algorithm* to solve the problem in minimal time, rather than the answer.
There are many ways to code searching for this. Here is my solution:
LOCAL ldDate, lnStart, lnStop lnStart = SECONDS() ldDate = DATE() llFound = .F. DO WHILE NOT llFound ldDate = ldDate + 1 llFound = NOT HasDuplicates(ldDate) ENDDO lnStop = SECONDS() ?ldDate ?lnStop - lnStart
FUNCTION HasDuplicates LPARAMETERS tdTestDate LOCAL lcTestDate, llDuplicate lcTestDate = DTOS(tdTestDate) llDuplicate = .F. FOR ii = 0 TO 9 IF LEN(CHRTRAN(lcTestDate, TRANSFORM(ii), ""))<7 llDuplicate = .T. EXIT ENDIF NEXT RETURN llDuplicate ENDFUNC
Tracy Pearson PowerChurch Software
At 09:20 2016-07-18, Ken McGinnis kamcginnis@gmail.com wrote:
How about 3456-01-23
The month can only be 01-12 and the day can only be 01-31 so I would start there since the year can be almost anything.
Your solution is incorrect. Note the duplicate 3's.
Well, no, the year cannot be almost anything since the solution is the NEXT date with no duplicate digits. Start with the year.
[snip]
Sincerely,
Gene Wirchenko