| Bytes | Lang | Time | Link |
|---|---|---|---|
| 053 | Charcoal | 250606T085606Z | Neil |
| 757 | C++ gcc | 250604T190626Z | David G. |
| 070 | JavaScript Node.js | 250604T060541Z | l4m2 |
| 066 | Brachylog | 250603T230939Z | DLosc |
| 316 | Python3 | 250603T164429Z | Ajax1234 |
| 074 | JavaScript ES6 | 250603T150427Z | Arnauld |
| 017 | Pyth | 250603T142828Z | CursorCo |
Charcoal, 53 bytes
FLθ⊞υEθ∧⁻ιλκFυ«≔⌕ι⁰η§≔ιη±¹FΦLθ⁼§ικ↔⁻ηκ⊞υEι∧⁻κμλ»›⁰⌈⊟υ
Try it online! Link is to verbose version of code. Explanation: Lots of brute force, working backwards from the end. (I tried to write a faster version, but I wasn't getting anywhere even with the 100 size test case.)
FLθ⊞υEθ∧⁻ιλκFυ«
Start a breadth-first search using each possible index as the end of the traversal.
≔⌕ι⁰η
Get the earliest hop of this traversal.
§≔ιη±¹
Mark it as visited.
FΦLθ⁼§ικ↔⁻ηκ
Find all unvisited indices that can hop here. (Because visited indices have been replaced with -1 they will never match a successful hop.)
⊞υEι∧⁻κμλ
Add another traversal with this as the new earliest hop.
»›⁰⌈⊟υ
Check that the last traversal visited all of the indices.
C++ (gcc), 757 bytes
#define R (i+v)
#define L (i-v)
#define V int v=I[i];
#define D B[i]
struct A{int C;int E;int G;int F;int H;};A B[10000];int M(int I[],int N,int i,int Q){if(Q==0)return 1;V
#define TRY(x)if(!B[x].H){B[x].H=1;if(M(I,N,(x),Q-1))return 1;B[x].H=0;}
if(D.C)TRY(L);if(D.E)TRY(R);return 0;}int T(int I[],int N){int K=0,J=0,i;for(i=0;i<N;i++){V
D.C=L>=0;D.E=R<N;D.G=0;D.F=0;D.H=0;if(D.C){K++;}else{if(D.E){K++;}else{D.F=1;J++;}}}if(J>1)return 0;int P=1;while(P&&(K>0)){P=0;for(i=0;i<N;i++){V
if(D.F)continue;int O=0;if(D.C&&B[L].G){D.C=0;O=1;}if(D.E&&B[R].G){D.E=0;O=1;}if(O)P=1;if(D.C){if(!D.E){if(J){B[L].G=1;D.F=1;P=1;}}}else{if(D.E){if(J){B[R].G=1;D.F=1;P=1;}}else{D.F=1;J++;}}}if(J>1)return 0;}for(i=0;i<N;i++){D.H=1;if(M(I,N,i,N-1))return 1;D.H=0;}return 0;}
This does all the test data, including the two 10Ks, plus a few of my own, in under 6 seconds on TIO.
Fitting it in a SE answer took work, since I include the 10Ks in the TIO. (I never knew there was a 64k limit.)
I started with a brute-force program, but my C++ version is now almost 37 hours into the first 10010K length (the 100 took 1.5 seconds). So I revised to find the entries that can be the final entry, and then (if there is one) have other entries "speak for" the only one they can go to. This repeats until I can't make progress, and then I do a brute force pass on what is left.
The ungolfed body:
#define R (i+v)
#define L (i-v)
#define V int v=array[i];
#define D data[i]
struct datum {
bool can_go_left : 1;
bool can_go_right : 1;
bool spoken_for : 1;
bool speaks_for : 1;
bool used : 1;
};
datum data[10000];
int attempt(int const array[], int length, int i, int needed)
{
if (needed == 0) return 1;
V
#define TRY(x) if (!data[x].used) { data[x].used=true; if (attempt(array,length,(x),needed-1)) return 1; data[x].used=false; }
if (D.can_go_left) TRY(L);
if (D.can_go_right) TRY(R);
return 0;
}
int test(int const array[], int length)
{
//memset(data, 0, sizeof(data));
int pending = 0,
final = 0,
i;
// initial setup. Sets up the data array, and pending and final
for (i=0; i<length; i++) {
V
D.can_go_left = L>=0;
D.can_go_right = R < length;
D.spoken_for = false;
D.speaks_for = false;
D.used = false;
if (D.can_go_left) {
pending++;
//if (D.can_go_right) {
// pending++;
//} else {
// //ok... speak for or final?
// pending++;
//}
} else {
if (D.can_go_right) {
//ok... speak for or final?
pending++;
} else {
D.speaks_for = true;
final++;
}
}
}
dump_array(array,length,"initial setup",pending,final);
if (final>1) return false;
// passes trying to improve. Generatlly needs final...
bool dirty = true;
while (dirty && (pending>0)) {
dirty = false;
for (i=0; i<length; i++) {
V
if (D.speaks_for) continue;
bool changed = false;
if (D.can_go_left && data[L].spoken_for) { D.can_go_left=0; changed=true; }
if (D.can_go_right && data[R].spoken_for) { D.can_go_right=0; changed=true; }
if (changed) dirty = true;
if (D.can_go_left) {
if (!D.can_go_right) {
//if (D.can_go_right) {
// //still pending
//} else {
if (final) {
data[L].spoken_for=true;
D.speaks_for=true;
dirty=true;
}
}
} else {
if (D.can_go_right) {
if (final) {
data[R].spoken_for=true;
D.speaks_for=true;
dirty=true;
}
} else {
D.speaks_for = true;
final++;
}
}
}
dump_array(array,0,"after pass",pending,final);
if (final>1) return 0;
}
dump_array(array,length,"after all pass",pending,final);
//do the brute force...
for (i=0; i<length; i++) {
D.used = true;
if (attempt(array,length,i,length-1)) return 1;
D.used = false;
}
return 0;
}
JavaScript (Node.js), 70 bytes
f=(a,i)=>a.some((c,j)=>c*c-i*i--?!/\d/.test(a):f(c=[...a],j,c[j]=1/0))
Don't get how xor of Arnauld work but whatever
Brachylog, 66 bytes
~c₂↰₁
kʰc+0|htℕ₁J&{k,0}ʰ;[J]z{↰₅|↔{↔ʰ}ᵐ↰₅↔ᵐ↔}↰
⟨⟨hⁱ²c{th₎}⟩≡{tb₎}⟩
Explanation
Performs an actual traversal of the list, replacing visited numbers with 0s and using Brachylog's non-determinism to pick directions.
Entry point (takes a list of integers as input):
~c₂↰₁
~c₂ Un-concatenate the input list into two parts
↰₁ Call the below predicate
Main, recursive predicate:
kʰc+0|htℕ₁J&{k,0}ʰ;[J]z{↰₅|↔{↔ʰ}ᵐ↰₅↔ᵐ↔}↰
EITHER:
kʰ Remove the last element of the first part
c Concatenate all remaining elements in one list
+0 The sum is 0
(in which case, return success)
| OR:
ht The last element of the first part
ℕ₁ must be a positive integer (not 0)
J Store that as J, the jump distance
& And
{ }ʰ Modify the first part as follows:
k Remove the last element
,0 Concatenate a 0 in its place
;[J] Pair the modified list with [J]
z Zip, pairing each of the two parts with J
{ } Either:
↰₅ Call the below predicate directly
| Or:
↔ Swap the two parts
{↔ʰ}ᵐ and reverse each part
↰₅ Then call the below predicate
↔ᵐ Afterwards, reverse each part
↔ and swap the two parts back
↰ Call this predicate recursively
Helper predicate that does the jumps (slightly ungolfed so it's easier to explain):
⟨⟨{hh}c{th₎}⟩≡{tb₎}⟩
{hh} The first part
{th₎} The first J elements of the second part
⟨ c ⟩ Concatenate those two lists
This is the new first part
{tb₎} The second part without the first J elements
This is the new second part
⟨ ≡ ⟩ Wrap both parts in a list and return it
A partial worked example: Suppose our input list is [5,3,2,6,1,4] and we are starting at the 2. After splitting the list at that point, we have [[5,3,2],[6,1,4]]. The main predicate saves off the 2 in J and replaces it with 0, giving [[5,3,0],[6,1,4]]. Pairing with [J] gives [[[5,3,0],[6,1,4]],[2]]. Zipping gives [[[5,3,0],2],[[6,1,4],2]]. Then we call the helper predicate:
{h } First element: [[5,3,0],2]
{ h} First element of that: [5,3,0]
{t } Last element: [[6,1,4],2]
{ h₎} If that is of the form [A,B], take the first B elements of A: [6,1]
⟨ c ⟩ Concatenate those two: [5,3,0,6,1]
{t } Last element: [[6,1,4],2]
{ b₎} If that is of the form [A,B], remove the first B elements from A: [4]
⟨ ≡ ⟩ Pair those two: [[5,3,0,6,1],[4]]
This represents a jump 2 spots to the right, onto the 1. The recursion continues from here, backtracking when it hits a dead end.
Python3, 316 bytes
E=enumerate
def f(l):
if(O:=[i for i,a in E(l)if i-a<0 and i+a>=len(l)]):
q,s=[(O[0],[O[0]])],[]
for i,L in q:
if len(L)==len(l):return 1
T={}
for I,a in E(l):
if any(I+a*j==i for j in[1,-1])and I not in L:T[I]=sum(0<=I+j*a<len(l)for j in[1,-1])
q+=[(K,L+[K])for K in T if T[K]==min(T.values())]
JavaScript (ES6), 74 bytes
Returns a Boolean value.
a=>a.some(g=(v,i)=>(v=a[i])?v^=a[i]^=g(a[i]=0,i-v)|g(0,i+v):!a.some(v=>v))
JavaScript (ES6), 71 bytes
Similar but much slower.
a=>a.some(g=(v,i)=>(v=a[i])?v^=a[i]^=g(a[i]=0,i-v)|g(0,i+v):!+a.join``)
Pyth, 17 bytes
sqVmaVtdd.pUQPM.p
Takes input as a list, outputs the number of valid traversal paths (0 is falsy in pyth, >=1 is truthy). Link will time out for any inputs of length greater than about 9.
Explanation
sqVmaVtdd.pUQPM.pQ # implicitly add Q
# implicitly assign Q = eval(input())
PM # remove the last element of each of
.pQ # all permutations of Q
maVtdd # get the absolute differences between adjacent elements of
.pUQ # all permutations of range(len(Q))
qV # vectorized equality, look for elements that are equal across these two lists
s # sum