# Relations between interval and semitones

Output this table:

-2* -1* - 0 - 1 2
-1* 0 1 - 2 3 4
1 2 3 - 4 5 6
3 4 - 5 - 6 7
5 6 - 7 - 8 9
6 7 8 - 9 10 11
8 9 10 - 11 12 13
10 11 - 12 - 13 14
• You can output one string with two types of split, 1D string array with one type of split, or 2D string array
• If your language support mixed type then you can fill numbers in number cells(but not -1* and -2*)
• If your number type has one value - then you can use it in - cells. Otherwise they should be text -.
• This table comes from here but I removed 1st row and 1st column
• Shortest code wins
• Why can't the asterisked negative numbers be represented with a numeric type? Looking at the linked Sandbox post you got the table from, it looks like the asterisks just refer to a footnote... Commented Jul 18, 2023 at 5:08
• @UnrelatedString Because -1* isn't -1
– l4m2
Commented Jul 18, 2023 at 6:04
• @l4m2: what Unrelated String is saying is that the *s are just pointing to the footnote "* Negative distance doesn't exist but it can be added 12 until non-negative" - they aren't actually part of the table. Commented Jul 18, 2023 at 7:37
• "split" -> "delimiter"? Also, I'm not entirely sure what the 3rd bullet point means... does it mean that you can use NaN or null? Commented Jul 18, 2023 at 8:45
• What's the use of the asterisk in -2*; the original footnote is missing.
– Kaz
Commented Jul 19, 2023 at 1:01

# JavaScript (ES6), 90 bytes

Returns a single string, using commas and line feeds as delimiters.

f=(n=7)=>~n--?[..."0024200"].map(j=>4-(n&2)&j?'-':v+["**"[++v+1]],v=34-n*7>>2)+
+f(n):''


Try it online!

Or 78 bytes without the asterisks:

f=(n=7)=>~n--?[..."0024200"].map(j=>4-(n&2)&j?'-':v++,v=34-n*7>>2)+
+f(n):''


Try it online!

### How?

We iterate from $$\n=6\$$ to $$\n=-1\$$. The starting value of each row can be obtained with:

$$v_n=\left\lfloor\frac{1}{4}(34-7n)\right\rfloor$$

There are 2 distinct row patterns:

$$\begin{cases}[v_n,v_n+1,\varnothing,v_n+2,\varnothing,v_n+3,v_n+4]&n\in\{-1,2,3,6\}\\ [v_n,v_n+1,v_n+2,\varnothing,v_n+3,v_n+4,v_n+5]&n\in\{0,1,4,5\}\end{cases}$$

We can just test the penultimate bit of $$\n\$$ to distinguish them. We generate $$\2\$$ if it's set or $$\4\$$ otherwise and do a bitwise AND with the digit from the lookup string "0024200" according to its position.

