Fully-palindromic triangles Consider the string 160615051. It can be "triangulated" as such:

  1
 606
15051


Then, each row is a palindrome. Also note that each side on the perimeter is also a palindrome:

  1  |   1   |   
 6   |    6  |      
1    |     1 | 15051 


Therefore, this string can be considered to be a fully-palindromic triangle. Don't worry about the altitude 100 in this case, it doesn't have to be palindromic.

Input: A string of printable ASCII characters from 0x20 to 0x7E. This can be a character array, a single string, or an array of ASCII code points. Your input will always be able to be triangulated (that is, its length will always be a perfect square).

Output: A truthy value if the string is a fully-palindromic triangle, or a falsey value otherwise.

Test cases

input =&gt; output

1 =&gt; true
A =&gt; true
AAAA =&gt; true
nope =&gt; false
{{}} =&gt; false
1101 =&gt; true
1011 =&gt; false
1202 =&gt; false
111110001 =&gt; true
160615051 =&gt; true
160625052 =&gt; false
1111111111111111 =&gt; true
1121123211234321123454321 =&gt; true
HHeHHeleHHellleHHellolleH =&gt; true
HellolleHHellleHHeleHHeHH =&gt; false
111111111111111111111111111111111111 =&gt; true
abcbdefeddefgfedbcdefedcbabcdefedcba =&gt; true
Jelly, 14 12 bytes

J’Æ²œṗZ⁻¦µU⁼


Try it online!

Background

We start by looking at the 0-based indices of the input string.

 H  H  e  H  H  e  l  e  H  H  e  l  l  l  e  H  H  e  l  l  o  l  l  e  H
 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24


To get the rows of the triangle, we can split the string before the indices 1, 1 + 3 = 4, 1 + 3 + 5 = 9, and 1 + 3 + 5 + 7 = 16. Since (n + 1)² = n² + (2n + 1), these sums are precisely the positive, perfect squares in the index list. If we also split the string before 0, this is as simple as splitting before all 0-based indices that are perfect squares.

After splitting, we get the following strings.

""
"H"
"HeH"
"HeleH"
"HellleH"
"HellolleH"


Next, we replace the empty string at the beginning with all the characters in the first column.

"HHHHH"
"H"
"HeH"
"HeleH"
"HellleH"
"HellolleH"


The task is now reduced to checking whether reversing all strings yields the same string array.

How it works

First J generates all 1-based indices of the input string J, then decrements them with ’ to yield all 0-based indices. Æ² tests all 0-based indices for squareness. For our example from above, this yields the following Boolean array.

 1  1  0  0  1  0  0  0  0  1  0  0  0  0  0  0  1  0  0  0  0  0  0  0  0


Next, we call œṗ to partition the input string, e.g., 

 H  H  e  H  H  e  l  e  H  H  e  l  l  l  e  H  H  e  l  l  o  l  l  e  H


before all 1's (actually, all truthy elements). For our example, this yields the following string array.

['', 
 'H',
 'HeH',
 'HeleH',
 'HellleH',
 'HellolleH'
]


Z⁻¦ is arguably the most interesting part of this answer. Let's analyze the more straightforward Z1¦ first.

¦ is the sparse quick. It consumes two links from the stack, specifically 1 and Z in this case. First Z is applied to its argument: the string array from before. Z is the zip atom and reads the string array / 2D character array by columns, yielding

['HHHHH',
 'eeee',
 'Hlll',
 'ell',
 'Hlo',
 'el',
 'Hl',
 'e',
 'H'
]


What used to be left side of the input string and the first column of the string array now becomes the first string.

Now ¦ peeks at 1 and finds a single index: 1. Thus the first string in the original string array is replaced with the first string in the return value of Z; strings at other indices remain unaffected.

['HHHHH',
 'H',
 'HeH',
 'HeleH',
 'HellleH',
 'HellolleH'
]


Let's call this array A.

We used Z⁻¦ instead of Z1¦, but this makes no difference: ⁻ compares the string array with the input string for inequality, yielding 1 since they're not equal. The difference between the two is that Z⁻¦ is dyadic because ⁻ is, allowing us to write œṗZ⁻¦ instead of œṗ¹Z1¦. This is because a dyad (œṗ) followed by a monad (œṗ¹Z1¦) is a fork (the monad is applied to the chain's argument / the input string, and the returned value is passed as the right argument to œṗ), while a dyad followed by another dyad (or at the end of the chain) is a hook, i.e., its right argument is the chain's argument.

All that's left to do is check for palindromicness. µ begins a new (monadic) chain who's argument is A. The upend atom U reverses all strings in A (but not A itself), then ⁼ compares the result with A for equality. The returned Boolean 1 indicates a fully-palindromic triangle; other strings would return 0.