24
\$\begingroup\$

This is a QWERTY keyboard.

Q W E R T Y U I O P
 A S D F G H J K L
  Z X C V B N M

We can "spiral out" on this keyboard, starting from G. The spiral will start at G, go to H, then to Y, then to T, then F, then V, then B, then N, then J, then U, then R, then D, then C,... etc. Your challenge is to, given a number 1 ≤ N ≤ 26, output the first N characters in this spiral. (If you are confused, refer to the pictures at the end of the post.)

The catch? Your program's score is proportional to the indices of characters found inside the spiral!

Scoring

  1. For every letter (case-insensitive) in your code, add the index of that character in the spiral to your score (starting from 1).
  2. For every character not in the spiral, add 10 to your score.
  3. The lowest score wins.

For example, the program print("Hello, World!") has a score of 300.

For your convenience, I have written an automatic program grader.

var SPIRAL = "GHYTFVBNJURDCMKIESXLOWAZPQ";
function grade(program) {
    var score = 0;
    for(var i = 0; i < program.length; i++) {
        if(/^[A-Za-z]$/.test(program[i])) {
            score += SPIRAL.indexOf(program[i].toUpperCase()) + 1;
        }
        else {
            score += 10;
        }
    }
    return score;
}

input.oninput = function() {
    output.value = "Your program's score is: " + grade(input.value);
}
textarea { width: 500px; height: 6em; font-style: monospace; }
<textarea id="input"></textarea>
<textarea disabled id="output"></textarea>

Other rules

  • Your submission may be a program or function.
  • You may take N starting at 0 or 1 and ending at 25 or 26, respectively, but the outputs should still begin with "G" and end with "GHYTFVBNJURDCMKIESXLOWAZPQ".
  • You must output the characters in the spiral in order.
  • If a function, you may return a list of characters instead of a string.
  • You may have one trailing newline following the output.
  • You may use lowercase letters instead of uppercase letters, or a combination of both.

Test cases

number -> output
1 -> G
2 -> GH
5 -> GHYTF
12 -> GHYTFVBNJURD
15 -> GHYTFVBNJURDCMK
24 -> GHYTFVBNJURDCMKIESXLOWAZ
26 -> GHYTFVBNJURDCMKIESXLOWAZPQ

Pictures

regular keyboard

The spiral superimposed:

spiral keyboard

\$\endgroup\$
  • 3
    \$\begingroup\$ Someone has watched Sphere recently... \$\endgroup\$ – Pureferret Nov 29 '17 at 14:47
  • \$\begingroup\$ @Pureferret Could you enlighten me? I'm not sure what you refer to. \$\endgroup\$ – Conor O'Brien Nov 29 '17 at 14:48
  • \$\begingroup\$ @ConorO'Brien In Sphere (both the novel and movie), an alien communicates with humans using a two-digit numeric code where each number corresponds to a letter on the keyboard in a very similar pattern. \$\endgroup\$ – Engineer Toast Nov 29 '17 at 15:02

32 Answers 32

14
\$\begingroup\$

Japt, 304 264 162 points

Saved 40 points thanks to @ConorO'Brien

;î"历锋㫿鮹㿬崴ꨜꎋΞ"csG

Test it online!

In order to save as many points as possible, the entire string is condensed into 9 Unicode chars by interpreting each run of 3 letters as a base-36 number, then converting to a code point. The program itself takes this compressed string (which costs 110 points, including the quotes) and maps each charcode by converting it to a string in base-36 (G after the ; at the beginning). î takes the first {input} chars of this, which is implicitly printed.

\$\endgroup\$
11
\$\begingroup\$

C, score: 544

g(g){write(1,"GHYTFVBNJURDCMKIESXLOWAZPQ",g);}

Try it online!

\$\endgroup\$
  • \$\begingroup\$ ...why are you naming the function the same thing as the argument? \$\endgroup\$ – Nic Hartley Nov 29 '17 at 9:12
  • 6
    \$\begingroup\$ @QPaysTaxes Because g is the cheapest letter per the scoring used in the challenge. \$\endgroup\$ – Steadybox Nov 29 '17 at 9:13
  • \$\begingroup\$ Ah, I missed the custom scoring. \$\endgroup\$ – Nic Hartley Nov 29 '17 at 9:16
11
\$\begingroup\$

Spiral, score:  61921   5127   4715   4655  4191

4.X~>v+^#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v
   X *   X X X X X X X X X X X X X X X X X X X X X X X X X
   ! >   h y t f V b n j u [ ( 1 3 2 ) ] U J N B F T Y H G
