text:
Consonance or dissonance?
Given two note names, you are to write a program that determines if the interval formed by these two notes is consonant or dissonant.
Introduction
In Western music, there are only 12 "different" tones. Their names, sorted from lowest to highest, are these: C, C#, D, D#, E, F, F#, G, G#, A, A#, B. The sequence is cyclical, i. e. it continues with another C after the B, infinitely.
The distance between two tones is called an interval. The interval between any two notes that are adjacent in the series above (e. g. C — C# or E — F) is called a semitone. The interval between more distant notes is defined as the number of semitone steps needed to get from the first to the second (while possibly wrapping around the sequence). Some examples: D to E = 2 semitones, C to G = 7 semitones, B to D# = 4 semitones (this wraps around the sequence).1
Now, these intervals are divided into two categories: consonant (pleasantly sounding if you play the two notes at once) and dissonant (not so much).
Let's define the consonant intervals to be: 0, 3, 4, 5, 7, 8 and 9 semitones.
The rest of them is dissonant, namely: 1, 2, 6, 10 and 11 semitones.
The Challenge
Write a "program" (in the usual broad sense of the word: a function is perfectly OK) to do the following:

Take two note names (strings from the sequence above) as an input. You may take them however you like (from stdin, as arguments, separated by whatever you want, even feel free to take them as a list of characters (e. g. ["C","#"]). However, you may not assign any other names to the notes (especially you may not number them from 0 to 11 and use the numbers).
For you music geeks out there, the notes will be specified without the octave. In this case, it also does not matter in which order the notes come and which is lower and which is higher. Finally, you don't need to handle any names not in the list above. No other enharmonics like E#, no flats, double-alterations and so on.
Pick any two different values. Your program must output one of them whenever the interval formed by the two notes in the input is consonant, and the other if they are not. (Could be True and False, but even π and e if you want :))
This is a code-golf. The shortest program in bytes in each language wins. Have fun!

Examples and Test Cases
Note 1    Note 2    Output    Interval [semitones]
  C          D     Dissonant   2
  A#         A#    Consonant   0
  G          D     Consonant   7 (wraparound)
  D#         A     Dissonant   6
  F          E     Dissonant   11
  A          C     Consonant   3

I don't add more of them since there aren't any particularly treacherous cases in this.
This is a first challenge of mine, so any constructive criticism is warmly welcome :—). If you find the theory explanation sloppy, feel free to ask questions. Finally, please do not tell me that this is a dupe of this or this. I made sure it's not. (The latter is quite similar but more complex. I thought that putting up a little simpler challenge will make it easier for people to join.)

1: I tried to simplify this explanation as far as I could. There's a lot more theory around intervals. Please don't bash me for leaving it out.

Jelly, 21 bytes
Takes input as a list of two strings. Returns 0 for dissonant or 1 for consonant.
OḢ6×%21_Lµ€IA“¬ɠṘ’æ»Ḃ

Try it online!
OḢ6×%21_Lµ€IA“¬ɠṘ’æ»Ḃ   - main link
         µ€             - for each note             e.g. ["A#", "C"]
O                       -   convert to ASCII codes  -->  [[65, 35], 67]
 Ḣ                      -   keep the first element  -->  [65, 67]
  6×                    -   multiply by 6           -->  [390, 402]
    %21                 -   modulo 21               -->  [12, 3]
       _L               -   subtract the length     -->  [12, 3] - [2, 1] = [10, 2]
           IA           - absolute difference       -->  8
             “¬ɠṘ’      - the integer 540205
                  æ»    - right-shift               -->  540205 >> 8 = 2110
                    Ḃ   - isolate the LSB           -->  2110 & 1 = 0

Making-of
We first should note that the function F that we're looking for is commutative: for any pair of notes (A, B), we have F(A, B) = F(B, A).
Since there are not too many possible inputs and only 2 possible outputs to deal with, it must be possible to find a rather simple hash function H, such that |H(A) - H(B)| produces a limited range of values and is collision-free for all possible pairs of notes (A, B) with respect to the expected output.
We're going to test the set of functions H(mul, mod), which are defined as:
H(mul, mod)(s) = ((ORD(s[0]) * mul) MOD mod) - LEN(s)

