The Scenario

Given an input of ASCII lowercase letters and spaces, draw a spiral of characters that traces the original input of characters excluding spaces.

The Rules

1) The characters shall spiral counterclockwise to the left in an outwardly fashion. If a left turn is not possible, then move straight.

Given: abcdefg

Image tracing first example

2) The characters can spiral into previous characters so long as rule #1 is not violated. Also, if that character is spiraled into, then that character is uppercased. Once a character is uppercased, it will stay uppercased regardless of the number of times it is reused.

Given: apples appeal

Image tracing second example

  • 1
    \$\begingroup\$ So if the word keeps into the spiral but violates the next character then the program stops? \$\endgroup\$
    – Matt
    Mar 15, 2016 at 2:28
  • \$\begingroup\$ I think what makes this a good challenge is you would have to "rewind the stack" so to speak and resume at a point that makes rule #1 always work. \$\endgroup\$
    – Tim Reddy
    Mar 15, 2016 at 13:51
  • 5
    \$\begingroup\$ The current wording makes rule 2 seem entirely optional. If it should be compulsory then I think a much more comprehensive test suite is necessary. \$\endgroup\$ Apr 29, 2016 at 12:49
  • 1
    \$\begingroup\$ What should the output be for input abcdefghab? \$\endgroup\$ Jun 3, 2017 at 15:03

1 Answer 1


JavaScript, 225 221 212 bytes

-9 bytes thanks to Conor O'Brien

Please note that your text cases conflict with each other. Your first test case starts in the middle of the spiral. Your second test case starts in the top middle of the spiral. I went with your first test case, because it was the first one I saw. You haven't edited your question in over a year, so sorry for the presumption.

First Test Case:

|     |
2<-1  6
|     |

Second Test Case:

|     |
|     |

Without any further adieu, here is the golfed code. I am 100% sure that if the community chips it this could be cut significantly. This returns a multiline array.

s=>eval("s=[...s.replace(/ /g,'')];i=0;k=j=1;a=[[],[],[]];b='00122210';c=b*100+'';for(;;){for(l=0;l<8;l++){if(!s[i])break;if(a[k][j]==s[i])s[i]=s[i].toUpperCase();a[k][j]=s[i];k=b[l];j=c[l];i++}if(!s[i])break}a")

Prettification snippet (prints a multiline string to console). Please note the different in my test case #2 and OP's test case #2 (see above if you have not already):

(if someone with more experience with snippets wants to fix this into HTML input feel free to edit this, I need to go to bed).

s=>eval("s=[...s.replace(/ /g,'')];i=0;k=j=1;a=[[],[],[]];b='00122210';c=b*100+'';for(;;){for(l=0;l<8;l++){if(!s[i])break;if(a[k][j]==s[i])s[i]=s[i].toUpperCase();a[k][j]=s[i];k=b[l];j=c[l];i++;g(a)}if(!s[i])break}a")

//replace argument here to change output
var arr = f("apples appeal");

function g(ar) {
  var str = "";

  for (x = 0; x < 3; x++) {
    for (y = 0; y < 3; y++) {
      str += ar[y][x] || " ";
    str += "\n";

Ungolfed and Explanation

    //remove spaces
    input = input.replace(/ /g, "");
    //convert to array (so I can uppercase individual letters)
    input = input.split("");
    //position in input
    var pos = 0;
    //positions inside output
    var xPos = 1;
    var yPos = 1;
    //output container (3 rows, 3 columns)
    var arr = [[],[],[]];
    //counterclockwise indexes for x
    var xOrder = "00122210";
    //counterclockwise indexes for y
    //var yOrder = "12221000"
    var yOrder = xOrder * 100 + "";
    //loop infinitely (breaks when input[pos] is undefined)
    for (;;) {
        //loop around circle
        for (var i = 0; i < 8; i++) {
            if (!input[pos]) {
            //if item already in array equal next item in input, set next item in input to caps before
            if (arr[xPos][yPos] == input[pos]) {
                input[pos] = input[pos].toUpperCase(); 
            //write or overwrite in array with current from input
            arr[xPos][yPos] = input[pos];
            //increment last because we do not prime our loops
            xPos = xOrder[i];
            yPos = yOrder[i];
        if(!input[pos]) {
    return arr;
  • 1
    \$\begingroup\$ a.split("") is equivalent to [...a]; s=>{...;return a;} is equivalent to s=>eval("...;a") (and the ; is optional in the less golfed version); all semicolons followed by a } are optional \$\endgroup\$ May 26, 2017 at 22:55
  • \$\begingroup\$ @ConorO'Brien thank you :) \$\endgroup\$
    – Stephen
    May 26, 2017 at 23:37
  • \$\begingroup\$ What output do you get for the test case apples appeal? I'm seeing ppa eas aLe, which is definitely not correct because there's no l next to the ps. \$\endgroup\$ Jun 3, 2017 at 9:47
  • \$\begingroup\$ @PeterTaylor the output is correct, according to the spiral order of the first test case, which I based my program on. The second test case uses a different spiral order (starts on the top). I added a log for each iteration of the snippet. Look at that - it might make more sense. \$\endgroup\$
    – Stephen
    Jun 3, 2017 at 14:16
  • \$\begingroup\$ By the logic of the first test case the output would be eppa apas lple s. \$\endgroup\$ Jun 3, 2017 at 15:01

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