18
\$\begingroup\$

The challenge

Given a list of words ["Programming", "Puzzles", "Code", "Golf"] output the words crossword-style:

      P r o g r a m m i n g
      u
      z
      z
  G   l
C o d e
  l   s
  f

The Algorithm

  • You have to process the list in the given order.
  • The words are printed in alternating orientations, starting horizontally.
  • The two words intersect at the first letter in the first word which is also present in the second word. If this letter occurs multiple times in the seond word, take the first one.

    Example:
    ["no", "on"] becomes:

    o
    n o
    

    and not

    n o
      n
    

Additional notes

  • Adjacent words in the list will have at least one common letter. ["Hi", "there"] is not a valid input.
  • Words will never collide. There will always be enough space to print the a word at the first possible intersection. ["Hello", "there", "end", "hello"] is not a valid input
  • The matching is case-sensitive.
  • Words can expand to the left and to the top.
  • The letters of the horizontal words have to be separated by one space.
  • The input list will contain at least two words.
  • All words will match the regex: [A-Za-z]+
  • You may print as many trailing whitespaces or newlines as you want, as long as the words are correctly chained.
  • On the other hand you may not add additional leading whitespaces. The word which floats to the left the most has zero leading spaces, the other lines have so many leading spaces that it all lines up correctly.
  • You program has to be able to deal with an arbitrary amount of words

Rules

Test cases

Input list on the first line, output starts on the second line.

["Stack", "Exchange"]
    E
    x
    c
    h
S t a c k
    n
    g
    e
["This", "site", "graduated", "finally"]
    f
    i       s
    n   T h i s
g r a d u a t e d
    l       e
    l
    y


Happy Coding!

\$\endgroup\$
  • \$\begingroup\$ Example 2, the first possible intersection between site and graduated is t \$\endgroup\$ – edc65 Feb 29 '16 at 14:59
  • \$\begingroup\$ @edc65 Shame on me, fixed it. Thanks for the hint! \$\endgroup\$ – Denker Feb 29 '16 at 15:03
3
\$\begingroup\$

JavaScript (ES6) 253

As an anonymous function with an array parameter

z=>(z.map((w,i)=>(i&&[...p].some((c,j)=>~(k=w.search(c))?i&1?[y-=k,x+=j]:[y+=j,x-=k]:0),[p=w,x<t?t=x:x,y<u?u=y:y]),t=u=x=y=0).map(([w,x,y],i)=>{x-=t,y-=u;for(c of w)(o[y]=o[y]||[])[x]=c,i&1?y++:x++},o=[]),o.map(r=>[...r].map(x=>x||' ').join` `).join`
`)

F=z=>(z.map((w,i)=>(i&&[...p].some((c,j)=>~(k=w.search(c))?i&1?[y-=k,x+=j]:[y+=j,x-=k]:0),[p=w,x<t?t=x:x,y<u?u=y:y]),t=u=x=y=0).map(([w,x,y],i)=>{x-=t,y-=u;for(c of w)(o[y]=o[y]||[])[x]=c,i&1?y++:x++},o=[]),o.map(r=>[...r].map(x=>x||' ').join` `).join`
`)

// Less golfed
F=z=>(
  z.map( // Step 1, find intersection points and relative position
    (w,i)=>(
      i && // for each word after thw first, find position respect the previous word
      [...p].some((c,j)=> // scan prec word using .some to exit at the first intersection found
         ~(k=w.search(c)) // search current char of p inside w
         ?i&1 // calc position, odd is vertical, even is horizontal
           ?[y-=k, x+=j] // returning an array so to have a truthy value
           :[y+=j, x-=k] // returning an array so to have a truthy value
         :0 // false = not found, continue the scan
      ),
      [p=w, // set preceding word
       x<t?t=x:x, // keep trace of min x
       y<u?u=y:y  // keep trace of min y
      ] // meanwhile, return word, x and y to be used in next step 
    ), t=u=x=y=0 // initializations
  )
  .map(([w,x,y],i)=>{ // Step 2, put char into the output array
      x-=t,y-=u; // normalize position respect to min values
      for(c of w) // for each char in word, set in the output array at the right place
        (o[y]=o[y]||[])[x]=c, 
        i&1?y++:x++ // increment x or y, again odd is vertical, even is horizontal
    }, o=[] // initialization of output array
  ),
  // Step 3, add the missing spaces and newlines
  o.map(r=>[...r].map(x=>x||' ').join` `).join`\n`
)

O.textContent=F(["This", "site", "graduated", "finally"])
<pre id=O></pre>

\$\endgroup\$
3
\$\begingroup\$

ANSI C, 385 390 Characters

int N,a=1,x,y,d=1,u,k,l;int main(int c,char**v){for(;a<c;)N+=strlen(v[a++]);int H=N*2,W=N*4,m=H,n=N,q=m,w=n;char*p,F[W][H],*o;memset(F,32,W*H);for(a=1;a<c;a++){q=(x=m)<q?m:q;w=(y=n)<w?n:w;m=-1;for(p=v[a];*p;p++){F[x][y]=*p;if(m<0&&a<c-1&&(o=strchr(v[a+1],*p))){u=o-v[a+1];m=d?x:x-u*2;n=d?y-u:y;}if(d)x+=2;else y++;}d=!d;}for(l=w;l<H;l++){for(k=q;k<W;)putchar(F[k++][l]);putchar(10);}}

Call it like this: ./crossword This site graduated finally

Ungolfed version:

int N,a=1,x,y,d=1,u,k,l;
int main(int c, char **v) {
    for(;a<c;)
        N+=strlen(v[a++]);
    int H = N*2, W = N*4, m = H, n = N, q=m, w=n;
    char *p,F[W][H], *o;
    memset(F, 32, W*H);
    for (a=1; a < c; a++) {
        q=(x=m)<q?m:q;
        w=(y=n)<w?n:w;
        m=-1;
        for (p=v[a]; *p; p++) {
            F[x][y] = *p;
            if (m<0&&a<c-1&&(o = strchr(v[a+1], *p))) {
                u = o-v[a+1];
                m = d ? x : x-u*2;
                n = d ? y-u : y;
            }
            if (d) x+=2; else y++;
        }
        d=!d;
    }
    for (l = w; l < H; l++) {
        for (k = q; k < W;)
            putchar(F[k++][l]);
        putchar(10);
    }
}

Thank you tucuxi for the tips!

\$\endgroup\$
  • \$\begingroup\$ one char: a++)N+=strlen(v[a]) => )N+=strlen(v[a++]) \$\endgroup\$ – tucuxi Feb 29 '16 at 15:35
  • \$\begingroup\$ another: char F[W][H],*p => char*p,F[W][H] \$\endgroup\$ – tucuxi Feb 29 '16 at 15:37
  • \$\begingroup\$ 3 chars: remove {} from single-line for, replace k++)putchar(F[k][l] with )putchar[k++][l] \$\endgroup\$ – tucuxi Feb 29 '16 at 15:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.