Super Bowl Sunday, when the Chiefs came back from a 10 point deficit in the 4th quarter to defeat the 49ers 31-20, was also a palindrome day. Since we Westerners write the date in the format mm/dd/yyyy, we could have turned that around and had the same day as 02022020 is the same forward and backwards.
The Riddler Express asked how many more of these types of dates there will be this century. The Riddler was published on 02/07/2020. So, I first stored this as a date. R defaults to the format yyyy-mm-dd for dates. We’ll deal with that later.
RidDate <- as.Date("2020-02-07")
Next, I built a function that would take a date as an input, and return TRUE if the date is palindrome and FALSE if the date was not a palindrome. I called the function is.palindrome().
## The input x is a date
is.palindrome <- function(x){
P <- strsplit(format(x, "%m%d%Y"), split = "")[[1]]
## with x as, say, 2043-05-19, P will now be a vector of characters that
## will look like "0", "5", "1", "9", "2", "0", "4", "3"
Pf <- P[1:4] ## Pf is the vector of characters "0", "5", "1", "9"
Pl <- P[8:5] ## Pl is the reversed vector of characters "3", "4", "0", "2".
if(all.equal(Pf,Pl)!=TRUE){
return(FALSE)
}
else{return(TRUE)}
}
## Test to see if it works
print("This one should return TRUE")
## [1] "This one should return TRUE"
is.palindrome(as.Date("2020-02-02"))
## [1] TRUE
print("This one should return FALSE")
## [1] "This one should return FALSE"
is.palindrome(RidDate)
## [1] FALSE
Now, we’ll use a while loop cycling through all of the dates until we get to 01/01/2100, the start of the new century. (Or would that be 01/01/2101 to be precise?)
PalindromeDates <- c()
loopDate <- RidDate + 1
while(loopDate < as.Date("2100-01-01")){
PalindromeDates <- c(PalindromeDates, is.palindrome(loopDate))
loopDate <- loopDate + 1
}
To find out the answer to our question, we simply find out how many TRUE’s are within my PalindromeDates vector.
sum(PalindromeDates)
## [1] 8
Well that wasn’t very satisfying. What are the actual dates in the format that we write them in?
format(RidDate + which(PalindromeDates), "%m/%d/%Y")
## [1] "12/02/2021" "03/02/2030" "04/02/2040" "05/02/2050" "06/02/2060"
## [6] "07/02/2070" "08/02/2080" "09/02/2090"
This is still not that satisyfing. If you’re not a computer, you probably don’t write a zero before the month. For fun, let’s check dates if we scratch the first 0. I’ll write a second function that does that.
is.palindrome2 <- function(x){ ## this will take a date
P <- strsplit(format(x, "%m%d%Y"), split = "")[[1]]
if(P[1]=="0"){
P <- P[-1]
Pf <- P[1:3]
Pl <- P[7:5]
}
else{return(FALSE)}
if(all.equal(Pf,Pl)!=TRUE){
return(FALSE)
}
else{return(TRUE)}
}
Using a similar loop as above, let’s find the number of palindromes without a 0 to lead the month.
PalindromeDatesNo0 <- c()
loopDate <- RidDate + 1
while(loopDate < as.Date("2100-01-01")){
PalindromeDatesNo0 <- c(PalindromeDatesNo0, is.palindrome2(loopDate))
loopDate <- loopDate + 1
}
How many of these are there? And what dates are these?
sum(PalindromeDatesNo0)
## [1] 17
sapply(format(RidDate + which(PalindromeDatesNo0), "%m/%d/%Y"), function(x) substr(x, 2, 10))
## 01/20/2021 02/20/2022 03/20/2023 04/20/2024 05/20/2025 06/20/2026
## "1/20/2021" "2/20/2022" "3/20/2023" "4/20/2024" "5/20/2025" "6/20/2026"
## 07/20/2027 08/20/2028 09/20/2029 01/30/2031 03/30/2033 04/30/2034
## "7/20/2027" "8/20/2028" "9/20/2029" "1/30/2031" "3/30/2033" "4/30/2034"
## 05/30/2035 06/30/2036 07/30/2037 08/30/2038 09/30/2039
## "5/30/2035" "6/30/2036" "7/30/2037" "8/30/2038" "9/30/2039"
This is much more satisfying.
What if we wrote our dates like the rest of the world did, in the format dd/mm/yyyy? Interestingly enough, Super Bowl Sunday would still have been a palindrome! Let’s find out how many more we get to add to the list.
is.palindrome3 <- function(x){
P <- strsplit(format(x, "%d%m%Y"), split = "")[[1]]
## with x as, say, 2043-05-19, P will now be a vector of characters that
## will look like "1", "9", "0", "5", "2", "0", "4", "3"
Pf <- P[1:4] ## Pf is the vector of characters "1", "9", "0", "5"
Pl <- P[8:5] ## Pl is the reversed vector of characters "3", "4", "0", "2".
if(all.equal(Pf,Pl)!=TRUE){
return(FALSE)
}
else{return(TRUE)}
}
PalindromeDatesWorld <- c()
loopDate <- RidDate + 1
while(loopDate < as.Date("2100-01-01")){
PalindromeDatesWorld <- c(PalindromeDatesWorld, is.palindrome3(loopDate))
loopDate <- loopDate + 1
}
print("The Total Number of Dates is ")
## [1] "The Total Number of Dates is "
sum(PalindromeDatesWorld)
## [1] 23
print("and those dates in the form dd/mm/yyyy are ")
## [1] "and those dates in the form dd/mm/yyyy are "
format(RidDate + which(PalindromeDatesWorld), "%d/%m/%Y")
## [1] "12/02/2021" "22/02/2022" "03/02/2030" "13/02/2031" "23/02/2032"
## [6] "04/02/2040" "14/02/2041" "24/02/2042" "05/02/2050" "15/02/2051"
## [11] "25/02/2052" "06/02/2060" "16/02/2061" "26/02/2062" "07/02/2070"
## [16] "17/02/2071" "27/02/2072" "08/02/2080" "18/02/2081" "28/02/2082"
## [21] "09/02/2090" "19/02/2091" "29/02/2092"
If we explore the ambiguous \(|-1|-2|-3|\) first. Let abs(x) represent |x|. Then \(|-1|-2|-3|\) can be interpreted as abs(-1)-2abs(-3), which is -5. OR, it can be interpreted as abs(-1abs(-2)-3), which is 5. Let’s build a function when there is just a vector of 3 values. This will take an input vector v = (-1,-2,-3) and a multiplier m (which will be used in recursive steps) with default value 1.
AbsValue3 <- function(v,m=1){
if(length(v)!=3){return("Error")}
else{
return(c(m*abs(v[1])+v[2]*abs(v[3]), m*abs(v[1]*abs(v[2])+v[3])))
}
}
## Does it work?
AbsValue3(-(1:3))
## [1] -5 5
Let’s extend this and find all of values of |-1|-2|-3|-4|-5|.
AbsValue5 <- function(v,m=1){
if(length(v)!=5){return("Error")}
else{
a1 <- m*abs(v[1])+v[2]*abs(v[3])+v[4]*abs(v[5])
a2 <- m*abs(v[1]*abs(v[2])+v[3])+v[4]*abs(v[5])
a3 <- m*abs(v[1])+v[2]*abs(v[3]*abs(v[4])+v[5])
a4 <- m*abs(AbsValue3(v[2:4],v[1])+v[5])
return(c(a1,a2,a3,a4))
}
}
## Check our work
AbsValue5(-(1:5))
## [1] -25 -15 -33 19 15
Again, let’s extend to |-1|-2|-3|-4|-5|-6|-7|.
AbsValue7 <- function(v,m=1){
if(length(v)!=7){return("Error")}
else{
A <- AbsValue5(v[1:5])+v[6]*abs(v[7])
a1 <- m*abs(v[1])+v[2]*abs(v[3])+v[4]*abs(v[5]*abs(v[6])+v[7])
a2 <- m*abs(v[1]*abs(v[2])+v[3])+v[4]*abs(v[5]*abs(v[6])+v[7])
a3 <- m*abs(v[1])+v[2]*abs(AbsValue3(v[4:6],v[3])+v[7])
a4 <- m*abs(AbsValue5(v[2:6],v[1])+v[7])
}
return(sort(c(A,a1,a2,a3,a4)))
}
## Check our work
AbsValue7(-(1:7))
## [1] -169 -153 -143 -97 -75 -67 -57 -27 -23 39 47 47 51 87
One more time, and we will get our answer. We extend to |-1|-2|-3|-4|-5|-6|-7|-8|-9|.
AbsValue9 <- function(v,m=1){
if(length(v)!=9){return("Error")}
else{
A <- AbsValue7(v[1:7])+v[8]*abs(v[9])
a1 <- m*abs(v[1])+v[2]*abs(v[3])+v[4]*abs(v[5])+v[6]*abs(v[7]*abs(v[8])+v[9])
a2 <- m*abs(v[1]*abs(v[2])+v[3])+v[4]*abs(v[5])+v[6]*abs(v[7]*abs(v[8])+v[9])
a3 <- m*abs(v[1])+v[2]*abs(v[3]*abs(v[4])+v[5])+v[6]*abs(v[7]*abs(v[8])+v[9])
a4 <- m*abs(v[1])+v[2]*abs(v[3])+v[4]*abs(AbsValue3(v[6:8],v[5])+v[9])
a5 <- m*abs(AbsValue3(v[2:4],v[1])+v[5])+v[6]*abs(v[7]*abs(v[8])+v[9])
a6 <- m*abs(v[1]*abs(v[2])+v[3])+v[4]*abs(AbsValue3(v[6:8],v[5])+v[9])
a7 <- m*abs(v[1])+v[2]*abs(AbsValue5(v[4:8],v[3])+v[9])
a8 <- m*abs(AbsValue7(v[2:8],v[1])+v[9])
}
return(sort(unique(c(A,a1,a2,a3,a4,a5,a6,a7,a8))))
}
## What are the values and how many are there?
RiddleVals <- AbsValue9(-(1:9))
length(RiddleVals)
## [1] 39
RiddleVals
## [1] -1041 -1031 -953 -541 -437 -423 -415 -405 -385 -375 -371
## [12] -285 -241 -225 -215 -213 -169 -147 -139 -129 -99 -95
## [23] -33 -25 -21 15 25 33 85 93 105 115 141
## [34] 171 187 221 269 273 479