Where ORD(s[0]) is the ASCII code of the first character of the note and LEN(s) is the length of the note (2 if there's a '#' and 1 if not).
Below is a commented version of the JS code that was used to find a couple of valid pairs (mul, mod) and the resulting bitmasks. There are many possible solutions, but * 6 % 21 is the shortest one with this method.

// all 12 notes
note = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'];

// reference implementation that takes 2 notes
// and returns 0 for dissonant or 1 for consonant
F = (a, b) =>
  +!~[1, 2, 6, 10, 11].indexOf((note.indexOf(a) - note.indexOf(b) + 12) % 12)

for(mul = 1; mul < 100; mul++) {
  for(mod = 1; mod < 31; mod++) {
    // hash function
    H = s => s.charCodeAt() * mul % mod - s.length;

    table = {};

    // for all possible pairs of notes (a, b)
    if(note.every(a => note.every(b => {
      // compute the table index
      idx = Math.abs(H(a) - H(b));

      // and the expected result
      res = F(a, b);

      // if the slot is empty, store the correct value
      if(table[idx] === undefined) {
        table[idx] = res;
        return 1;
      }
      // else, make sure that the correct value is already there
      return table[idx] == res;
    }))) {
      // if all tests pass: translate the table into a binary mask
      for(n = 0, msk = 0; n < 31; n++) {
        msk |= (table[n] || 0) << n;
      }
      // and display the result
      console.log('mul ' + mul + ', mod ' + mod + ' --> ' + msk);
    }
  }
}

How do you even come up with these things?.. Are you getting these kind of 'algorithms' by hand or by brute-force? And regardless of the answer of the second question: how?!.. :S "literal integer 540205; right shifted with (ASCII code; multiply by 6; modulo 21; keep first; subtract length...); bitwise-AND 1". Your answers keep impressing me every time..

@KevinCruijssen I've added the original JS code that was used to find these values.

Thanks for the added explanation. I'm still as impressed as first, but you gave a clear explanation of how you came up with it. Too bad I can only upvote once.

APL (Dyalog), 62 39 bytes
Uses ⎕IO←0; 0 is consonant, 1 is dissonant. Takes list of base note chars as left argument and list of sharps as right argument.
{⎕A[|-/('C D EF G A '⍳⍺)+⍵=⍕#]∊'BCGKL'}

Try it online!
{…} anonymous function where ⍺ is the left argument and ⍵ is the right argument
 ⎕A[…]∊'BCGKL' is the Alphabet, indexed by the following, a member of the string?
  ⍕# format the root namespace (yields the sharp character)
  ⍵= are the right argument chars (the sharps) equal to that?
  (…)+ add the following:
   'C D EF G A '⍳⍺ indices of the left argument chars in the string
  -/ difference between those
  | absolute value

Would you mind adding an explanation for those of us who are unfamiliar with APL?

@Draconis Explanation added.

MATL, 30 27 26 bytes
,j'DJEFPGIALBC'&mQs]ZP7Mdm

Inputs the two notes in different lines. Outputs 0 for consonant, 1 for dissonant.
Try it online! Or verify all test cases.
Explanation
The 11-character string
DJEFPGIALBC

encodes both the notes and the dissonant intervals, as follows.
The program first finds the 1-based indices of the input characters in the above string. A non-sharp input like D will give 1, E will give 3, ..., C will give 11. These numbers can also be considered 1×1 numeric arrays. A sharp input like C# will give the 1×2 array [11 0], meaning that C was found at position 11 and # was not found.
Observe that letters JPIL will never be present in the input. For now they are only used as placeholders, so that for example note E is two semitones above D. But they will also be useful to define dissonant intervals.
The numbers in the first entry of the 1×1 or 1×2 array correspond to note pitch in semitones, not counting sharp symbols (yet). Observe that the scale defined by these numbers doesn't start at C; but that doesn't matter because we only want intervals, that is, differences between notes. Subtracting the obtained numbers would give either the interval or 12 minus the interval. But first we need to consider the sharp symbol.
To consider sharp notes, a golfy way (in MATL) is to add 1 to each entry of the 1×1 or 1×2 array obtained previously and then sum the array (2 bytes). Thus non-sharp notes are increased by 1 and sharp notes by 2. This makes sharp notes 1 semitone higher than non-sharp notes, as required. We are also adding an extra semitone to all notes, but that doesn't change the intervals between them. So now note D will give pitch number 2, D# will give 3, ..., C will give 12, C# will give 13.
Dissonant intervals are 1, 2, 6, 10, or 11. These have a modulo-12 symmetry: an interval between two notes is dissonant if and only if the interval with the notes in reverse order, modulo 12, is dissonant.
If we compute the consecutive differences of the string 'DJEFPGIALBC' we get the numeric vector
6 -5 1 10 -9 2 -8 11 -10 1

which contains precisely the dissonant intervals, in addition to some negative values, which will be neither useful nor harmful. Observe that it is the choice of additional letters JPIL in the string 'DJEFPGIALBC' that defines (via consecutive differences) the dissonant intervals.
To see if the two input notes are dissonant we take the absolute difference of their pitch numbers. For example, C and D# will give numbers 12 and 3 respectively, and the absolute difference is 9. The actual difference would be -9, and the actual interval would be 3 (obtained as -9 modulo 12). But thanks to the symmetry referred to above, we can consider 9 instead of 3. Since 9 is not present in the vector of consecutive differences, the notes are consonant.

I like the way how you encoded both the notes and the dissonant intervals in the same string.

JavaScript (ES6), 68 64 bytes
Takes the notes as two strings in currying syntax (a)(b). Returns 0 for dissonant or 1 for consonant.
a=>b=>488055>>(g=s=>'C D EF G A'.search(s[0])-!s[1])(a)-g(b)+9&1

Test cases

let f =

a=>b=>488055>>(g=s=>'C D EF G A'.search(s[0])-!s[1])(a)-g(b)+9&1

console.log(f('C' )('D' )) // 0 (Dissonant)
console.log(f('A#')('A#')) // 1 (Consonant)
console.log(f('G' )('D' )) // 1 (Consonant)
console.log(f('D#')('A' )) // 0 (Dissonant)
console.log(f('F' )('E' )) // 0 (Dissonant)
console.log(f('A' )('C' )) // 1 (Consonant)

Formatted and commented
a => b =>                       // given the two notes 'a' and 'b'
  488055 >>                     // 19-bit lookup bitmask: 1110111001001110111
    (g = s =>                   // we use g() to convert a note 's' into a semitone index
      'C D EF G A'.search(s[0]) // position of the note: -1 for 'B' (not found) to 9 for 'A'
      - !s[1]                   // subtract 1 semitone if the '#' is not there
    )(a)                        // compute the result for 'a'  --> [ -2 ...  9]
    - g(b)                      // subtract the result for 'b' --> [-11 ... 11]
    + 9                         // add 9                       --> [ -2 ... 20]
  & 1                           // test the bitmask at this position (0 if negative or > 18)

Jelly, 26 bytes
i@€ØAo.SḤ’d5ḅ4µ€ạ/“¢£©½¿‘ċ

A monadic link taking a list of the two notes (as lists of characters) and returning 0 for consonant and 1 for dissonant.
Try it online! or see all inputs in the test-suite.
How?
i@€ØAo.SḤ’d5ḅ4µ€ạ/“¢£©½¿‘ċ - Link: list of lists of characters, notes
              µ€           - for €ach note in notes: (call the resulting list x)
   ØA                      -   yield the uppercase alphabet
i@€                        -   first index of c in ^ for €ach character, c
                           -     ...note '#' is not there so yields 0 (A->1, B->2,...)
      .                    -   literal one half
     o                     -   or (vectorised)  - e.g. "C#" -> [3, 0] -> [3, 0.5]
       S                   -   sum
        Ḥ                  -   double - that is ...  C C#  D D#  E  F F#  G G#  A A#  B
                                                 ->  6  7  8  9 10 12 13 14 15  2  3  4
         ’                 -   decrement         ->  5  6  7  8  9 11 12 13 14  1  2  3
           5               -   literal five
          d                -   divmod                (e.g. 9 -> [1,4] or 11 -> [2,1])
             4             -   literal four
            ḅ              -   convert from base     (e.g. [1,4] -> 8 or [2,1] -> 9)
                                                 ->  4  5  6  7  8  9 10 11 12  1  2  3
                 /         - reduce x with:
                ạ          -   absolute difference   (e.g. ["G#", "A"] -> [12, 1] -> 11)
                  “¢£©½¿‘  - code-page indices = [1, 2, 6, 10, 11]
                         ċ - count occurrences (1 if in the list, 0 if not)

Jelly, 31 bytes
O_65ị“¢[ḋṃ’b⁴¤+L$€Ḣ€ạ/e“cṾ’b12¤

Try it online!
wheeeeee 32 bytes too long
Explanation
O_65ị“¢[ḋṃ’b⁴¤+L$€Ḣ€ạ/e“cṾ’b12¤  Main link
O                                Cast each character to an int using Python `ord`
 _65                             Subtract 65 (A is 0, G is 7)
     “¢[ḋṃ’b⁴¤                   [2, 3, 5, 7, 9, 10, 0]
     “¢[ḋṃ’                      37058720
           b                     Digits in base
            ⁴                    16
    ị                            Index into this list; this creates the gaps for sharps
                 €               For each sublist
              +L$                Add the length to each element (Sharpens sharp notes)
              +                  Add
               L                 Length
                   €             For each sublist
                  Ḣ              Take the first element
                    ạ/           Absolute difference between the two (unoctaved) pitches # It's convenient that every interval's inverse (?) has the same consonance/dissonance
                      e          Is the semitone difference in
                       “cṾ’b12¤  [1, 2, 6, 10, 11]?
                       “cṾ’      25178
                           b     base
                            12   12

Hey, that's a great answer! I was wondering if someone makes use of the symmetry, and you did. And I like your method for matching the note names with numbers as well! +1.

The semitone difference may be symmetrical but you still get duff results - for example "G#", "A" (dissonant) yields a difference of 11 which is not in [1,2,6].

@JonathanAllan oh uh well that's embarrassing; I thought that absolute difference fixed that... ._. will fix lol

@JonathanAllan fixed for a couple extra bytes (3 IIRC)

Mathematica, 55 bytes
function                                                  arguments        bytes

FreeQ[1|2|6|10|11]@Abs[#-#2&@@Sound`PitchToNumber/@#]&    [{"C","F#"}]     55

Map the internal built-in Sound`PitchToNumber on the input (list of two strings), take the absolute difference, then pattern match for dissonant interval numbers.

Just for fun (non-competing)
Here are some shorter functions that violate the restriction “you may not assign any other names to the notes.” The rudimentary Music` package has predefined note constants (like A4 = 440.) and the function HertzToCents (which can be golfed). Instead of strings, we will use the note constants as arguments, but given in a different format for each function.
FreeQ[1|2|6|10|11]@Abs@@Round[.01HertzToCents@#]&         [{C3,Fsharp3}]   50+9=59
FreeQ[1|2|6|10|11]@Abs@Round[17Log[#2/#]]&                [C3,Fsharp3]     43+9=52
FreeQ[1|2|6|10|11]@Abs@Round[17Log@#]&                    [C3/Fsharp3]     39+9=48

The package import <<Music`; takes 9 bytes.
This function converts a string (like "F#") into a note constant (like Fsharp3):
Symbol[StringReplace[#,"#"->"sharp"]<>"3"]&                                44

To accept intervals larger than an octave, replace Abs[…] with Mod[…,12].

Why are some intervals considered dissonant? An interval is a ratio of two frequencies. If the ratio has a “simple” numerator and denominator, it tends to be more consonant. In 5-limit tuning, ratios can be factored into integer powers of only prime numbers less than or equal to 5. No interval in equal temperament, besides the octave, is a just interval; they are merely close approximations using powers of the 12th root of 2.
Instead of hard-coding which interval numbers are dissonant, we can find a rational approximation of the interval and then determine if its numerator and denominator are “simple” (meaning that the denominator is less than 5 and the ratio does not divide 7).
This table shows each of the steps in that process.
Table[
  Module[{compoundInterval,simpleInterval,rationalApprox,denomLeq5,div7,consonant},
    compoundInterval = Power[2, i/12];
    simpleInterval   = 2^Mod[Log2[compoundInterval], 1];
    rationalApprox   = Rationalize[N@simpleInterval, 1/17];
    denomLeq5        = Denominator[rationalApprox]<=5;
    div7             = Denominator[rationalApprox]>1 && rationalApprox\[Divides]7;
    consonant        = FreeQ[1|2|6|10|11][Mod[i,12]];

    InputForm/@{
      i, simpleInterval, rationalApprox,
      denomLeq5, div7, denomLeq5 && !div7,
      consonant
    }
  ], {i, 0, 12}
]

i   sInterval  ratio   denomLeq5  div7       den&&!div  | consonant?

0   1          1       True       False      True       | True
1   2^(1/12)   17/16   False      False      False      | False
2   2^(1/6)    9/8     False      False      False      | False
3   2^(1/4)    6/5     True       False      True       | True
4   2^(1/3)    5/4     True       False      True       | True
5   2^(5/12)   4/3     True       False      True       | True
6   Sqrt[2]    7/5     True       True       False      | False
7   2^(7/12)   3/2     True       False      True       | True
8   2^(2/3)    8/5     True       False      True       | True
9   2^(3/4)    5/3     True       False      True       | True
10  2^(5/6)    7/4     True       True       False      | False
11  2^(11/12)  11/6    False      False      False      | False
12  1          1       True       False      True       | True

The rational approximation lies within 1/17 of the interval because that is the largest threshold that distinguishes between all 12 equal tempered intervals. We match rational numbers with the pattern Rational[a_,b_] (or just a_~_~b_) first, and then match integers with only _.
This culminates in the following rather short function that determines if an arbitrary frequency ratio (greater than 1) is consonant or dissonant.
Rationalize[#,1/17]/.{a_~_~b_:>b<=5&&!a∣7,_->True}&       [Fsharp3/C3]     51+9=60

Gosh, don't tell me Mathematica has a builtin even for this... :D

Charcoal, 30 bytes
≔B#A#G#FE#D#Cζ§”o∧⌈ς”⁻⌕ζ⮌θ⌕ζ⮌η

Try it online! Link is to verbose version of code. Outputs 1 for consonant, 0 for dissonant. Explanation:
≔B#A#G#FE#D#Cζ                  Store reversed note names in z
                        θ       First input
                       ⮌        Reversed
                     ⌕ζ         Find index in z
                            η   Second input
                           ⮌    Reversed
                         ⌕ζ     Find index in z
                     ⁻          Subtract
               ”o∧⌈ς”           Compressed string 100111011100
              §                 Circularly index
                                Implicitly print

out of curiosity, is there a mnemonic reason the glyph ⌕ζ is used for "find index"?

@Jonah ζ is the variable assigned to earlier.

Mathematica, 118 bytes
FreeQ[{1,2,6,10,11},Min@Mod[Differences[Min@Position["C|C#|D|D#|E|F|F#|G|G#|A|A#|B"~StringSplit~"|",#]&/@{#,#2}],12]]&

Input form

["A#","D"]

Outputs
True->Consonant
False->Dissonant

thanks @JonathanFrech -16 bytes

Just a remark: you don't need to output strings Consonant and Dissonant. You may output any two values instead of them (0/1,... whatever). That could save some bytes.

Can you not omit the If[...,0,1] and define True->Consonant; False->Dissonant?

yes of course my friend

{"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"} (54 bytes) is equivalent to "C|C#|D|D#|E|F|F#|G|G#|A|A#|B"~StringSplit~"|" (46 bytes).

StringCases["CC#DD#EFF#GG#AA#B",_~~"#"...] – 42 Bytes

Also, 2 bytes can be saved by replacing {1,2,6,10,11} with 1|2|6|10|11

Slightly surprised Mathematica doesn't have a built-in for this.

@Skyler See the answer below.

J, 68 bytes
[:e.&1 2 6 10 11[:(12| -~/)(<;._1',C,C#,D,D#,E,F,F#,G,G#,A,A#,B')i.]

explanation
A straightforward, not super golfed implementation in J:

Input is given as boxed itemized notes (produced using cut), in order.
Find their indexes in the range of notes: (<;._1',C,C#,D,D#,E,F,F#,G,G#,A,A#,B')i.]
Subtract the first from the second: -~/
Take the remainder when divided by 12: 12|
Check if it's one of the dissonant notes: e.&1 2 6 10 11

Try it online!

///, 90 88 bytes
/^/"\///^\/\///C^D/##"E/DD"F/E#"G/FD"A/GD"B/AD"#,#/,"B#^B/#"A#/#"A^G#^G^F#/#"F^E^D#^D/#/

Try it online! (all test cases at once)

Put the input after the code.
Separate the note names with ,B# in each test case.
The output is , for consonant, ,# for dissonant.
Support for double-alterations (##) or E# in some particular cases. Otherwise the output is , for consonant, #, for dissonant (thanks to modulo 12 symmetry)
Can handle multiple test cases at once (if separated reasonably)
Lowercase characters are printed exactly.

C (gcc), 91 bytes
g(char*s){return (s[1]&1|2**s&15)*4/5;}f(char*x,char*y){return (1952220<<g(x)>>g(y))&2048;}

call: f("A#", "D")
Return value:

Consonant: 2048
Dissonant: 0

Bonus: The function is case insensitive.
Try it online!

Are there not two unnecessary spaces in both return (s?

You may try g(char*s){s=(s[1]&1|2**s&15)*4/5;}f(char*x,char*y){x=1952220<<g(x)>>g(y)&2048;} and nice solution!

C (gcc), 115 117 120 bytes
g(char*a){a=*a-65+!!a[1]*(7-*a/70-*a/67);}f(x,y)char*x,*y;{x="(pP$HL<lt<X"[g(x)]*32+"=ZukW-^h1F6"[g(x)]>>g(y)&1;}

Try it online!
Return 1/0 for consonat and dissonat. It is always interesting to do string manipulation with pure C. Take input as f("A#", "C")

Python 2, 125 117 83 78 77 bytes
a,b=map("C C#D D#E F F#G G#A A#B".index,input())
print chr(abs(a-b))in""

Where the "" at the end actually contains the characters "\x02\x04\x0c\x14\x16"
Try it Online!
(+3 because I forgot 11 or 22 in the list to begin with)
-8 bytes from Jonathan Frech and switching to Python 2.
-34 bytes with suggestions from Jonathan Frech and using str's index instead of list's.
-4 bytes from inlining i and Neil's reversing the string suggestion (only -2 really, as i forgot () around a generator)
-5 bytes from un-inlining i & changing the input format
-1 bytes from Jonathan Frech with map() and unprintables.
Takes input in one line of stdin in the format:
'C','C#'

True is dissonant, False is consonant.
Old Explanation:
i='C C#D D#E F F#G G#A A#B'.index
a,b=input()
print abs(i(a)-i(b))in[2,4,12,20]

Python str.index returns the lowest (positive) starting index of a matching substring, so
"ABACABA".index("A") == 0 and "ABACABA".index("BA") == 1. Because of this, we can put the note names evenly spaced in a string, and as long as (for example) A comes before A#, the shared A won't be a problem.
i='C C#D D#E F F#G G#A A#B'.index

i is now a function that returns the index in 'C C#D D#E F F#G G#A A#B' its argument (a note name) is, which is 2 * (the number of semitones that note is up from C)
a,b=input()

Python 2's input() is (mostly) equivalent to eval(input()) in Python3, so with a valid input of the format 'C#','F' (for example), a='C#' and b='F'
print abs(i(a)-i(b))in[2,4,12,20]

If the disttance between the first note and the second note in the string is not 2, 4, 12, or 20 (since the note names are represented in 2 characters), then the interval is dissonant, print True, else it is consonant, print False.

Since the input format is not strict, you can use eval(input()) (13 bytes) instead of input().split() (15 bytes).

101 bytes

98 bytes

79 bytes

Also 79 bytes

76 bytes

@JonathanFrech Thanks again! (Sorry for misspelling your name, also.)

As is, your code will not run. You would have to add two bytes, either [] or () to build a valid list comprehension or generator expression. Also, please credit @Neil for reversing the string.

May I ask you what is wrong with my 76 byte suggestion?

Also, those are 153 bytes; 75 of which are unnecessary spaces.

@JonathanFrech My apologies about that. My original post didn't have 11 (or 22 for the 2-widths) in it, so it failed for 'C','B'. I've updated the post with your solution (with \x11 added).

chr(abs(a-b))+64in"BDLTV"

@orlp Your solution, however, takes more bytes. Python 2 allows for these non-printable characters to exist in strings, though it may be impossible to represent them in an answer. (They appear as empty strings: ``)

@orlp Also, I think you meant chr(abs(a-b)+64)in"BDLTV".

You could use Unicode characters () instead of an emtpy string.

@JonathanFrech "" added

@JonathanFrech I did mean that. And at the time I wrote that comment it was shorter than what was in the answer. I don't really like unicode/unprintable character abuse in Python.

PowerShell, 107 bytes
param($a,$b)[math]::abs(($x=-split'C C# D D# E F F# G G# A A# B').indexof($b)-$x.indexof($a))-in1,2,6,10,11

Try it online!
Outputs True for dissonant and False for consonant.
Takes input $a and $b, the two notes, as strings. Performs a -split operation on the scale, which splits on whitespace, to create an array of the notes, stores that into $x. Finds the .indexof $b in that array, subtracts the index of $a, and then takes the absolute value thereof. Checks whether that number is -in the dissonant ranges.

Python 2, 68 bytes
lambda a,b,f='C C#D D#E F F#G G#A A#B'.find:3142>>(f(a)-f(b))/2%12&1

Try it online!
Outputs: 1 is dissonant, 0 is consonant.

SQL, 582 bytes
SQL Fiddle
I still have some golfing to do on it, but I wanted to get it down here before I end up breaking it completely.
If the input is in a letter format, then putting those letters in a table with values is okay, right?
CREATE TABLE N(N char(2),v int)
Insert Into N values('A',1),('A#',2),('B',3),('C',4),('C#',5),('D',6),('D#',7),('E',8),('F',9),('F#',10),('G',11),('G#',12);
CREATE TABLE D(D char(9),v int)
Insert Into D values('C',0),('D',1),('D',2),('C',3),('C',4),('C',5),('D',6);
CREATE FUNCTION I(@A char(2),@B char(2))
RETURNS char(9) as
BEGIN
DECLARE @E int=(SELECT v from N where n=@A),@F int=(SELECT v from N where n=@B)
DECLARE @C char(9) = (SELECT case D when 'D' then 'Dissonant' when 'C' then 'Consonant' END from D where v in(abs(@e-@f),12-abs(@e-@f)))
RETURN isnull(@C,'NotANote')
END

Perl 5, 106 bytes
("C,C#,D,D#,E,F,F#,G,G#,A,A#,B,"x2)=~/$F[0],(.*?)$F[1],/;$r=(1+($1=~y/,//))%12;say(grep/$r/,(0,3..5,7..9))

Try it online!
Returns false for dissonant, true for consonant.


text:
Score a Game of Boggle
Background
In Boggle, a round is scored by adding up the points for each unique word a player has found (i.e. any word that more than one player has found is worth 0 points). The points are calculated based on the number of letters in each word, as follows:
3 letters: 1 point
4 letters: 1 point
5 letters: 2 points
6 letters: 3 points
7 letters: 5 points
8 or more letters: 11 points
Challenge
In this challenge, write a program or function that takes in a list of lists of strings representing each player's words and outputs a list of the players' scores. You can assume that there will be at least 2 players and all words will be 3 or more letters and will all be lowercase (or all uppercase if you would prefer). You may also assume that each player will only use each word once; that is, no player's list will contain duplicates. This is code golf, so shortest answer in bytes wins.
Rules
Input can be taken in any reasonable format. Examples include a list of lists of strings, a list of comma-separated strings, a comma separated string on each line of input, etc. Output can be in the form of a list of integers (or your language's equivalent) or you can print the values to stdout using a separator of your choice (such as a newline).
Test Cases
Input => Output
[["cat","dog","bird","elephant"],
 ["bird","dog","coyote"],
 ["dog","mouse"]]                 => [12,3,2]

[["abc","def","ghi"],
 ["ghi","def","abc"]]             => [0,0]

[["programming","puzzles"],
 ["code","golf"],
 []]                              => [16,2,0]

The longest (theoretically) possible word in Boggle is 16 letters; do we need to be able to handle words longer than this?

Husk, 21 20 19 bytes
-2 bytes thanks to Zgarb
Idea taken from A055228
ṠṀöṁ(⌈√Π-3▼8L)fε`#Σ

Try it online!
Explanation (Of older version)
            ṠṀ-oṠ-uΣ   Remove duplicated words
                   Σ   Concatenate
                  u    Remove duplicates
               oṠ-     Remove those unique elements from the list (give list of elements that appear more than once)
            ṠṀ-        Remove those words from each list in the input
m                      For each list
 ṁ(                    Map then sum
          L)           Length
        ▼8             Min(8,x)
      -3               Minus 3
     Π                 Factorial
    √                  Square root
   ⌈                   Ceiling

20 bytes

Nice, I won't rearrange though, to save on the explanation.

19 bytes using f instead of -

Thanks, I couldn't quite get that method to work myself.

Gah! Thought I'd managed to tie you, hadn't noticed you're down to 19 now.

R, 142 126 121 117 bytes
function(L)sapply(lapply(L,setdiff,(l=unlist(L))[duplicated(l)]),function(x)sum(c(1,1,2,3,5,11)[pmin(6,nchar(x)-2)]))

Try it online!
Takes L as a list of vectors of strings; returns the values.
First, it unlists the words, finds the duplicates, then removes them from the players' word lists. Then it takes these unique word lists and computes the scores of each, using pmin to ensure that words longer than 8 get scored as 11.

You can shorten it to 108 bytes if you only take away the duplicates in the sapply inner function: function(L)sapply(L,function(x)sum(c(1,1,2,3,5,11)[pmin(6,nchar(x[!x%in%(l=unlist(L))[duplicated(l)]])-2)]))

JavaScript (ES6), 106 93 bytes
[Saved 13(!) bytes, thanks to Arnauld, Shaggy, and JollyJoker.]
a=>a.map(b=>b.map(c=>x+=(a+'').split`,`.filter(d=>d==c)[1]?0:+'11235'[c.length-3]||11,x=0)|x)

Test cases:

let f=

a=>a.map(b=>b.map(c=>x+=(a+'').split`,`.filter(d=>d==c)[1]?0:+'11235'[c.length-3]||11,x=0)|x)

console.log(f([["cat","dog","bird","elephant"],
               ["bird","dog","coyote"],
               ["dog","mouse"]
              ])
           )  // [12,3,2]

console.log(f([["abc","def","ghi"],
               ["ghi","def","abc"]
              ])
           ) // [0,0]

console.log(f([["programming","puzzles"],
               ["code","golf"],
               []
              ])
            ) // [16,2,0]

I think you can replace c[7]?11:c[6]?5:c[5]?3:c[4]?2:1 with '00011234'[c.length]||11.

That gives [15,2,0] instead of [16,2,0] for the last test case, but that's probably easily fixed.  Will work some more after dinner, unless you post a genius answer (as you usually do).  Thanks!  : )

Ah yes, sorry, that should be '00011235'.

I think you can save another few bytes on top of @Arnauld's suggestion like so.

There are at least 3 letters, '11235'[c.length-3]||11, right?

Nevermind, just realized  Justin Mariner did exactly that.

JavaScript (ES6), 92 bytes
a=>a.map(b=>b.reduce((s,v)=>s+(a.filter(b=>b.includes(v))[1]?0:+"11235"[v.length-3]||11),0))

Somewhat similar to Rick Hitchcock's answer but created mostly independently; I used a different method of summing (reduce) and different method for checking for repeated terms (filter + includes). Credit to him for the idea of checking for item [1] instead of checking .length>1, though.
Test Cases

let f=
a=>a.map(b=>b.reduce((s,v)=>s+(a.filter(b=>b.includes(v))[1]?0:+"11235"[v.length-3]||11),0))

;[[["cat","dog","bird","elephant"],["bird","dog","coyote"],["dog","mouse"]],[["abc","def","ghi"],["ghi","def","abc"]],[["programming","puzzles"],["code","golf"],[]]]
.forEach(test=>O.innerHTML+=JSON.stringify(test)+" -> "+JSON.stringify(f(test))+"\n")

You should be able to save a byte by using s+= and removing the parentheses around the ternaries. And 3 more by using map instead of reduce: https://tio.run/##NY/NjoMgEIDv@xicJLWkbLOXTXAfhCXpiIg0yBhBk218dxc0vczPN99MMk9YIerZTekasDN7L3YQDbARpqoVTXsUq2jiRQDrnU9mPrkL2i@didVKqeTq5/Z9IZx/3r@IXJk3wabhelfbxnkdxY1uke4aQ0RvmEdbSSmJhkRq0qHNsXVzl5PxZhogJKJq@WanoPEPkzn4CUZcYu4zkARaXUTT52gHd1glv1mZn@Y0o51hHF0oN6bl9fImHr7O75d19H3plVIfx/M9ZU904fEbHnT/Bw

Well done.  Your use of reduce and includes makes your answer quite different from mine.

Pyth, 26 bytes
Uses H.PWiz's formula.
m+Fm.E@.!a3hS,8lk2fq1/sQTd

Verify all the test cases.
The initial version, 33 bytes:
m+Fm*h+++*6>lk7y>lk6>lk5glk3q1/sQ

Verify all the test cases.
Explanation

m+Fm*h+++*6>lk7y>lk6>lk5>glk3q1/sQ   Full program.

m                                    Map over the input.
   m                                 Map over each sublist.
                        >lk3         Is the length higher than 2? 1 if True and 0 if False.
      +             >lk5             Plus "is length higher than 5?".
       +       y>lk6                 Plus "is length higher than 6?", doubled.
        +*6>lk7                      Plus "is length higher than 7?", times 6.
     h                               Increment.
                            q1/sQ    Count the occurrences of the element in the flattened
                                     input, and check if it equals 1. 0 if False, 1 if True.
    *                                Multiplication.
 +F                                  Sum each sublist.

Python 2, 106 105 88 84 bytes
-1 byte thanks to Jonathan Frech
-1 (17) bytes thanks to reffu

lambda x:[sum(sum([1,0,1,1,2,6][:len(s)-2])*(`x`.count(`s`)<2)for s in l)for l in x]

Try it online!

105 bytes.

104 bytes

@reffu thanks, I've made some modifications to golf even further :3

@Rod Nice, I forgot about the second parameter of sum trick.

Perl 6, 64 bytes
{@^a.map:{sum .map:{@a.Bag{$_}>1??0!!(1,1,2,3,5)[.comb-3]||11}}}

Try it online!

Japt, 29 25 24 23 21 20 bytes
Ëx@èøX ¥1©3nXÊm8)Ê¬c

Try it

Saved 4 bytes by using the formula H.PWiz found for the scoring.

Explanation
Implicit input of array U.
Ëx@

Map over the array (Ë) and reduce each sub-array by addition (x) after passing its elements through the following function, where X is the current word.
èøX

Count (è) the elements in U that contain (ø) X.
¥1

Check if that is equal to 1.
©

Logical AND (&&).
3nXÊm8)

Subtract (n) 3 from the minimum of (m) 8 and the length (Ê) of X.
Ê¬c

Factorial, square root and round up, respectively.

Haskell, 76 75 bytes
f l=[sum[fst.last$zip[0,0,1,1,2,3,5,11]w|w<-p,[w]==(filter(==w)=<<l)]|p<-l]

Try it online!

Jelly, 26 bytes
ðċ@Ị¥ÐfL€«8ị“¡[żÇ’ḃ11¤Sµ€Ẏ

Try it online!

Java 10, 202 200 198 197 194 bytes
a->{int q=a.length,r[]=new int[q],i=0,j,f;for(;i<q;i++)for(var s:a[i]){for(f=j=0;j<q;)f|=a[j].contains(s)&!a[i].equals(a[j++])?1:0;r[i]+=f<1?(j=s.length())<5?1:j<6?2:j<7?3:j<8?5:11:0;}return r;}

-1 byte thanks to @ceilingcat.
Explanation:
Try it here.
a->{                       // Method with ArrayList<String>[] parameter & int[] return-type
  int q=a.length,          //  Length of the input-array
      r[]=new int[q],      //  Result integer-array the size of the input-array,
                           //  initially filled with 0s by default
      i=0,j,               //  Index integers
      f;                   //  Flag integer (used as boolean)
  for(;i<q;i++)            //  Loop `i` in the range [0, `q`):
    for(var s:a[i]){       //   Inner loop over the Strings of the `i`'th List
      for(f=j=0;           //    Reset the flag `f` and index `j` both to 0
          j<q;)            //    Inner loop `j` in the range [0, `q`) again:
        f|=a[j].contains(s)//     If the `j`'th list contains the current String
           &!a[i].equals(a[j++])?
                           //     and the `i`'th and `j`'th list aren't the same:
            1              //      Bitwise-OR the flag with 1 (0->1; 1->1)
           :               //     Else:
            0;             //      Bitwise-OR the flag with 0 (0->0; 1->1)
                           //    End of inner loop (3) (implicit / single-line body)
      r[i]+=               //    Increase the `i`'th item in the result integer-array by:
            f<1?           //     If the flag is still 0 (so the current String is unique):
             (j=s.length())<5?
                           //      If the length of the String is below 5:
              1            //       Increase by 1
             :j<6?         //      Else-if the length is 5 instead:
              2            //       Increase by 2
             :j<7?         //      Else-if the length is 6 instead:
              3            //       Increase by 3
             :j<8?         //      Else-if the length is 7 instead:
              5            //       Increase by 5
             :             //      Else (the length is above 7):
              11           //       Increase by 11
            :              //     Else (the flag is 1 - thus the String is not unique):
             0;            //      Leave it the same by increasing with 0
  return r;}               //  Return the resulting integer-array

I love ternaries, and the only thing I hate about ScaLa is that they removed this ternary syntax.

@V.Courtois Hmm, out of curiosity, how is the ternary syntax in Scala now?

uh : if(bool1)exp1 else exp2

R, 117 bytes
A completely different approach from the other R answer:
function(L)sapply(L,function(x)sum(c(0:3,5,11)[cut(nchar(x[x%in%names(which(table(unlist(L))<2))]),c(0,2,4:7,Inf))]))

Test cases:
> f=function(L)sapply(L,function(x)sum(c(0:3,5,11)[cut(nchar(x[x%in%names(which(table(unlist(L))<2))]),c(0,2,4:7,Inf))]))
> L=list(c("cat","dog","bird","elephant"),c("bird","dog","coyote"),c("dog","mouse"))
> f(L)
[1] 12  3  2
> L=list(c("abc","def","ghi"),c("ghi","def","abc"))
> f(L)
[1] 0 0
> L=list(c("programming","puzzles"),c("code","golf"),c())
> f(L)
[1] 16  2  0

Takes the names occurring only once in the list, convert their length to a factor based on the given cut-off points and translates that into scores that is then summed.

114 bytes by combining our two approaches in the deduplication step.

K (ngn/k), 34 bytes
{+/'(&7\5782020)'#''x^\:&1<#'=,/x}

Try it online!

&1<#'=,/x get non-unique words (i.e. words that more than one player identified)
x^\: remove the non-unique words from each player's submission
#'' get the number of characters in each players' words
(&7\5782020) a compressed version of 0 3 5 6 7 7 8 8 8 8 8 8
(...)' do a binary search, returning the index of the first value in the left-side list not larger than each item in the right-side list (this translates word lengths to their scores)
+/' get each player's point total (by summing the score of their individual words)

Perl 5, 104 + 2 (-na) = 106 bytes
push@a,[@F];map$k{$_}++,@F}{map{$s=0;map$s+=(($l=y///c)<8?$l<7?$l<5?1:$l-3:5:11)*($k{$_}<2),@$_;say$s}@a

Try it online!

Clojure, 102 bytes
#(for[p %](apply +(for[w p](if(next(filter #{w}(flatten %)))0(get{3 1 4 1 5 2 6 3 7 5}(count w)11)))))

next returns nil if there is only one word w :)

PHP, 226 bytes
function x($a){foreach($a as$p){$q=call_user_func_array('array_diff',$a);array_push($a,array_shift($a));$x=0;array_map(function($b)use(&$x){$b=strlen($b);$x+=($b<5?1:($b==5?2:($b==6?3:($b==7?5:11))));},$q);$o[]=$x;}return $o;}

I think this could still be trimmed down quite a bit.
Ungolfed:
function x($a) {
    foreach ($a as $p) {
        $q = call_user_func_array('array_diff', $a);
        array_push($a, array_shift($a));
        $x = 0;
        array_map(function($b) use (&$x){
            $b = strlen($b);
            $x += ($b < 5 ? 1 : ($b == 5 ? 2 : ($b == 6 ? 3 : ($b == 7 ? 5 : 11))));
        }, $q);
        $o[] = $x;
    }
    return $o;
}

Try it online!

Scala, 242 bytes
The function takes, as a parameter a, a Seq[Set[String]] and returns an    Array[Int]. I use an Array for it to be mutable (4-char loss).
var s=Seq("")
a.foreach(x=>x.foreach(y=>s:+=y))
var u:Array[Int]=Array()
var i= -1
a.foreach(t=>{i+=1
u:+=0
t.map(x=>{val l=x.length
if(s.count(_==x)<2){if(l>7)u(i)+=11
if(l==7)u(i)+=5
if(l==6)u(i)+=3
if(l==5)u(i)+=2
if(l>2&l<5)u(i)+=1}})})
u

Try it online!
Might be optimizable, since I did not even work on the
if(l>7)u(i)+=11
if(l==7)u(i)+=5
if(l==6)u(i)+=3
if(l==5)u(i)+=2
if(l>2&l<5)u(i)+=1

part. Thanks for this challenge!

Swift 4, 164 bytes*
{$0.map{Set($0).subtracting(Dictionary(grouping:$0.flatMap{$0},by:{$0}).flatMap{$1.count != 1 ?$0:nil}).map{[0,1,1,2,3,5,11][min(max($0.count-2,0),6)]}.reduce(0,+)}}

The above expression is technically correct, pure Swift. However, the expression is so complex that, due to exponential blowup in the type inference system, can't be processed before the compiler gives up after some arbitrary timeout (like 15s or something).
To make this expression compilable with the current compiler, it can be broken down like this:
{
let n = Dictionary(grouping:$0.flatMap{$0},by:{$0}).flatMap{$1.count != 1 ?$0:nil}
return $0.map{Set($0).subtracting(n).map{[0,1,1,2,3,5,11][min(max($0.count-2,0),6)]}.reduce(0,+)}
}

Test cases:
let f: (_ input: [[String]]) -> [Int] = {
    let n = Dictionary(grouping:$0.flatMap{$0},by:{$0}).flatMap{$1.count != 1 ?$0:nil}
    return $0.map{Set($0).subtracting(n).map{[0,1,1,2,3,5,11][min(max($0.count-2,0),6)]}.reduce(0,+)}
}

let testcases: [(input: [[String]], expected: [Int])] = [
    (input: [
            ["cat","dog","bird","elephant"],
            ["bird","dog","coyote"],
            ["dog","mouse"]
        ],
        expected: [12,3,2]
    ),
    (input: [
            ["abc","def","ghi"],
            ["ghi","def","abc"]
        ],
        expected: [0,0]
    ),
    (input: [
            ["programming","puzzles"],
            ["code","golf"],
            []
        ],
        expected: [16,2,0]
    ),
]

for (caseNumber, testcase) in testcases.enumerated() {
    let actual = f(testcase.input)
    assert(actual == testcase.expected,
        "Testcase #\(caseNumber) \(testcase.input) failed. Got \(actual), but expected \(testcase.expected)!")
    print("Testcase #\(caseNumber) passed!")
}

Broken down:
let verboseF: (_ input: [[String]]) -> [Int] = { playerHands in
    let allWords = playerHands.flatMap{$0}
    // demo data for first test case:
    // allWords: ["cat", "dog", "bird", "elephant", "bird", "dog", "coyote" "dog", "mouse"]

    let allWordsGroupedByThemselves = Dictionary(grouping: allWords, by: {$0})
    /* allWordsGroupedByThemselves:
    [
        "cat": ["cat"],
        "dog": ["dog", "dog", "dog"],
        "bird": ["bird", "bird"],
        "elephant": ["elephant"],
        "coyote": ["coyote"], "mouse": ["mouse"]
    ]*/

    let allWordsUsedMoreThanOnce = allWordsGroupedByThemselves.flatMap{$1.count != 1 ?$0:nil}
    // allWordsUsedMoreThanOnce: ["dog", "bird"]

    return playerHands.map{ hand in
        // demo data for first hand of first test case:
        // hand: ["cat","dog","bird","elephant"]

        let uniqueWordsInHand = Set(hand)
        // uniqueWordsInHand: ["cat","dog","bird","elephant"]

        let uniqueWordsInHandNotUsedByOthers = uniqueWordsInHand.subtracting(allWordsUsedMoreThanOnce)
        // uniqueWordsInHandNotUsedByOthers: ["cat", "elephant"]

        let wordLengths = uniqueWordsInHandNotUsedByOthers.map{$0.count}
        // wordLengths: [3, 8]

        let scores = wordLengths.map{ wordLength in
            return [0,1,1,2,3,5,11][min(max(wordLength-2, 0), 6)] //A look up table that maps word length to word score
        }
        //scores: [1, 11]

        let playerScore = scores.reduce(0,+)
        // playerScore: 12

        return playerScore
    }
}

ASP + Python, 137 bytes
u(P,W):-1{p(_,W)}1;p(P,W).s(P,S):-S=#sum{@v(W):u(P,W)};p(P,_).#script(python)
def v(w):return[1,1,2,3,5,11][min(len(w.string),8)-3]#end.

Expects data formatted as:
p(1,("cat";"dog";"bird";"elephant")).
p(2,("bird";"dog";"coyote")).
p(3,("dog";"mouse")).

Needs clingo 5.2.1 with python support.
Ungolfed:
unique(P,W):- 1 { player(_,W) } 1 ; player(P,W).
score(P,S):- S = #sum{@value(W): unique(P,W)} ; player(P,_).
#script (python)
def value(word):
    return [1,1,2,3,5,11][min(len(word.string),8)-3]
#end.

The python function is heavily inspired from the python answer.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
Visualize Nicomachus's Theorem
Nichomachus's Theorem relates the square of a sum to the sum of cubes:

and has a beautiful geometric visualization:

Challenge: Create the 2d part of this visualization in ascii.
You will need to ensure that all visual demarcations are upheld by your diagram.  This is simplest to do with four "colors," though it's possible to achieve with only three (see last example below for how).  With four colors, you use two to distinguish between regions within a "strip" (ie, the different parts that make up a single cube), and two to distinguish between adjacent strips.  You may also use more than four colors if you like.  If any of this is confusing, the example output below should clarify.
Input / Output
Input is a single integer greater than 0.  Output is an ascii grid similar to the examples below, corresponding to the flattened grid for that input number in the image above.  Leading and trailing whitespace are ok.
This is code golf, with standard rules.
Sample outputs
N = 1
#

N = 2
#oo
o@@
o@@

N = 3
#oo+++
o@@+++
o@@+++
+++###
+++###
+++###

N = 4
#oo+++oooo
o@@+++oooo
o@@+++@@@@
+++###@@@@
+++###@@@@
+++###@@@@
oo@@@@oooo
oo@@@@oooo
oo@@@@oooo
oo@@@@oooo

N = 5
#oo+++oooo+++++
o@@+++oooo+++++
o@@+++@@@@+++++
+++###@@@@+++++
+++###@@@@+++++
+++###@@@@#####
oo@@@@oooo#####
oo@@@@oooo#####
oo@@@@oooo#####
oo@@@@oooo#####
+++++#####+++++
+++++#####+++++
+++++#####+++++
+++++#####+++++
+++++#####+++++

Three color version for N = 4, thanks to @BruceForte:
#oo+++oooo
o##+++oooo
o##+++####
+++ooo####
+++ooo####
+++ooo####
oo####++++
oo####++++
oo####++++
oo####++++

Four-colour theorem :D

Can you add the output for N=5 please?

@Uriel Done. See my edit.

Thanks! Also, can I switch the @ and o s only in the outer strip in N=4? Or must the output be a strict substitution of these texts with another charset?

@Uriel switching is fine.  All that matters is that adjacent colors don't conflict, so that the pattern is visible.

Suerly you meant a maximum of four "colors.", not minimum?

@BruceForte I don't think you can do it with less than four colors and still preserve all the visual demarcations.

You can, for N = 1 and N = 2 you did yourself ;) Here's a non-trivial case that checks out with 3 colors. (Nice question btw!)

@BruceForte So there is!  Nice catch.  i've edited the question.

Can the image be rotated? (i.e can the 1 be at the right and/or the bottom?)

@LevelRiverSt yeah that’s fine

MATL, 30 28 27 bytes
t:P"@:s:@/Xk&+@+8MPt&(]30+c

Try it online!
Bonus features:

For 26 bytes, the following modified version produces graphical output:
 t:P"@:s:@/Xk&+@+8MPt&(]1YG

Try it at MATL Online!

The image is begging for some colour, and it only costs 7 bytes:
 t:P"@:s:@/Xk&+@+8MPt&(]1YG59Y02ZG

Try it at MATL Online!

Or use a longer version (37 bytes) to see how the character matrix is gradually built:
 t:P"@:s:@/Xk&+@+8MPt&(t30+cD9&Xx]30+c

Try it at MATL Online!
Example outputs
For input is 8, the following shows the basic version, graphical output, and colour graphical output.

Explanation
General procedure
A numeric matrix is built from outer to inner layers in N steps, where N is the input. Each step overwrittes an inner (upper-left) part of the previous matrix. At the end, the numbers in the obtained matrix are changed to characters.
Example
For input 4 the first matrix is
10 10  9  9  9  9  8  8  8  8
10 10  9  9  9  9  8  8  8  8
 9  9  8  8  8  8  7  7  7  7
 9  9  8  8  8  8  7  7  7  7
 9  9  8  8  8  8  7  7  7  7
 9  9  8  8  8  8  7  7  7  7
 8  8  7  7  7  7  6  6  6  6
 8  8  7  7  7  7  6  6  6  6
 8  8  7  7  7  7  6  6  6  6
 8  8  7  7  7  7  6  6  6  6

As a second step, the matrix
7 7 7 6 6 6
7 7 7 6 6 6
7 7 7 6 6 6
6 6 6 5 5 5
6 6 6 5 5 5
6 6 6 5 5 5

is overwritten into the upper half of the latter. Then the same is done with
6 5 5
5 4 4
5 4 4

and finally with
3

The resulting matrix is
3 5 5 6 6 6 8 8 8 8
5 4 4 6 6 6 8 8 8 8
5 4 4 6 6 6 7 7 7 7
6 6 6 5 5 5 7 7 7 7
6 6 6 5 5 5 7 7 7 7
6 6 6 5 5 5 7 7 7 7
8 8 7 7 7 7 6 6 6 6
8 8 7 7 7 7 6 6 6 6
8 8 7 7 7 7 6 6 6 6
8 8 7 7 7 7 6 6 6 6

Lastly, 30 is added to each entry and the resulting numbers are interpreted as codepoints and converted to characters (thus starting at 33, corresponding to !).
Construction of the intermediate matrices
For input N, consider decreasing values of k from N to 1. For each k, a vector of integers from 1 to k*(k+1) is generated, and then each entry is divided by k and rounded up. As an example, for k=4 this gives (all blocks have size k except the last):
1 1 1 1 2 2 2 2 3 3

whereas for k=3 the result would be (all blocks have size k):
1 1 1 2 2 2

This vector is added, element-wise with broadcast, to a transposed copy of itself; and then k is added to each entry. For k=4 this gives
6  6  6  6  7  7  7  7  8  8
6  6  6  6  7  7  7  7  8  8
6  6  6  6  7  7  7  7  8  8
6  6  6  6  7  7  7  7  8  8
7  7  7  7  8  8  8  8  9  9
7  7  7  7  8  8  8  8  9  9
7  7  7  7  8  8  8  8  9  9
7  7  7  7  8  8  8  8  9  9
8  8  8  8  9  9  9  9 10 10
8  8  8  8  9  9  9  9 10 10

This is one of the intermediate matrices shown above, except that it is flipped horizontally and vertically. So all that remains is to flip this matrix and write it into the upper-left corner of the "accumulated" matrix so far, initiallized to an empty matrix for the first (k=N) step.
Code
t       % Implicitly input N. Duplicate. The first copy of N serves as the
        % initial state of the "accumulated" matrix (size 1×1). This will be
        % extended to size N*(N+1)/2 × N*(N+1)/2 in the first iteration
 :P     % Range and flip: generates vector [N, N-1, ..., 1]
"       % For each k in that vector
  @:    %   Push vector [1, 2, ..., k]
  s     %   Sum of this vector. This gives 1+2+···+k = k*(k+1)/2
  :     %   Range: gives vector [1, 2, ..., k*(k+1)/2]
  @/    %   Divide each entry by k
  Xk    %   Round up
  &+    %   Add vector to itself transposed, element-wise with broadcast. Gives
        %   a square matrix of size k*(k+1)/2 × k*(k+1)/2
  @+    %   Add k to each entry of the this matrix. This is the flipped
        %   intermediate matrix
  8M    %   Push vector [1, 2, ..., k*(k+1)/2] again
  Pt    %   Flip and duplicate. The two resulting, equal vectors are the row and
        %   column indices where the generated matrix will be written. Note that
        %   flipping the indices has the same effect as flipping the matrix
        %   horizontally and vertically (but it's shorter)
  &(    %   Write the (flipped) intermediate matrix into the upper-left
        %   corner of the accumulated matrix, as given by the two (flipped)
        %   index vectors
]       % End
30+     % Add 30 to each entry of the final accumulated matrix
c       % Convert to char. Implicitly display

I don't know MATL at all, but could you save any bytes by taking mod10 rather than adding 30 and converting to character?

Or even mod4...

@user2390246  Do you mean to keep them as numbers with a single digit and avoid converting to char? That wouldn't work, because the numeric matrix would be printed with spaces between the numbers. But thanks for the idea anyway :-)

Fair enough. What happens with n > 226? Won't that go outside the range of valid characters? (Unsurprisingly, times out on TIO, so I couldn't check)

@user2390246 Yes, for high input numbers it goes outside. And if we consider ASCII chars the maximum code point is 127, so it goes outside even sooner. But as you noticed it runs out of memory before that happens (the resulting char matrix is too large). Anyway, working up to a given input size only due to memory or data type limitations is usually allowed

Python 2, 187 178 164 162 152 bytes
-8 bytes thanks to Mr.Xcoder
-1 byte thanks to Stephen
-10 bytes thanks to Jonathan Frech

g=lambda y:y>1and[l+y*f(y,i)for i,l in enumerate(g(y-1))]+y*[''.join(f(y,i)for i in range(y*-~y/2))]or['#']
f=lambda y,i:'0@+#'[(y*~-y/2%y+i)/y%2+y%2*2]

Try it online!

For when you get home, 179 bytes.

@Mr.Xcoder 178 bytes

Is it allowed to not include your lambda function's name byte count when you are using it recursively, i.e. using its name in the rest of the code?

sum(range(y))%y -> y*~-y/2%y

@JonathanFrech yeah, when it's recursive it must be there.

Charcoal, 50 46 bytes
Ｆ⮌…·¹Ｎ«≔⊘×ι⊕ιθＦ⊕⊘ι«Ｆ§#+@⁺ικ«ＵＯ⁻θ×ικθλＵＯθ⁻θ×ικλ

Try it online! Link is to verbose version of code. Previous 50-byte version with explanation: Try it online!
Ｆ⮌…·¹Ｎ«≔÷×ι⁺¹ι²θＦ⁺¹÷ι²«Ｆ§#+@⁺ικ«ＵＯ⁻θ×ικθλＵＯθ⁻θ×ικλ

Ｆ     «     Loop over
  …·¹       Inclusive range from 1 to
     Ｎ      Input as a number
 ⮌          Reversed

   ι⁺¹        Add 1 to current index
  ×   ι       Multiply by current index
 ÷     ²      Divide by 2
≔       θ     Assign to q

Ｆ     «      Loop over
             Implicit range from 0 to
   ÷ι²       Half the current index
 ⁺¹          Plus 1

Ｆ       «    Loop over
  #+@        Literal string
 §           Circularly indexed by
     ⁺ικ     Sum of outer and inner index

    ×ικ     Multiply outer and inner index
  ⁻θ        Subtract from q
ＵＯ     θλ   Draw an oblong (q-ik, q) using that character

ＵＯθ⁻θ×ικλ   Draw an oblong (q, q-ik) using that character

Note: I loop over the character rather than trying to assign the character directly to l because you can't directly assign the result of indexing a string to a variable as it's an ambiguous construct in Charcoal. Fortunately the byte count is the same.

Technically you can, with an ASCII variable since its argument order is reversed (note that it needs an operator to access so it's still less golfy)

C (gcc), 135 128 120 bytes
f(n,m,i,x,y,k){for(m=n*-~n/2,i=m*m;i--;printf("\n%d"+!!(~i%m),(x/k+y/k+k)%3))for(x=i%m,y=i/m,k=n;x>=k&y>=k;x-=k--)y-=k;}

Try it online!
Uses only three colors.
Conceptually, works on a grid rotated by 180 degrees:
000111
000111
000111
111220
111220
111001

And computes colors according to the formula:
c(x,y,n) = c(x-n,y-n,n-1)                   if x >= n and y >= n
         = (x div n + y div n + n) mod 3    otherwise

123 bytes.

@JonathanFrech This isn't valid C and breaks with gcc -O2.

Fair enough; is it possible that the second code only works for three colors because of the modulus three (g(i%m,i/m,n)%3)?

Suggest x/k&&y/k instead of x>=k&y>=k

R, 131 126 123 bytes
3 bytes saved thanks to @Giuseppe
function(n){l=w=sum(1:n)
m=matrix(,l,l)
for(i in n:1){m[l:1,l:1]=outer(x<-(1:l-1)%/%i,x,`+`)+i
l=l-i}
write(m%%4,"",w,,"")}

Try it online!
This uses the same algorithm as @LuisMendo 's MATL answer. The only difference is that rather than converting to characters, the matrix is output with all of the values mod4 to ensure that each element is a single ascii character.

123 bytes! I brought the for loop back for -1 byte :)

Python 2, 176 175 bytes
n=input()
R,J=range,''.join;r=[]
for i in R(n+1):
 S=sum(R(i));c='AxBo'[i%2::2]
 for j in R(S):r[~j]+=c[j/i%2]*i
 r+=[J(c[-j/i%2]for j in R(S+i,0,-1))]*i
for l in r:print J(l)

Try it online!

If you define J="".join; (+10 bytes) and replace both "".joins (-2*7=-14 bytes) with J (+2 bytes), you can save a byte (as there has to be an additional space after the print; +1 byte).

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Simple complexity
Output

                  #         #  #    #  # #####  ##    #
                  ##        ####    #######  #   #    ##
                ####        ##      ##    #  ### #######
                #  #         #       #    ##### ### #  #
                #  # ### #####   #####    #         #  #
                ####### ###  #  ###  #    ##        ####
                ##    #   #  ###  #  #######        ##
                 #    ##  #####   ##### #  #         #
                ##    #                   #         #  # #####
                 #    ##                  ##        #######  #
                 #######                ####        ##    #  ###
                ### #  #                #  #         #    #####
                    #  #                #  # ### #####    #
                    ####                ####### ###  #    ##
                    ##                  ##    #   #  #######
                     #                   #    ##  ##### #  #
    #  # #####  ##    #                   #
    #######  #   #    ##                  ##
    ##    #  ### #######                ####
     #    ##### ### #  #                #  #
 #####    #         #  #                #  # ###
###  #    ##        ####                #######
  #  #######        ##                  ##    #
  ##### #  #         #                   #    ##
          #         #  # #####   #####  ##    #
          ##        #######  #  ###  #   #    ##
        ####        ##    #  ###  #  ### #######
        #  #         #    #####   ##### ### #  #
        #  # ### #####    #       #         #  #
        ####### ###  #    ##      ##        ####
        ##    #   #  #######    ####        ##
         #    ##  ##### #  #    #  #         #
                                          #
                                          ##
                                        ####
                                        #  #
                                        #  # ###
                                        #######
                                        ##    #
                                         #    ##
                                 #####  ##    #
                                ###  #   #    ##
                                  #  ### #######
                                  ##### ### #  #
                                  #         #  #
                                  ##        ####
                                ####        ##
                                #  #         #
                                  #         #  #    #  # #####
                                  ##        ####    #######  #
                                ####        ##      ##    #  ###
                                #  #         #       #    #####
                                #  # ### #####   #####    #
                                ####### ###  #  ###  #    ##
                                ##    #   #  ###  #  #######
                                 #    ##  #####   ##### #  #
                                ##    #                   #
                                 #    ##                  ##
                                 #######                ####
                                ### #  #                #  #
                                    #  #                #  # ###
                                    ####                #######
                                    ##                  ##    #
                                     #                   #    ##

Trailing spaces allowed. Shortest solution wins.
hint0
hint1:

thanks @Tahg for correcting hint1

Is this some sort of a Dragon curve?

How can we output this? ASCII only, graph-like like Stewie commented, etc?

@Riker I tagged ascii-art but you can graph it if you like, well, if it leads to shorter code...

@ngn output only challenges without any explanation to the way the data was formed are usually frowned upon (see https://codegolf.stackexchange.com/q/126037), because the first answer tends to blow off the "mysterious" part

@Uriel, what about requiring spoiler tags for such questions?  The mystery is appealing -- shame to throw it out altogether...

@Uriel That's what kolmogorov-complexity is about, isn't it? I agree, after it's cracked, there won't be much pleasure in solving the puzzle. All that remains will be basic golfing...

Personally I don't like challenges like this where finding out the rule / recipe is part of the task. Besides, once a person finds it, all others can just follow it, so why not post in the first place?

This challenge was well received. Perhaps because of all the extra stuff posted along with the string.

@LuisMendo It's an interesting argument.  Code golf in its purest form is about "implementing a known solution succinctly."  Puzzles in their purest form are about finding a solution -- the implementation is either not relevant or considered busy work.  One option would be to post the "trick" in spoilers.  That way the pure code golfers to attack the problem as a golfing challenge, and those who like both the golf and puzzle challenges could avoid looking and solve both.

I think the "mysterious" part is something that I could definitely see more of. Although one answer might find the trick to it, the rest of it is still a regular code-golf challenge... And it provides a good challenge for those who aim to find the pattern in the beginning anyways.

@H.PWiz, I'm not sure that +26/-7 is really "well received". It looks more like "poorly received but managed to hit the HNQ fast enough to get a skewed score".

Can we output an array containing strings of each line?

@Shaggy I'm afraid the output wouldn't look as desired then

SOGL V0.12, 17 16 14 bytes
 #6{³IIč▓┼;I+§

Try it Here!
At a later update č▓ could be removed for 12 bytes - that converts ToS from an array of arrays of characters a multiline string to an array of strings - [["#","#"],[" ","#"]] -> ["##"," #"] - , because ┼ - horizontal append - doesn't deal well with arrays of arrays of characters - which I creates, because it's used for array rotation too. In SOGL an array of arrays of characters should be = array of strings, but many things don't support that yet..
Explanation:
 #            push "#"
  6{          6 times do
    ³           create 3 total copies of ToS
     II         rotate clockwise twice
       č▓       normalize as explained above
         ┼      append horizontally
          ;     get the 3rd copy ontop
           I    rotate clockwise
            +   append vertically
             §  reverse horizontally

wait what how does this work

@ConorO'Brien just added an explanation :p

oh nice

JavaScript (ES6), 233 217 213 198 182 170 163 122 bytes

f=_=>[...Array(64)].map((_,x,a)=>a.map(g=(i=(n=64,x),j)=>(n>>=1)?i&n?j&n?g(j,i):` `:j&n?g(i,~j):g(~i,j):`#`).join``).join`
`
document.write(`<pre>${f()}</pre>`)

Edit: Saved 14 18 bytes thanks to @Shaggy. Saved 3 bytes thanks to @ngn. Saved a further 12 bytes thanks to the two working together. Saved 41 bytes by stealing @user202729's observations that the quarters use reflections rather than rotations. Ungolfed:
function f() {
    var s = '';
    for (var i = 0; i < 64; i++) {
        for (var j = 0; j < 64; j++) {
            var x = i, y = j, c = '#'; // Default to #
            // Each non-blank quadrant maps to to the original
            // image by doubling and a reflection. Repeat
            // this six times unless we hit the blank quadrant.
            for (var n = 0; n < 6; n++) {
                if (x >= 32) {
                    if (y >= 32) {
                        // Bottom right quarter is a diagonal reflection
                        var t = x - 32;
                        x = y - 32;
                        y = t;
                    } else {
                        // Bottom left quarter is blank
                        c = ' ';
                        break;
                    }
                } else {
                    if (y >= 32) {
                       // Top right corner is a horizontal reflection
                       y = 63 - y;
                    } else {
                       // Top left corner is a vertical reflection
                       x = 31 - x;
                    }
                }
                x *= 2;
                y *= 2;
            }
            s += c;
        }
        s += '\n';
    }
    return s;
}

Do you need to count the f= here? Nicely done, by the way.

217 bytes

@Shaggy No, I was rushing, so I just pasted it into byte-counter. I found an even better place to set n though.

Even better :) Looks like you missed the edit to my comment above; save another 2 bytes by assigning 126 to a variable; 2 more by using the same trick you used for placing the assignment of n: https://tio.run/##RY7RCsIwDEXf/QpBhIS1Befow7AbfoeILXOMlNmOTaR@/XTt0Jck9@aeEGteZmpGGp7c@Xs7N95Nvm9F7zuA@aaqixDiPI7mDbLAq3iYASCoQy4ZMYOqMslySjL7ldApoDg5zms6HfPaLsXt87oDmXPLLaOMsIyKOLFkYpkiNrNcFiztllT4I/GS3uo1GiIeEv0jQwL1TmP8BIX15LRe@0bPCIjzBw

You don't need f= in byte count, but code snippet doesn't work without it.

@ThePirateBay Sorry, I accidentally deleted it in the latest edit.

intriguing solution, beats my own js

i+i and j+j occur way too often - you can save some bytes by assigning them to variables (or default params)

@ngn: Well spotted. Applying that gives 201 bytes

if instead of introducing new variables, we double i and j themselves (n-- -> (i*=2,j*=2,n--)) replacing i<32 with i<64, it becomes benefitial to assign 64 to a variable 198 bytes

@ngn Thanks, you inspired me to use bit twiddling to shave off another 28 bytes!

@Neil if you go on at this rate your byte count will soon be negative :) One small improvement: >>=1 could be /=2

@ngn I'd have to change the test if I did that; 1/2 != 0.

@Neil ah... you're right, but it still works - n eventually drops to 5e-324 without affecting the output and then becomes 0 :) it took me a while to figure out why it works when it obviously shouldn't

:o What the smeg?! I looked away for a while and half the bytes disappeared! Stellar work :)

@Neil Any chance you could add an explanation or an ungolfed version?

@Jonah I hope you find that helpful.

@Neil Thanks, I appreciate it

LOGO, 375 341 297 295 278 + 3 bytes
Add 3 bytes because of -p flag, which enable perspective mode by default, thus don't need to run perspective command, saves 9 bytes overall.
Use FMSLogo on Windows with Unix (LF) newline format (FMSLogo have problem with parsing CR newline format)
to R
rt 90
end
to g :w :l
R fd 2*:l R bk :l up 180
run :w
R run :w
fd 2*:l R bk :l run :w
fd 2*:l up 180
end
to h
pu
ask -1[setxyz 0 0 870]g[g[g[g[g[g[rt 45 fd .7 pd fd 0 pu bk .7 lt 45]1]2]4]8]16]32
repeat 64[sety 64-# repeat 64[setx #-1 type if pixel=[0 0 0]""#["\ ]](pr)]
end

Unfortunately, no "Try it online!" link because I can't find any online interpreter support perspective mode.
Idea: Draw a picture of the image, then retrieve the pixels from the picture and print as output.
Picture breakdown to simple repeated parts:
.
Make use of the hint above. However, since LOGO does not support reflection, we can only simulate that by enter 3D (perspective) mode and turn the turtle 180 degree around an axis parallel to the computer screen.
This defines a helper function g, which given 2 parameters l (image side length) and w (procedure used to draw the image), draw 3 copies of its reflected image. (see hint in the question) The procedure h perform the main procedure.

You can probably omit some spaces like 90 fd -> 90fd and save a few bytes.

@JonathanFrech Unfortunately, FMSLogo doesn't support that.

Why does papert support it then?

@JonathanFrech I see, but then papert doesn't support pixel, which is necessary to get the pixel back after drawing. So I must use FMSLogo, and cannot take advantage of omitting those spaces.

Is this the only answer that actually exploits the pattern rather than bit packing?

@Jonah I'm not sure how the above JS solution work, so I can't be sure. But all the other answers (exclude the JS and TFeld's Python2 which use the same algorithm) pack the whole information in the code.

@Jonah The JS solution was first to exploit the pattern, though it does it in an interesting way - with modular arithmetic and bit operations instead of concatenating matrices. This LOGO solution is also interesting and unique with its pixel-reading approach. I don't know enough LOGO to understand the code but judging by the description it repeats certain patterns without going all the way down the fractal's structure (which I already gave away in hint1).

@ngn thanks for that explanation

05AB1E, 30 26 bytes
'#)6F©R®í®'#ð:®ζ)2ä€ø€J˜}»

Try it online!

Python 2, 205 195 ... 145 144 142 144 bytes
g=lambda n,i,j,*_:g(n/2,*[~i,j,i,~j][2*(j&n>0)-(i&n>0):])if n*(i&n<=j&n)else'# '[i&n>0]
r=range(64)
for j in r:print''.join(g(32,j,i)for i in r)

Try it online!
Inspired by Neil's JS answer.

n>>1 is n/=2.

a is defined and then used once. Replacing its reference with its value could save four bytes.

I overlooked a useful simplification - rather than doing everything using rotations, I should have been using reflections instead. It saved me 41 bytes on my answer!

I think you can save two bytes by simplifying your [...[x],...[x]][z] selection.

You need to include g= in the code and the byte count since it calls itself.

@totallyhuman Fair enough

CJam, 30 bytes
"#"]{_W%_32ff&+\_Wf%\z+.+}6*N*

Try it online!

Haskell, 126 125 113 106 103 bytes
e=[]:e
z=zipWith
r=reverse
m s=z(++)(r s++map(' '<$)s)$map r s++foldr(z(:))e s
unlines$m$m$m$m$m$m["#"]

A direct implementation of hint1 in the spoiler.
Function m generates the next iteration. The main functions applies m 6 times. Details to m:
m s=                          -- s is the current pattern
     zipWith(++)              -- concatenate pairwise the lines of
                (r s)++       --    the lines of s in reverse order, followed by
                map(' '<$)s   --    each char in s replaced by a space
                              -- and
                map r s++     --    each line of s reversed, followed by
                foldr ... s   --    the transposition of s

e=[]:e;foldr(zipWith(:))e     -- this right fold transposes a matrix

Edit: @ngn saved a byte and @Laikoni another 3. Thanks!

n$n$n$n$n$n["#"] is shorter than iterate n["#"]!!6 :)

@ngn: well spotted. Thanks a lot!

You can use e=[]:e;foldr(zipWith(:))e instead of import Data.List;transpose and then shorten zipWith.

Java 7, 259 238 237 200 bytes
void f(){char[][]o={{35}},n;for(int s=1,x,y;s<64;s*=2,o=n)for(n=new char[64][64],x=s;x-->0;)for(y=0;y<s;n[s+y++][x]=32)n[s+~y][x]=n[y][2*s+~x]=n[s+x][s+y]=o[y][x];for(char[]b:o)System.out.println(b);}

Saved 2 bytes by removing the {} on the x loop, thanks ngn
Saved 19 bytes from various assignment changes, thanks Jonathan
Saved 24 bytes for print vs return (didn't know this was allowed), and
Saved 13 bytes for loop changes, thanks Nevay
Try it online!
My first challenge, and I think respectable for Java.  Uses hint 1, (which is wrong btw, but I can't write comments). It can probably be golfed further, this pass was basically as is, without pretty printing.

I am not sure if it might be because of a version difference, but I tested your code on TIO using Java 8, and it prints null characters instead of spaces.

It sure did, thanks for noticing.  Apparently, Java is quite happy with displaying nulls as spaces in its Strings.

You can save a byte by removing s=1 from your for loop and replacing int s,t,x,y; with int s=1,t,x,y;.

@Tahg that might depend on the IDE or terminal you're using. In any case, welcome and congratulations for a well-golfed first answer. Consider removing the braces around single-statement for-s. What is wrong with hint1? I might well have made a mistake as I put it together late last night.

n[s-1-y][x]=o[y][x];n[y][t-1-x]=o[y][x]; -> n[s-1-y][x]=n[y][t-1-x]=o[y][x];.

the proper transformation matrix is [[V,H],[_,T]] (Either that or there's some subtle difference in your algorithm, but that's what I needed)

'#' -> 35; ' ' -> 32.

@Tahg bummer... fix coming up soon, thanks

201 bytes: void f(){char[][]o={{35}},n;for(int s=1,t,x,y;s<64;s=t,o=n)for(n=new char[t=2*s][t],x=s;x-->0;)for(y=0;y<s;n[s+y++][x]=32)n[s+~y][x]=n[y][t+~x]=n[s+x][s+y]=o[y][x];for(char[]b:o)System.out.println(b);}

J, 30 27 bytes
|:@(|:@|.,|.@|:,.])^:6,.'#'

Try it online!
Original version.
((|.,.|."1),' '"0,.|:)^:6,.'#'

Try it online!

Python 2, 586 bytes
import zlib,base64 as b
print zlib.decompress(b.b64decode('eJyVVlsOwzAI++8pJuX+d1zXDGLAUKi0pUp52ATcfj7+Wni3dF2/677ZO1dw+z/Zd3+rJU4SdkVHMcYQS9OuJVGio4N61p31+TGoQkco6eqoU6gSWdBJRrQhjhIdvLQ6YhNrqrEtUsu8yEbjmRqUWXlgYbl5EHfLC7cDQl4sxxAhO4wUv7fFPTx22sUWqOeEJ544Z3vn9FPU+ZmdHtCak6Fk3hfCx0FkOC8DF4YvmgoFMnCEwW2cDBkzftoiGy4GZaNhM8VYSl3YMEV7ctxsjLQKRCHZ3IB6+ATZpKSKmEyGrqZvEHY8lEQBWf8zbuAg0eypWG6nRqTLIzM+NPQa2faN89FlxhMY2vcTKDP7579fl0rmIpJ+grTvSyis798ghb4vM0CuVgbM1SFdvukjnFnfR1Gt3vAEngd6lGrIDdfkDU/ARwl+ecMHf5SzIzct8KhsqHANZ0FqFbpXdad5qH2DzOHJIHGM2pz26oug9i2+EBpX+cXQCpBA7/tne01lLb4wviHjtJE='))

Try it online.

Python 2, 1032 1025 bytes
I like this one more. But it is much longer. It could be golfed down but there is no need for that. officialaimm's approach is much shorter.
-7 thanks to Jonathan Frech
print''.join(' '*int(x)if'/'<x<'@'else("#"*(ord(x)-64),"\n")[x<"#"]for x in'99A9A2A4A2A1E2B4A9!99B8D4G2A3A4B8!88D8B6B4A2C1G8!88A2A9A7A4E1C1A2A8!88A2A1C1E3E4A9A2A8!88G1C2A2C2A4B8D8!88B4A3A2C2A2G8B55!98A4B2E3E1A2A9A55!88B4A559A9A2A1E2!98A4B99B8G2A2!98G88D8B4A2C!88C1A2A88A2A9A4E1!992A2A88A2A1C1E4A5!992D88G1C2A4B4!992B99B4A3A2G4!777A559A4B2E1A2A4!4A2A1E2B4A559A777!4G2A3A4B99B992!4B4A2C1G88D992!5A4E1C1A2A88A2A569!1E4A9A2A88A2A1C88!C2A4B8D88G98!2A2G8B99B4A89!2E1A2A9A559A4B88!55A9A2A1E3E2B4A98!55B8G2A2C2A3A4B88!8D8B4A2C2A2C1G88!8A2A9A4E3E1C1A2A88!8A2A1C1E4A7A9A2A88!8G1C2A4B6B8D88!8B4A3A2G4D8B99!9A4B2E1A2A4A2A9A99!99996A777!99996B992!99994D299!99994A2A992!99994A2A1C88!99994G98!99994B4A98!99995A4B88!9996E2B4A89!9995C2A3A4B88!9997A2C1G88!9997E1C1A2A88!9997A9A2A88!9997B8D88!9995D8B99!9995A2A9A99!9997A9A2A4A2A1E2!9997B8D4G2A2!9995D8B6B4A2C!9995A2A9A7A4E1!9995A2A1C1E3E4A5!9995G1C2A2C2A4B4!9995B4A3A2C2A2G4!9996A4B2E3E1A2A4!9995B4A559A5!9996A4B99B4!9996G88D4!9995C1A2A88A2A4!9999A2A88A2A1C!9999D88G1!9999B99B4A1!99991A559A4B')

Try it online.

The question allows [t]railing spaces, though your solution omits some spaces.

allowing trailing spaces means, that I dont have to output them. Is that correct? It would save bytes on my second approach. On the first one it is already done because I deleted the trailing spaces while saving my file...

I do not know for sure, but I interpreted it as allowing additional spaces, not allowing missing spaces.

x=='!' -> x<'#'

if x.isdigit() -> if"/"<x<"@"

'\n'if x=='!'else'#'*(ord(x)-64) -> ("#"*(ord(x)-64),"\n")[x<"#"]

@JonathanFrech Thank you. I should really look at the character table for those comparissons.

965 bytes.

897 bytes.

Mathematica, 112 90 bytes
Thanks to Jonathan Frech for help saving 2 bytes!
""<>Nest[{{(r=Reverse)@#,r/@#},{" "+0#,#}}~Flatten~{{1,3},{2,4}}&,{{"#"}},6]~Riffle~"
"

Try it online! (Mathics)
For some reasons, Mathics prints leading spaces in all lines except the first one when print multiline string. Also Mathics doesn't support operator.
Explanation:

{{Reverse@#,Reverse/@#},{" "+0#,#}} : Represent the reverse-horizontally, reverse-vertically, replace-all-by-" ", and transpose ( is transpose operator in Mathematica), corresponding to different ways to reflect or rotate the image.
~Flatten~{{1,3},{2,4}} : Flatten in particular dimensions.
Nest[ ... ,{{"#"}},6] : Apply the function inside to {{"#"}} 6 times.
~Riffle~"<literal newline character>" : Riffle a newline character between each line.
""<> : Join all strings together.

You can define replace Reverse with R and define R=Reverse; to save two bytes.

C# (.NET Core), 1016 1002 980 955 bytes
Saved 14 bytes thanks to Kevin Cruijssen!
Saved 47 bytes thanks to Jonathan Frech!
o=>{foreach(var l in new[]{35223185965568,52841249260288,0xf00c0c277f00,0x9004043ee900,0x977c7c200900,0xfee4e4300f00,0xc22727f00c00,73934616658944,0xc2000020097c,73667282210788,0x7f0000f00c27,0xe9000090043e,9895614577696,0xf0000fee430,0xc0000c227f0,4398050918032,325982355457<<21,1092065689603<<20,835235872783<<20,291765223433<<20,0x7c20090000970000,-15289957744513<<17,21955973480545<<17,68788263321667<<16,68799053409<<17,206425089091<<16,0xf00c27277f0000,618546478825<<16,650622541833<<16,0xfee430300f0000,208473439235<<18,72203117569<<18,1<<21,3<<20,15<<20,9<<20,9895936,127<<17,97<<17,67<<16,15969<<17,3829596160,662634496,16105<<16,8201<<16,806289408,4027318272,9217L<<18,537463164,806293476,4027321383,2416182334,2541517856,4276413488,3257346032,1128152720,3254779936,1124073520,2130706672,3909091472,150995095,251658494,201326786,67108931})System.Console.WriteLine(System.Convert.ToString(l,2).PadLeft(64,'0').Replace('0',' ').Replace('1','#'));}

Try it online!

Explanation
The format of the output is stored inside an array of signed 64-bit numbers, which fits perfectly since each line is 64 characters long. Empty spaces are represented by 0 and # is represented by 1.
The numbers are then converted to their binary string, zeros are padded left until the string is 64 characters wide and then the 0 and 1 characters are replaced with   and #.
The code is stored inside a lamba function, more specifically a System.Func<string>.
Some constants in the long[] are shortened by performing some bit-shifting.

Is there not an unnecessary space in long[] n=new[]?

@JonathanFrech Ah you are right, apparently it snuck in there somehow.

You can save 14 bytes by printing directly and using the new[]{...} directly in the loop: o=>{foreach(var l in new[]{...})System.Console.WriteLine(System.Convert.ToString(l,2).PadLeft(64,'0').Replace('0',' ').Replace('1','#'));} Try it here. 1002 bytes

@KevinCruijssen Thanks, getting close to the <1000! :P

I think you can save 11 bytes by shortening some constants using bitshifting. See my Python script for a list of possible replacements.

@JonathanFrech Thanks, that's awesome? Actually we can even shorten it by 22 bytes, since C# doesn't require the l suffix!

Can you not pad the string with spaces in the first place?

@Neil That wouldn't save any bytes, as I would have to replace the other 0s in the binary string anyways.

You would save 4 bytes by not having to specify the padding character.

Well, if the trailing l is not needed, you can probably save even more bytes.

Looks like the bottom of this is bugged.

@Neil Oh you're right, that does help.

@JonathanFrech It seems some numbers are bugged with your solution, any idea why?

I am no expert in C#, but replacing all << with L<< seems to fix the issue. Is it possible that a literal number is an integer by default, and so wraps around as only 32 bits are used?

This code snippet strongly suggests that that might be the problem.

Investigating the problem further, I think that any integer literal on the <<'s left side that is larger than 2**31-1 is -- without a trailing L -- interpreted as a 64-bit number. If, however, that literal is smaller or equal to 2**31-1, it is interpreted as a 32-bit number. Bitshifting a 32-bit number results in a 32-bit number, not in a required 64-bit number, and thus the output is buggy.

Take a look at my improved C# constant golfer, which also implements someone's idea to use hexadecimal literals.

@JonathanFrech Hey, that's awesome! i'll improve my post as soon as I can.

Charcoal, 42 bytes
#↓##ＦＥ⁵Ｘ²ι«‖↑Ｊ⁻×³ι¹±⁰ψ⟲ＯＯ⁴×²ι⟲ＣＪ⁰±φＴ×⁴ι×⁴ι

Try it online! Link is to verbose version of code. Would be 25 bytes if this worked:
#ＦＥ⁷Ｘ²ι«‖↑⟲Ｃ→⁴⟲ＣＪ⁰±φＴιι

Explanation:
#↓##

Manually generate the first recursion, since it's not possible to rotate around (1, 0.5). (Such a rotation would only make sense if it was 180°.)
ＦＥ⁵Ｘ²ι«

Loop over the first five powers of 2 (1, 2, 4, 8, 16).
‖↑

Reflect the canvas vertically. This completes the top left quarter of the result.
Ｊ⁻×³ι¹±⁰ψ⟲ＯＯ⁴×²ι

Rotate the canvas 180° around a point half-way up the right-hand side. The copy ends up in the correct position for the top right quarter of the result.
⟲Ｃ

Rotate the canvas 90° around the bottom right corner. The copy of the top right corner ends up in the correct position for the bottom right corner of the result. The copy of the top left corner is extraneous.
Ｊ⁰±φＴ×⁴ι×⁴ι

Trim the canvas to the size we want. The trim starts at the cursor or the top left of the canvas, whichever is bottom rightmost. The cursor is therefore sent to (0, -1000) to ensure that it doesn't interfere with the trim.

Dyalog APL, 29 bytes
⎕←(((⊖,⌽)⍪⊢∘' '¨,⍉)⍣6)1 1⍴'#'

Try it online!

((⊖,⌽)⍪∊,⍉)⍣6⍪⍕# with ⎕ML←0.

Python 2, 715 711 bytes

-4 bytes thanks to @Jonathan Frech

for k in range(64):print"".join(ord(i)*" #"[j%2]for j,i in enumerate('												<?<<<89:11222	202	4	$" 	!%$%$&%$($%&'))[k<<6:][:64]

Try it online!

711 bytes.

@JonathanFrech Thank you, I didn't think there were no new-lines. :D

Perl 5, 452 bytes
451 bytes code + 1 for -p.
Packs all the data into the string, rather than stealing @Neil's correct answer.
$_=unpack"B*","\x00\x00\x20\x09\x09\x7c\xc2\x33\x00\x30\x0f\x0f\xe4\x43\x33\x00\xf0\x0c\x0c\x27\x7f\x33\x00\x90\x04\x04\x3e\xe9\x33\x00\x97\x7c\x7c\x20\x09\x33\x00\xfe\xe4\xe4\x30\x0f\x33\x00\xc2\x27\x27\xf0\x0c\x33\x00\x43\x3e\x3e\x90\x04\x33\x00\xc2\x00\x00\x20\x09\x7c\x00\x00\x43\x00\x00\x30\x0f\xe4\x00\x00\x7f\x00\x00\xf0\x0c\x27\x00\x00\xe9\x00\x00\x90\x04\x3e\x00\x00\x09\x00\x00\x97\x7c\x20\x00\x00\x0f\x00\x00\xfe\xe4\x30\x00\x00\x0c\x00\x00\xc2\x27\xf0\x00\x00\x04\x00\x00\x43\x3e\x90\x09\x7c\xc2\x00\x00\x20\x00\x00\x0f\xe4\x43\x00\x00\x30\x00\x00\x0c\x27\x7f\x00\x00\xf0\x00\x00\x04\x3e\xe9\x00\x00\x90\x00\x00\x7c\x20\x09\x00\x00\x97\x00\x00\xe4\x30\x0f\x00\x00\xfe\x00\x00\x27\xf0\x0c\x00\x00\xc2\x00\x00\x3e\x90\x04\x00\x00\x43\x33\x00\x20\x09\x7c\x7c\xc2\x33\x00\x30\x0f\xe4\xe4\x43\x33\x00\xf0\x0c\x27\x27\x7f\x33\x00\x90\x04\x3e\x3e\xe9\x33\x00\x97\x7c\x20\x20\x09\x33\x00\xfe\xe4\x30\x30\x0f\x33\x00\xc2\x27\xf0\xf0\x0c\x33\x00\x43\x3e\x90\x90\x04\x37\x00\x20\x37\x00\x30\x37\x00\xf0\x37\x00\x90\x37\x00\x97\x37\x00\xfe\x37\x00\xc2\x37\x00\x43\x36\x00\x7c\xc2\x36\x00\xe4\x43\x36\x00\x27\x7f\x36\x00\x3e\xe9\x36\x00\x20\x09\x36\x00\x30\x0f\x36\x00\xf0\x0c\x36\x00\x90\x04\x36\x00\x20\x09\x09\x7c\x34\x00\x30\x0f\x0f\xe4\x34\x00\xf0\x0c\x0c\x27\x34\x00\x90\x04\x04\x3e\x34\x00\x97\x7c\x7c\x20\x34\x00\xfe\xe4\xe4\x30\x34\x00\xc2\x27\x27\xf0\x34\x00\x43\x3e\x3e\x90\x34\x00\xc2\x00\x00\x20\x34\x00\x43\x00\x00\x30\x34\x00\x7f\x00\x00\xf0\x34\x00\xe9\x00\x00\x90\x34\x00\x09\x00\x00\x97\x34\x00\x0f\x00\x00\xfe\x34\x00\x0c\x00\x00\xc2\x34\x00\x04\x00\x00\x43"=~s/[3-9](.)/$1x$&/ger;y/01/ #/;s/.{64}/$&
/g

Reversible output from xxd for 451 byte file:
00000000: 245f 3d75 6e70 6163 6b22 422a 222c 2200  $_=unpack"B*",".
00000010: 0020 0909 7cc2 3300 300f 0fe4 4333 00f0  . ..|.3.0...C3..
00000020: 0c0c 277f 3300 9004 043e e933 0097 7c7c  ..'.3....>.3..||
00000030: 2009 3300 fee4 e430 0f33 00c2 2727 f00c   .3....0.3..''..
00000040: 3300 433e 3e90 0433 00c2 0000 2009 7c00  3.C>>..3.... .|.
00000050: 0043 0000 300f e400 007f 0000 f00c 2700  .C..0.........'.
00000060: 00e9 0000 9004 3e00 0009 0000 977c 2000  ......>......| .
00000070: 000f 0000 fee4 3000 000c 0000 c227 f000  ......0......'..
00000080: 0004 0000 433e 9009 7cc2 0000 2000 000f  ....C>..|... ...
00000090: e443 0000 3000 000c 277f 0000 f000 0004  .C..0...'.......
000000a0: 3ee9 0000 9000 007c 2009 0000 9700 00e4  >......| .......
000000b0: 300f 0000 fe00 0027 f00c 0000 c200 003e  0......'.......>
000000c0: 9004 0000 4333 0020 097c 7cc2 3300 300f  ....C3. .||.3.0.
000000d0: e4e4 4333 00f0 0c27 277f 3300 9004 3e3e  ..C3...''.3...>>
000000e0: e933 0097 7c20 2009 3300 fee4 3030 0f33  .3..|  .3...00.3
000000f0: 00c2 27f0 f00c 3300 433e 9090 0437 0020  ..'...3.C>...7.
00000100: 3700 3037 00f0 3700 9037 0097 3700 fe37  7.07..7..7..7..7
00000110: 00c2 3700 4336 007c c236 00e4 4336 0027  ..7.C6.|.6..C6.'
00000120: 7f36 003e e936 0020 0936 0030 0f36 00f0  .6.>.6. .6.0.6..
00000130: 0c36 0090 0436 0020 0909 7c34 0030 0f0f  .6...6. ..|4.0..
00000140: e434 00f0 0c0c 2734 0090 0404 3e34 0097  .4....'4....>4..
00000150: 7c7c 2034 00fe e4e4 3034 00c2 2727 f034  || 4....04..''.4
00000160: 0043 3e3e 9034 00c2 0000 2034 0043 0000  .C>>.4.... 4.C..
00000170: 3034 007f 0000 f034 00e9 0000 9034 0009  04.....4.....4..
00000180: 0000 9734 000f 0000 fe34 000c 0000 c234  ...4.....4.....4
00000190: 0004 0000 4322 3d7e 732f 5b33 2d39 5d28  ....C"=~s/[3-9](
000001a0: 2e29 2f24 3178 2426 2f67 6572 3b79 2f30  .)/$1x$&/ger;y/0
000001b0: 312f 2023 2f3b 732f 2e7b 3634 7d2f 2426  1/ #/;s/.{64}/$&
000001c0: 0a2f 67                                  ./g

Try it online!

Jq 1.5, 538 535 488 476 bytes
This is a straightforward representation.  I haven't attempted any fancy encodings yet. Replaced 0,0 pairs with Z function.
Thanks again to Jonathan Frech for helping eliminate 3 bytes!
def B:recurse(if.>0then./2|floor else empty end)|.%2;def S:256+.|[B]|reverse[2:]|map(if.>0then"#"else" "end)|join("");def Z:0,0;[[Z,3,1,1,4,5,2],[1,4,5,2,2,3,Z],[Z,Z,2,3,Z],[Z,Z,3,1,1,4]]as$m|[[],[9,15,12,4,124,228,39,62],[Z,Z,Z,Z,124,228,39,62,32,48,240,144],[32,48,240,144,151,254,194,67,194,67,127,233,9,15,12,4],[124,228,39,62,32,48,240,144,32,48,240,144,151,254,194,67],[194,67,127,233,9,15,12,4,9,15,12,4,124,228,39,62]]as$c|$m[]|range(16)as$l|map($c[.][$l]|S)|join("")

Character count
$ wc -c picture.jq
 476 picture.jq

Sample run
$ jq -Mnr -f picture.jq
                  #         #  #    #  # #####  ##    #
                  ##        ####    #######  #   #    ##
                ####        ##      ##    #  ### #######
                #  #         #       #    ##### ### #  #
                #  # ### #####   #####    #         #  #
                ####### ###  #  ###  #    ##        ####
                ##    #   #  ###  #  #######        ##
                 #    ##  #####   ##### #  #         #
                ##    #                   #         #  # #####
                 #    ##                  ##        #######  #
                 #######                ####        ##    #  ###
                ### #  #                #  #         #    #####
                    #  #                #  # ### #####    #
                    ####                ####### ###  #    ##
                    ##                  ##    #   #  #######
                     #                   #    ##  ##### #  #
    #  # #####  ##    #                   #
    #######  #   #    ##                  ##
    ##    #  ### #######                ####
     #    ##### ### #  #                #  #
 #####    #         #  #                #  # ###
###  #    ##        ####                #######
  #  #######        ##                  ##    #
  ##### #  #         #                   #    ##
          #         #  # #####   #####  ##    #
          ##        #######  #  ###  #   #    ##
        ####        ##    #  ###  #  ### #######
        #  #         #    #####   ##### ### #  #
        #  # ### #####    #       #         #  #
        ####### ###  #    ##      ##        ####
        ##    #   #  #######    ####        ##
         #    ##  ##### #  #    #  #         #
                                          #
                                          ##
                                        ####
                                        #  #
                                        #  # ###
                                        #######
                                        ##    #
                                         #    ##
                                 #####  ##    #
                                ###  #   #    ##
                                  #  ### #######
                                  ##### ### #  #
                                  #         #  #
                                  ##        ####
                                ####        ##
                                #  #         #
                                  #         #  #    #  # #####
                                  ##        ####    #######  #
                                ####        ##      ##    #  ###
                                #  #         #       #    #####
                                #  # ### #####   #####    #
                                ####### ###  #  ###  #    ##
                                ##    #   #  ###  #  #######
                                 #    ##  #####   ##### #  #
                                ##    #                   #
                                 #    ##                  ##
                                 #######                ####
                                ### #  #                #  #
                                    #  #                #  # ###
                                    ####                #######
                                    ##                  ##    #
                                     #                   #    ##

Three omittable spaces in B: rec and 16) as $l|.

if.==0then" "else"#"end -> if.>0then"#"else" "end.

Python 2, 174 164 154 bytes (based on matrix operations)

-10 bytes thanks to ngn.
-10 bytes thanks to Jonathan Frech.

from numpy import*
s=[['#']]
exec'b=fliplr(s);s=vstack((hstack((flipud(s),b)),hstack((eye(len(s)),rot90(b)))));'*6
s[s>'#']=' '
for l in s:print''.join(l)

Try it online!

import * -> import*; in s.tolist() -> in s

154 bytes.

K (ngn/k), 32 31 27 bytes
6{,[|x;""x],'(+|+x),+x}/"#"

Try it online!
6{ }/ 6 times do
+x transpose
|x reverse vertically
+|+x reverse horizontally
, concatenate vertically
,' concatenate horizontally
,[A;B] is the same as A,B. it helps avoid parentheses around A and around the whole expression
""x use the elements of x as indices in the empty string. out-of-bounds indexing produces spaces, so this expression will return an all-spaces matrix, same size as x

Canvas, 10 bytes
#６［↔ω⤢∔ω↶×

Try it here!

C# (.NET Core), 976 969 bytes
o=>{foreach(var l in new[]{35223185965568,52841249260288,0xf00c0c277f00,0x9004043ee900,0x977c7c200900,0xfee4e4300f00,0xc22727f00c00,73934616658944,0xc2000020097c,73667282210788,0x7f0000f00c27,0xe9000090043e,9895614577696,0xf0000fee430,0xc0000c227f0,4398050918032,0x97cc20000200000,0xfe44300003<<20,0xc277f0000f<<20,0x43ee900009<<20,0x7c20090000970000,-0x1bcff0ffff020000,0x27f00c0000c20000,0x3e90040000430000,9017629528424448,0x300fe4e4430000,0xf00c27277f0000,0x90043e3ee90000,0x977c2020090000,0xfee430300f0000,0xc227f0f00c0000,0x433e9090040000,2097152,3145728,15728640,9437184,9895936,16646144,12713984,4390912,2093088768,3829596160,662634496,1055457280,537460736,806289408,4027318272,2416181248,537463164,806293476,4027321383,2416182334,2541517856,4276413488,3257346032,1128152720,3254779936,1124073520,2130706672,3909091472,150995095,251658494,201326786,67108931})System.Console.WriteLine(System.Convert.ToString(l,2).PadLeft(64).Replace('0',' ').Replace('1','#'));}

Try it online!

Hi, welcome to PPCG! This looks almost exactly the same as @IanH's C# .NET answer.. So if you have any improvements for his, make a comment instead of creating a new answer that is almost exactly the same. As for your question, you can use <s>969</s> to cross out the previous bytes.

I do not have the reputation needed to comment.

Please don't try to circumvent the rep requirements.

Does this mean that in PPCG I cannot try to help others if my reputation is too low?

@Shaggy to be fair, stackexchange is a bit harsh on newcomers, let's not make it harder for them by assuming malice too quickly

C# (.NET Core), 739 bytes
_=>{var r="";for(int i=0,j,k=0;i<626;i++)for(j=0;j++<@"4#+#$#&#$##'$$&#=$*&&)$#%#&$:&*$($&#$%#):#$#+#)#&'#%##$#:#$##%#'%'&#+#$#:)#%$#$%$#&$*&:$&#%#$%$#$)*$=#&$$'%'##$#+#<$&#5#+#$##'5#&$4$*)$#5)2&*$&#$%2%##$#2#$#+#&'7#$#2#$##%#'&#;&2)#%$#&$:$4$&#%#$);#5#&$$'##$#*#$##'$$&#5#;)$#%#&$4$:$&#$%#)2&;#&'#%##$#2#$#7'&#+#$#2#$##%2%$#&$*&2)5#$)*$4$&#5'##$#+#5#&$<#+#$##'%'$$&#=$*)$#$%$#%#&$:&*$&#$%$#$%#):#$#+#&'%'#%##$#:#$##%#'&#)#+#$#:)#%$#&$($*&:$&#%#$)&&*$=#&$$'##$#&#$#+#^#a$^&^#$#^#$##%Z)[$&#\#&$S'$$&#S%$#%#&$T#$%#)T'#%##$#T#+#$#T$*&R&*$T#$#+#V#+#$#&#$##'F$*&&)$#D&*$($&#$%B#$#+#)#&'C#$##%#'%'&#G)#%$#$%$#&$F$&#%#$%$#$)G#&$$'%'##$#F$&#5#H#&$4$G)2&F%##$#2#$#J#$#2#$##%F&2)G$4$&#H#5#&$"[i]-34;){r+=i%2<1?' ':'#';if(++k%64<1)r+='\n';}return r;}

Try it online!
Uses the same approach is this other answer.

730 bytes

JavaScript (Node.js), 1233 bytes
_=>` 18# 9# 2# 4# 2# #5 2#2 4#
 18#2 8#4 4#7 2# 3# 4#2
 16#4 8#2 6#2 4# 2#3 #7
 16# 2# 9# 7# 4#5 #3 # 2#
 16# 2# #3 #5 3#5 4# 9# 2#
 16#7 #3 2# 2#3 2# 4#2 8#4
 16#2 4# 3# 2#3 2# 2#7 8#2
 17# 4#2 2#5 3#5 # 2# 9#
 16#2 4# 19# 9# 2# #5
 17# 4#2 18#2 8#7 2#
 17#7 16#4 8#2 4# 2#3
 16#3 # 2# 16# 2# 9# 4#5
 20# 2# 16# 2# #3 #5 4#
 20#4 16#7 #3 2# 4#2
 20#2 18#2 4# 3# 2#7
 21# 19# 4#2 2#5 # 2#
 4# 2# #5 2#2 4# 19#
 4#7 2# 3# 4#2 18#2
 4#2 4# 2#3 #7 16#4
 5# 4#5 #3 # 2# 16# 2#
 #5 4# 9# 2# 16# 2# #3
#3 2# 4#2 8#4 16#7
 2# 2#7 8#2 18#2 4#
 2#5 # 2# 9# 19# 4#2
 10# 9# 2# #5 3#5 2#2 4#
 10#2 8#7 2# 2#3 2# 3# 4#2
 8#4 8#2 4# 2#3 2# 2#3 #7
 8# 2# 9# 4#5 3#5 #3 # 2#
 8# 2# #3 #5 4# 7# 9# 2#
 8#7 #3 2# 4#2 6#2 8#4
 8#2 4# 3# 2#7 4#4 8#2
 9# 4#2 2#5 # 2# 4# 2# 9#
 42#
 42#2
 40#4
 40# 2#
 40# 2# #3
 40#7
 40#2 4#
 41# 4#2
 33#5 2#2 4#
 32#3 2# 3# 4#2
 34# 2#3 #7
 34#5 #3 # 2#
 34# 9# 2#
 34#2 8#4
 32#4 8#2
 32# 2# 9#
 34# 9# 2# 4# 2# #5
 34#2 8#4 4#7 2#
 32#4 8#2 6#2 4# 2#3
 32# 2# 9# 7# 4#5
 32# 2# #3 #5 3#5 4#
 32#7 #3 2# 2#3 2# 4#2
 32#2 4# 3# 2#3 2# 2#7
 33# 4#2 2#5 3#5 # 2#
 32#2 4# 19#
 33# 4#2 18#2
 33#7 16#4
 32#3 # 2# 16# 2#
 36# 2# 16# 2# #3
 36#4 16#7
 36#2 18#2 4#
 37# 19# 4#2`.replace(/(.)(\d+)/g,(_,c,n)=>c.repeat(n))

Try it online!

Ooh, what's the problem now? Erm... Am I missing something?

I didn't downvote, but, fyi, it can be compressed much more using this.

I didn't either, but this isn't in the spirit of the question.  The pattern was generated, presumably, by some simple recursive procedure.  The challenge is determine the rule, at which point your solution will be extremely short.

I upvoted. It's a valid solution, though far from what I expect the best js one to be (<300 chars).

Convert to base 36 to save ~50 bytes.

I am completely aware that this is not the optimal solution or the shortest solution or a clever one. I simply tried using an algorithm and it ended up being this. This is, however, a perfectly valid solution and hence doesn't deserve downvotes. Boring solutions should not be upvoted but they shouldn't be downvoted either.

As such, I am not switching to a "something compressed something" solution nor am I golfing this any further.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/