Chain words crossword-style

18

1

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!

Denker

Posted 2016-02-27T19:51:01.167

Reputation: 6 639

Example 2, the first possible intersection between site and graduated is t – edc65 – 2016-02-29T14:59:22.307

@edc65 Shame on me, fixed it. Thanks for the hint! – Denker – 2016-02-29T15:03:28.420

Answers

3

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>

edc65

Posted 2016-02-27T19:51:01.167

Reputation: 31 086

3

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!

Thomas Oltmann

Posted 2016-02-27T19:51:01.167

Reputation: 471

one char: a++)N+=strlen(v[a]) => )N+=strlen(v[a++]) – tucuxi – 2016-02-29T15:35:57.087

another: char F[W][H],*p => char*p,F[W][H] – tucuxi – 2016-02-29T15:37:03.403

3 chars: remove {} from single-line for, replace k++)putchar(F[k][l] with )putchar[k++][l] – tucuxi – 2016-02-29T15:49:44.917