0;vgv*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*vvv****v+^v+^v+^v+^*v++4
    X X X X X X X X X X X X X X X X X X X X X X X X X X
    v v v v v v v v v v v v v v v v v v v v v v v v v v
    Y y J F V u t U [ G H B n 3 N 2 j ) h g f ] ( 1 b T

An interpreter can be found here.

Explanation:

P.X~ZZ*v+^#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v
   X       X X X X X X X X X X X X X X X X X X X X X X X X X
   !       h y t f V b n j u r d c m k i e s x l o w a z p q
0;vgv*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*v*****************************************************************vP
    X X X X X X X X X X X X X X X X X X X X X X X X X X
    v v v v v v v v v v v v v v v v v v v v v v v v v v
    z y x w V u t s r q p o n m l k j i h g f e d c b a

The program begins at the 0 character on the fourth line. The first piece of code to run is 0;vg. ; takes a number as input and places it in the stack. v places what is in the register (a zero) into the stack. It will be used as the counter. g is a label, when it is reached, the control jumps to the other occurence of the letter g in the code.

So this is where the control is now:

X
v
g

Since there is whitespace in all other directions, the instruction pointer starts moving upwards. v places a zero into the stack, and X pops it from the stack immediately. Because the popped value is zero, the instruction pointer moves to X (otherwise it would treat it as whitespace).

By default, the control flow is in turn-right mode, so now when it reaches the junction, the instruction pointer turns to the right. v yet again pushes a zero into the stack, * increments the register by one.

v*v*v
  X
  v
  g

The next v places what is in the register (number 1) into the stack, the instruction pointer attempts to turn to the right, hitting the next X. The value just added to the stack is popped and placed in the register. Because it is non-zero, X is not entered, and the IP proceeds to the next * on the right instead, again incrementing the value in the register.

v*v*v*v*v
X X X X X
v v v v v
i h g f e

This happens again and again until we reach the end of this part and the line of *s begins. By now the value in the register is 6, which is ASCII letter g minus ASCII letter a. Thus with a line of 97 *s we increment the value in the register to 103, which matches the letter g we want to print. v pushes it into the stack, and P is another label upon hitting which we jump to the other P on the first line of the code.

Here . pops the value from the stack and prints it as a character. After that X pops the extraneous zero from the stack, then ~ compares the two remaining values in the stack (the values being the counter and the input value). If the values are the same, the operator places zero in the stack (otherwise -1 or 1). Again, the control attempts to turn right. X pops the value of the comparison from the stack, if it is zero, X, and after it ! is entered, terminating the program.

P.X~ZZ*v+^
   X
   !

Otherwise the IP continues to the Z, which is a label which in this case jumps only one step to the right. The reason for doing this is that jumping sets the value in the register back to zero. * increments the register and v places the resulting 1 into the stack. + pops the two top elements of the stack (the 1 and the counter), adds them, and places the result in the stack (in effect this increments the counter by one). ^ copies the result from the stack to the register without removing it from the stack.

# decrements the value in the register by one, v pushes the decremented value to the stack, the IP attempts to turn to the right, and the X pops the value from the stack. If the value is non-zero the IP keeps moving to the east, decrementing the value in the register, until it hits zero, and the IP enters an X branch.

#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v#v
 X X X X X X X X X X X X X X X X X X X X X X X X X
 h y t f V b n j u r d c m k i e s x l o w a z p q

The branch leads to a label corresponding to the value of the counter. Upon hitting the label, the control jumps to the other occurence of the label in the section where we started with the label g, starting another iteration. As with the g, the value in the register gets incremented up to the ASCII value of the letter we need to print. Then the character is printed and the counter incremented, another label is selected. This happens until after the last iteration the counter equals the input, and the program terminates.

Edit:

P.X~Zv+^
   X *
   ! Z

Achieves the same thing as

P.X~ZZ*v+^
   X
   !

but with less whitespace.

Edit 2:

vv****v+^v+^v+^v+^*v++P

Can be used instead of:

*****************************************************************vP
\$\endgroup\$
  • 2
    \$\begingroup\$ Ironic that a languaje called "Spiral" has such a high score in a spiral output problem. \$\endgroup\$ – Shirkam Nov 29 '17 at 10:10
6
\$\begingroup\$

Haskell, 471

(`take`"GHYTFVBNJURDCMKIESXLOWAZPQ")

Try it online!

This is a bit of a benchmark, I feel like there must be a better way, but its the best I've found so far.

Explanation

I suppose I should explain this for those not familiar with Haskell too well. The function take takes the first n elements of the list. It is called like this:

take n list

We want to take the first n elements of the sting "GHYTFVBNJURDCMKIESXLOWAZPQ", so we want something like

f n=take n"GHYTFVBNJURDCMKIESXLOWAZPQ"

We can do better though, we can infix take using backticks

f n=n`take`"GHYTFVBNJURDCMKIESXLOWAZPQ"

And now this can be made pointfree

(`take`"GHYTFVBNJURDCMKIESXLOWAZPQ")
\$\endgroup\$
  • \$\begingroup\$ It's a shame partial application requires using partial in Clojure. This is what I was going for, but partial was too expensive. \$\endgroup\$ – Carcigenicate Nov 29 '17 at 2:37
  • 3
    \$\begingroup\$ Isn't your score 470? That's what the snippet in the question is giving me anyway... \$\endgroup\$ – Just a student Nov 29 '17 at 8:33
5
\$\begingroup\$

Jelly, 211 score

19 bytes

“eȷÞ('¢ạẓkȮV’œ?ØAðḣ

Try it online!

saved a bunch of score thanks to Emigna's suggestion to use œ? :D

\$\endgroup\$
5
\$\begingroup\$

Vim, 461 418

CGHYTFVBNJURDCMKIESXLOWAZPQg^[G@" D

Thanks @pacholik for -43 score!

Try it online!

vim-animation

\$\endgroup\$
  • 1
    \$\begingroup\$ Make it 418 with CGHYTFVBNJURDCMKIESXLOWAZPQg©G@" D (© is escape) \$\endgroup\$ – pacholik Nov 29 '17 at 9:04
4
\$\begingroup\$

Befunge, Score: 531

QPZAWOLXSEIKMCDRUJNBVFTYHG"&\>,# 1#\-# :# _@

I feel this challenge would have been more interesting if the output had to be in a spiral as well.

\$\endgroup\$
4
\$\begingroup\$

TI-Basic (TI-84 Plus CE), 454 432 points

sub("GHYTFVBNJURDCMKIESXLOWAZPQ",1,Ans

-22 points from Conor O'Brien

Run with 5:prgmNAME.

Returns/prints the substring from 1 to Ans (the number input).

TI-Basic is a tokenized langauge, so I'm scoring this by the byte values of the tokens.

sub( is 0xbb 0x0c, so 20

" is 0x2a, so *, so 10*2=20

Uppercase letters don't change, so the string is 351

, is 0x2b, so +, so 10*2=20

1 is 0x31, so 1, so 10

Ans is 0x72, which is r, so 11

20 + 20 + 351 + 20 + 10 + 11 = 432

\$\endgroup\$
  • \$\begingroup\$ With this interpretation of the scoring rules, you can save 31 more bytes by looking for the letters in creative places. Replace the S, A, Z, P by the stat variables s, a, z, p (in the STAT + 5 menu), which score 17 points each: they're 2-byte tokens whose first byte corresponds to b. Replace the O, W, Q by the ordinary lowercase letters, which score 20 points each: they're 2-byte tokens 0xBBBF, 0xBBC7, 0xBBC1. \$\endgroup\$ – Misha Lavrov Nov 29 '17 at 8:03
3
\$\begingroup\$

Python 3, score = 762 753

1-based input. This is worse than the trivial approach, since it uses 37 non-letters. It is somewhat interesting, though.

-9 thanks to Leo.

h=lambda g:g and h(g-1)+chr(65+int('GYGGYHGYYGYTGTYHGYGGHGGTGHGYGYGFGHGGYGGHHGGHHYYGHGHGGYFGGYHGGTHGHTGGGGGFGGVHGT'[g*3-3:g*3],35)%26)or''

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ I like this approach :) By the way [:g*3][-3:] can become [g*3-3:g*3] lowering the total score by 9 points \$\endgroup\$ – Leo Nov 29 '17 at 3:51
3
\$\begingroup\$

05AB1E, score: 204

.•3ŽγY
₁ùÐÁo0ª ’ö:•£

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ I wondered why it was cached hah! \$\endgroup\$ – Magic Octopus Urn Nov 30 '17 at 1:17
2
\$\begingroup\$

Brainf**k, score = 2690

Input a single byte ranging from 0x1 to 0x1a.

>>++++>+++>>>>++++++++++[<+<-<+>>>-]<<--<+++>>>++>->+++++++++++>++++++>-------->---->-->>---------->--------->+++++>++++++++>--->+>----------->+++++++++>------->+++++++>++++++++++++>----->------>+>>+++++++[<+++++++++++[<[[+<]+<]>->[[>]>]<<<-]>-]<<[-]>,[[<]<.[-]>+[>]<-]

Try it online!

\$\endgroup\$
2
\$\begingroup\$

APL (Dyalog), score: 391

↑∘'GHYTFVBNJURDCMKIESXLOWAZPQ'

Try it online!

The only use for Latin letters in Dyalog is in variable names and some system functions. Apart from that, only glyphs and some Greek letters are used.

\$\endgroup\$
1
\$\begingroup\$

Python 3, 522

lambda g:"GHYTFVBNJURDCMKIESXLOWAZPQ"[:g]

Try it online!

An anonymous lambda utilizing Python's slicing of strings ("asdf"[:i] gets the first i characters of "asdf")

\$\endgroup\$
1
\$\begingroup\$

Clojure, 484 474 points

-10 points because apparently a % can exist after a number without a space separating them!? I might have to go back over and improve some submissions.

#(subs"ghytfvbnjurdcmkiesxlowazpq"0%)

An anonymous function. Basically a Clojure port of what's already been posted. Scores nicely! I think this is the first Clojure program I've ever written that doesn't contain a single space.

(defn spiral [n]
  ; Substring the hardcoded list, going from index 0 to n
  (subs "ghytfvbnjurdcmkiesxlowazpq" 0 n))
\$\endgroup\$
1
\$\begingroup\$

Ly, 521 points

"QPZAWOLXSEIKMCDRUJNBVFTYHG"ns[,spol];

Try it online!

I don't feel as though this is optimizable.

\$\endgroup\$
1
\$\begingroup\$

Bash, score: 465

cut -b-$1<<<GHYTFVBNJURDCMKIESXLOWAZPQ

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Husk, 293 bytes

↑¨ghytfvb⌋ȷÜdcmkÏexl⁰Λzpq

This is the shortest one I could find, next closer ¨gHYtfvB⌋ȷÜdCmkÏex←ẆAzpq¨ for a score of 293..

Try it online!

Explanation

Brute-force search, turns out all lower-case gave the best score. It's basically the same as @Wheat Wizard's solution, take () on a compressed string (¨).

\$\endgroup\$
1
\$\begingroup\$

Common Lisp, score: 580

(subseq"GHYTFVBNJURDCMKIESXLOWAZPQ"0(read))

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Excel, 490 points

=LEFT("GHYTFVBNJURDCMKIESXLOWAZPQ",A1)

Convention for Excel ansers is to take input from A1. Changing this to G1 cuts 22 points (468).

=LEFT("GHYTFVBNJURDCMKIESXLOWAZPQ",G1)
\$\endgroup\$
1
\$\begingroup\$

C#, score 546

g=>"GHYTFVBNJURDCMKIESXLOWAZPQ".Substring(0,g);
\$\endgroup\$
1
\$\begingroup\$

Rust, score 443

It is not often that Rust is good at code golf but here it beats many languages

|g|&"GHYTFVBNJURDCMKIESXLOWAZPQ"[..g]
\$\endgroup\$
1
\$\begingroup\$

Golang, score 861

func g(g int){io.WriteString(os.Stdout,"GHYTFVBNJURDCMKIESXLOWAZPQ"[0:g])}

Play it online !

\$\endgroup\$
1
\$\begingroup\$

Javascript ES6, 527 points

g=>`GHYTFVBNJURDCMKIESXLOWAZPQ`.slice(0,g)

Try it !

f=g=>`GHYTFVBNJURDCMKIESXLOWAZPQ`.slice(0,g)

input.oninput = function() {
    output.value = f(input.value);
}
textarea { width: 500px; height: 6em; font-style: monospace; }
<textarea id="input"></textarea>
<textarea disabled id="output"></textarea>

\$\endgroup\$
1
\$\begingroup\$

PHP, 590 points

<?=substr(GHYTFVBNJURDCMKIESXLOWAZPQ,0,$argv[1]);

Try it online!

\$\endgroup\$
1
\$\begingroup\$

PHP, score 584

fiddled a bit with the dictionary; the fact that xoring the string cuts it off rendered substr obsolete.

<?=">1 -?/;73,+=:420<*!56.8#)("^str_repeat(y,$argv[1]);

Try it online.

\$\endgroup\$
0
\$\begingroup\$

Mathematica, 528

"GHYTFVBNJURDCMKIESXLOWAZPQ"~StringTake~#&

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Pyth, score: 371

<"GHYTFVBNJURDCMKIESXLOWAZPQ

Try it here.

How?

<"GHYTFVBNJURDCMKIESXLOWAZPQ"Q   implicit string end, implicit input
<                            Q   first Q(=input) elements ...
 "GHYTFVBNJURDCMKIESXLOWAZPQ"    ... of this string
\$\endgroup\$
0
\$\begingroup\$

Ruby, 453 points

->g{'GHYTFVBNJURDCMKIESXLOWAZPQ'[0,g]}

Try it online!

\$\endgroup\$
0
\$\begingroup\$

><>, 558+16= 574 points

<;v? : <{"GHYTFVBNJURDCMKIESXLOWAZPQ"
  >$o1-^

Uses the -v flag to push input onto the stack.

Pushes the spiral onto the stack in reverse order, then rotates the input to the top. Then, while the top of the stack is non-zero, prints the next letter and decrements the top of the stack.

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Pyth, 261 points

<."AZJ{Û§zoÆæÏýú

Try it here!

This outputs uppercase letter. For lowercase, you can try the alternative 261 byter.

\$\endgroup\$

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.