{map ->\i,\j {{j-3,j-2,$_&&j-1,!$_&&j-1,$_&&j,j+$_,j+1+$_}((153+>i)%%2)},<1 2 4 6 8 9 11 13>.kv}  Returns the output as a 2D list with False for the blanks. Try it online! • How fo False == -? – l4m2 Commented Jul 18, 2023 at 6:05 # Charcoal, 4739 37 bytes Ｅ⁸Ｅ⁺Σ…68ι⊕Ｅ⁷Σ…432234λ⎇﹪λ⁴⁺⊖⊖÷λ⁴…*‹λ⁸-  Try it online! Link is to verbose version of code. Outputs a Charcoal array, i.e. each element on its own line and each row double-spaced from the previous. Explanation:  ⁸ Literal integer 8 Ｅ Map over implicit range ⁷ Literal integer 7 Ｅ Map over implicit range 432234 Literal string 432234 … Truncated to length λ Current column Σ Digital sum ⊕ Vectorised increment ⁺ Vectorised add 68 Literal string 68 … Extended to length ι Current row Σ Digital sum Ｅ Map over list λ Inner value ﹪ Modulo ⁴ Literal integer 4 ⎇ If divisible then - Literal string - otherwise λ Current value ÷ Integer divided by ⁴ Literal integer 4 ⊖ Incremented ⊖ Incremented ⁺ Concatenated with * Literal string * … Truncated to length λ Current value ‹ Is less than ⁸ Literal integer 8  The program works by generating the following table, where the headers are generated from a list of differences: + 1 5 8 10 12 15 19 0 1 5 8 10 12 15 19 6 7 11 14 16 18 21 25 14 15 19 22 24 26 29 33 20 21 25 28 30 32 35 39 28 29 33 36 38 40 43 47 34 35 39 42 44 46 49 53 42 43 47 50 52 54 57 61 48 49 53 56 58 60 63 67 Multiples of 4 are replaced with - while the remaining numbers are integer divided by 4 and then decremented twice, appending a * if this reduces them below zero. # 05AB1E, 47 bytes 6L3-D>3FDÌ}D>DÌDÌ)εƵqbNèi¨Ƶ;S£ë3ô}'-.ý˜εD0‹i'*«  Try it online. Explanation: 6L # Push list [1,2,3,4,5,6] 3- # Decrease each by 3: [-2,-1,0,1,2,3] D> # Duplicate it, and increase each by 1 3F } # Loop 3 times: DÌ # Duplicate the top list, and increase each by 2 D>DÌDÌ # Three more duplicates with +1, +2, and +2 respectively again ) # Wrap all lists on the stack into a list ε # Map over each inner list: Ƶq # Push compressed integer 153 b # Convert it to binary: 10011001 Nè # Index the current map-index into it i # If this is 1: ¨ # Remove the last item of the list Ƶ; # Push compressed integer 212 S # Convert it to a list: [2,1,2] £ # Split the list into parts of that size: [[a,b],[c],[d,e]] ë # Else: 3ô # Split the list into triplets: [[a,b,c],[d,e,f]] } # After the if-else: '-.ý '# Intersperse the list of sub-lists with "-" delimiter ˜ # And flatten it to a single list again ε # Map over each inner value: D # Duplicate the current value 0‹i # Pop the copy, and if it's a negative integer: '*« '# Append a "*" # (after which the matrix is output implicitly as result)  See this 05AB1E tip of mine (section How to compress large integers?) to understand why Ƶq is 153 and Ƶ; is 212. # Python 3, 222 216 bytes r=[];z=(0,3,4,7);m=-1 for i in range(8): r.append([]);s=i*2-(i+1)//4 for q in range(7):d=q-3-int(q>3)+int(q<2 and i in z);r[m]+=[s+d];r[m][m]="-"if(q in(2,4)and i in z)or q==3 and i in(1,2,5,6)else r[m][m] print(r)  Try it online! • Welcome to code golf! Is your code producing the dashes in the right place? In particular, q==3 and z in(1,2,5,6) looks strange because q==3 seems to cause z==2. – xnor Commented Jul 19, 2023 at 10:51 • Yes you are right! I had it working perfect, but two of my variable-name substitutions pointed to d! I have updated my answer. Commented Jul 21, 2023 at 5:46 # Python 3, 76 bytes n=0 for r in b"(($"*2:n+=-4|r;print([r%c*'-'or(n:=n+1)for c in b""])


Try it online!

This prints each row as its own list. The two bytestrings contain unprintable characters -- here's the code with their ASCII values shown:

n=0
for r in[21,40,40,36]*2:n+=-4|r;print([r%c*'-'or(n:=n+1)for c in[1,1,5,3,5,1,1]])


Try it online!

The r's in [21,40,40,36]*2 correspond to the 8 rows, and the c's in [1,1,5,3,5,1,1] to the 7 columns. They are chosen to make a "modulo table" producing the positions of the dashes, with a dash where r%c==1 and r%c==0 elsewhere.

           c
1 1 5 3 5 1 1
r  %--------------
21 | 0 0 1 0 1 0 0
40 | 0 0 0 1 0 0 0
40 | 0 0 0 1 0 0 0
36 | 0 0 1 0 1 0 0
21 | 0 0 1 0 1 0 0
40 | 0 0 0 1 0 0 0
40 | 0 0 0 1 0 0 0
36 | 0 0 1 0 1 0 0


Each non-dash position is filled with the number n, which is first incremented. Changes to n persist between rows, so before the start of each row we decrease n from the end of the previous row by substracting either 3 or 4, noting that it will increment by 1 before the first value is produced.

These deltas are encoded per-row by the r's as -4|r, which produces [-4,-3,-3,-3,-4,-3,-3,-3]. Because this pattern repeats in 2 blocks of 4 for the 8 rows, as did the dash pattern, we write the r's list as a four-entry list repeated twice, saving bytes.

Here are all the properties we needed the hardcoded r's and c's to satisfy:

-4|21 == -3
-4|40 == -4
-4|36 == -4

21%5 == 36%5 == 1
40%3 == 1
21%1 == 40%1 == 36%1 == 40%5 == 21%3 == 36%3 == 0


I found these with a brute-force search, and many other options were possible.

# Scala, 145 bytes

Port of @xnor's Python answer in Scala.

Golfed version. Try it online!

var n=0;for(r<-Seq(21,40,40,36)++Seq(21,40,40,36)){n+= -4|r;println(Seq(1,1,5,3,5,1,1).map(c=>if(r%c==0){n+=1;n.toString}else"-").mkString(","))}


Ungolfed version. Try it online!

object Main {
def main(args: Array[String]): Unit = {
var n = 0
val rs = List(21, 40, 40, 36) ++ List(21, 40, 40, 36)
val cs = List(1, 1, 5, 3, 5, 1, 1)

for (r <- rs) {
n += -4 | r
val result = cs.map { c =>
if (r % c == 0) {
n += 1
n.toString
} else "-"
}
println(result.mkString(", "))
}
}
}