20

This puzzle is part of the Puzzling StackExchange Advent Calendar 2021. The accepted answer to this question will be awarded a bounty worth 50 reputation.

< Previous Door Next Door >


Question: What message is hidden inside this tree?

triangle with asterisks, spaces, greater and less than signs, upper and lowercase O’s and @ symbols.

Text Version:

               *
              >​>​>​
             >​>​>​O​>​
            >​O​<​O​>​o​@​
           O​>​o​>​o​>​>​O​@​
          >​>​@​<​O​>​o​<​@​>​>​
         @​O​>​o​@​O​<​o​<​@​<​<​@​
        O​<​<​<​o​>​>​>​@​O​<​<​<​o​<​
       o​<​O​<​@​>​>​>​O​>​>​>​o​>​@​>​>​
      >​>​>​O​>​o​@​O​<​<​o​@​<​O​>​o​@​>​>​
     O​<​<​<​<​o​@​O​<​<​<​<​<​o​>​o​>​>​@​O​<​
    o​<​<​O​@​>​>​>​>​>​O​<​<​<​<​o​@​O​<​o​@​>​<​
   <​<​<​<​<​<​<​@​>​O​<​o​>​>​>​@​>​O​>​>​>​>​>​>​o​
  >​@​O​>​>​o​<​@​O​>​>​o​@​<​O​>​>​>​o​<​o​>​>​@​O​<​<​
 o​>​>​>​>​>​@​<​<​O​>​o​<​o​>​>​@​>​>​>​>​O​>​o​@​<​O​>​>​
o​>​>​@​O​<​<​<​<​o​@​O​>​>​o​>​<​>​<​<​>​>​<​<​>​>​>​<​>​<​@​

Note:

The asterisk (and the leading spaces) are for decoration only.


Small Hint:

dan04 is correct in their assumption that the tree is executable. ;) You won’t find the solution by digging through a list of existing esolangs (or at least I really hope so).

The language, unsurprisingly, has a “Print” command.

Medium Hint:

- O/o are not bracketed groups.
- Output depends on ASCII code points.
- I had to be very careful with my wording in the original note.
- The commands are very simple.

Large Hint:

Which line a command is on influences its result (except if the command is @).

Between two @s, you will often find a structure of the form O{x times > or <}o. This is a “trick” that does a very simple operation. It’s employed to compensate for what \n does.

Maybe you should focus on the start, which gets us to a printable ASCII letter in (14+3) commands.

Some confirmations of what people have said:
- @ = print value as char
- > = increment value (somehow)
- < = decrement value (somehow)

Lukas Rotter
  • 10,321
  • 1
  • 49
  • 89
  • 8
    Asterisks are for decoration No, without a star it's not christmas tree! ... Wait, yes, it's for decoration ... – WhatsUp Dec 02 '21 at 09:27
  • 2
    A christmas tree without a star is NOT a christmas tree, even with other decorations. – Stevo Dec 02 '21 at 09:34
  • 2
    In case it's helpful information to anyone, the tree contains 95 >s, 65 <s, 32 Os, 32 os, and 31 @s. – dan04 Dec 02 '21 at 17:15
  • 1
    Imagine if this were a Turing Machine or something (would be hella cool) – Avi Dec 02 '21 at 17:18
  • 4
    @Avi: I suspect that it actually is some kind of esoteric programming language like that. I also see that the characters O and o form balanced "brackets". – dan04 Dec 02 '21 at 17:23
  • 1
    This reminds me of the Advent of Code 2015 Christmas tree: https://www.reddit.com/r/adventofcode/comments/3v5vfk/what_the_finished_christmas_tree_will_look_like/ Same symbols, same colors, and apparently players got different trees (different outputs?). – hb20007 Dec 03 '21 at 10:22
  • 3
    @hb20007 Yep, that's the inspiration :) I have no idea what the AOC tree does or how its generated, though. That's independent from this puzzle. – Lukas Rotter Dec 03 '21 at 10:27
  • I just got to thinking about the page title. "Nerds" seems like a reasonable description of most Stack Exchange users. But why "broke"? Logically, there's nothing preventing a rich person from taking up puzzle solving as a hobby. So I think "broke" must be a hint somehow. Maybe that the output is a saying about the unimportance of money. Or maybe it's a hint to what one of the programming language's commands does. – dan04 Dec 04 '21 at 08:52
  • 1
    Since O/o do not represent brackets or parenthesis, I suppose I don’t need a while or for loop to count the <s and >s between them? –  Dec 04 '21 at 12:00
  • @dan04 Broke was just included because my head conjured up a story of someone not being able to afford a real christmas tree so they make one with ASCII art (with the computer they somehow affored at an earlier point :)) – Lukas Rotter Dec 04 '21 at 19:06

4 Answers4

11

Thanks to @Crimsonfox, the complete answer is:

Christmas Comes But Once a Year

The corresponding ASCII code points we get by running the commands are:

67 104 114 105 115 116 109 97 115 32 67 111 109 101 115 32 66 117 116 32 79 110 99 101 32 97 32 89 101 97 114


To solve the puzzle, I created the tiny JavaScript program below. The code iterates through all the characters of the string (the asterisk and spaces are removed), assigning a specific command to each symbol.

var input =
    "\n" +
    ">>>\n" +
    ">>>O>\n" +
    ">O<O>o@\n" +
    "O>o>o>>O@\n" +
    ">>@<O>o<@>>\n" +
    "@O>o@O<o<@<<@\n" +
    "O<<<o>>>@O<<<o<\n" +
    "o<O<@>>>O>>>o>@>>\n" +
    ">>>O>o@O<<o@<O>o@>>\n" +
    "O<<<<o@O<<<<<o>o>>@O<\n" +
    "o<<O@>>>>>O<<<<o@O<o@><\n" +
    "<<<<<<<@>O<o>>>@>O>>>>>>o\n" +
    ">@O>>o<@O>>o@<O>>>o<o>>@O<<\n" +
    "o>>>>>@<<O>o<o>>@>>>>O>o@<O>>\n" +
    "o>>@O<<<<o@O>>o><><<>><<>>><><@";

var output = [], x = 0, line = 0;

for(var i = 0; i < input.length; i++) { if(input[i] === ">") { // increment value x += line; } else if(input[i] === "<") { // decrement value x -= line; } else if(input[i] === "O") { // multiply by line number x *= line; } else if(input[i] === "o") { // divide by line number and round off x = Math.floor(x / line); } else if(input[i] === "@") { // print ASCII character output.push(x); } else if(input[i] === "\n") { // increment line number line++; } }

console.log(String.fromCharCode(...output));

As we can see, we need to do four simple arithmetic operations in order to decode the Christmas tree: addition (>), subtraction (<), multiplication (O) and division (o), using the line number of the corresponding command. @ prints the value of x which represents an ASCII code point.


Original answer

Note: Since this used to be a partial answer, some of the information below might be incorrect.

The hints provided in the question (and one of OP’s comments) let us conclude the following:

As stated in the “large hint,” < and > are used to increment and decrement a variable by a certain value, while @ means “print ASCII character.”

O/o are not bracketed groups. Between two @s, you will often find a structure of the form O{x times > or <}o. This is a “trick” that does a very simple operation.
O/o do not represent brackets or parenthesis. However, O{…}o seems to imply that O and o do come in pairs and thus probably have a similar purpose. Since each of the five different symbols represent a “very simple operation,” we should probably focus on simple additions (or subtractions) rather than multiplications and divisions.
It's employed to compensate for what \n does. The difference between the number of O and o should turn out to be small, if not 0.
→ This suggests that O and o represent a particular number and have something to do with line numbers. Since O adds 1 to the line variable and o subtracts the same number in the code above, we can say there is only little difference between the two commands.

Which line a command is on influences its result (except if the command is @).
→ The variable line in the code must somehow be involved in incrementing and decrementing the value x. In the example above, a > on line 4 increments x by 4, while a < decrements it by 4. @ simply outputs the value of the counter x.

Maybe you should focus on the start, which gets us to a printable ASCII letter in (14+3) commands.
→ There are exactly 14 symbols or commands before the first print command (@), excluding line breaks, as well as 3 Os: >>>>>>O>>O<O>o. We have make sure x is between 65 (A) and 90 (Z) (or 97 and 122 for the lowercase letters), so that the commands yield a valid letter of the alphabet.

I had to be very careful with my wording in the original note. (The asterisk (and the leading spaces) are for decoration only.)
→ If OP had written “whitespaces” instead of “spaces,” that would mean we could also ignore line breaks and line numbers, which is not the case, according to the hints.

Now, the question arises whether >/< and O/o really constitute two separate counters that can be incremented and decremented.

10

I think I’ve got it, just working through the message, the first letters are coming out as expected. The commands map as follows:

< / >: increment and decrement by line number
\n: increment line number variable
@: print
O / o: multiply and divide by line number

The first word is Christmas. Edit: I’m having trouble with that should be a space, coming out 1 character too high. But if I skip it (or assume it’s a space) I get Comes as the second word.

Edit 2: Answer is “Christmas Comes But Once a Year” because I’m silly and forgot to floor it.

Crimsonfox
  • 462
  • 2
  • 7
  • 4
    I'll accept Lypyrhythm's answer because it provides a better explanation. But since you are the one who actually solved this, I'll just award a 100 points bounty to you (independent from the event) – Lukas Rotter Dec 04 '21 at 18:38
  • @Lukas Rotter Thanks! Wasn't expected to get so invested in this, great puzzle! – Crimsonfox Dec 04 '21 at 18:40
5

Partial answer

The tree is a program in an esoteric program language, which has at least one state variable (which I'll call “the accumulator”), and 5 commands:

  • > / < = increment/decrement the accumulator
  • @ = print a character whose value is somehow related to the accumulator's value (likely ASCII code, or a simple 1=A, 2=B, 3=C, ..., 26=Z code).
  • O ... o = a bracketed group of instructions, perhaps representing a while or for loop.

Whitespace and * are ignored.

Edit: My original idea about O and o was disproven by the Medium Hint. But I still think it's some kind of complementary pair of commands.

dan04
  • 3,280
  • 12
  • 26
  • 2
    Good observations. I got Brainf**k vibes from this at first sight and mapping Oo><@ to Oo+-. makes a valid program, but it writes unprintable characters. (This doesn't make use of loops or jumps, but we either get a program with just one register or a program without loops.) Anyway, we can write a program that writes numbers instead of ASCII codes. (Not having loops means that going into the useful range of ASCII characters will be very verbose.) In honour of Lukas, we could call this bf variant Brainrot. :) Unfortunaltely, I don't know what to do next. – M Oehm Dec 03 '21 at 05:45
  • 1
    I'll spoiler that O/o are not bracketed groups – Lukas Rotter Dec 03 '21 at 06:24
  • @LukasRotter: Well, I'll try a different approach, then. Is there any significance to the fact that the number of O's and os are exactly equal, or is that just coincidental? – dan04 Dec 03 '21 at 08:26
  • 1
    @dan04 Strictly speaking it's coincidental, but it's a coincidence that's likely to happen if you write code in this language (if it outputs anything that makes sense). The difference between the number of O and o should turn out to be small, if not 0. – Lukas Rotter Dec 03 '21 at 08:34
  • 1
    Why do you think that < and > change the accumulator? It could be e.g. moving the read/write pointer, as in a Turing machine. Also why is @ printing characters? This looks like pure guessing to me - so is the entire puzzle actually, for such a computer puzzle I would prefer something that involves a little bit of logical reasoning. – WhatsUp Dec 03 '21 at 08:43
  • 2
    @WhatsUp The last command is @, so unless that is the print command we're leaving something out of the output. – Jafe Dec 03 '21 at 08:50
  • 1
    @WhatsUp: Perhaps it's an intentional red herring, but < and > just look like they'd be some complementary pair of operations. Maybe they're p-- and p++, or maybe they're *p-- and *p++, but either one can generally be described as "decrement" and "increment". Similarly, it would make sense for O and o to be paired somehow. I picked @ as print because it's the leftover "unpaired" operation: A program that outputs a simple message doesn't need an input command. Also what @Jafe said about @ being the last command. – dan04 Dec 03 '21 at 09:05
  • 1
    Though, the new "Medium Hint" suggests that \n may also be a command. – dan04 Dec 03 '21 at 09:07
  • @Jafe But you first need to assume that @ is a command. For example, in C we have printf("Hello World!\n"); where printf appears at the beginning of the instruction. Same with basically every programming language. Very rarely do we have a grammar that looks like "Hello World!\n", print. It's also possible that @ is something like \n. – WhatsUp Dec 03 '21 at 16:55
  • 1
    I'm sorry that my comments are nonconstructive, as I don't have much idea with this kind of "guessing" puzzles. Maybe we have to wait for more hints. – WhatsUp Dec 03 '21 at 17:03
2

I also assumed @ prints a character based on an accumulated value

If < and > increment and decrement a register that starts as 0 then throughout the program the register varies between 0 and 31.

If O and o increment and decrement a different register that starts as 0 then throughout the program the register varies between 0 and 3.

These seem to be independently covering 5 bits and 2 bits. If you concatenate the values the 2 bits above the 5 bits then it outputs valid capital ASCII characters and one dash for the first 24 characters, two digits for the next two and then 5 non printing characters. Unfortunately it does not spell anything.

The hint "I had to be very careful with my wording in the original Note." makes me think that while the asterisk(s) and space mean nothing, maybe the line breaks affect the program somehow.

caPNCApn
  • 19,113
  • 1
  • 63
  • 96
  • So, if I understand correctly, you got the output "HLNMOPNLLFMSQQO-JKJCFNOQ47␗␜␟␛␀". – dan04 Dec 03 '21 at 09:29
  • @dan04 Correct. – caPNCApn Dec 03 '21 at 21:45
  • What do you mean by “concatenate the values the 2 bits above the 5 bits”? For example, if i = 11 and j = 2, should the result be concat(j, i), i.e. 211? –  Dec 04 '21 at 08:02
  • 1
    @Lypyrhythm: If means that if x is the 5-bit register and o is the 2-bit register, then their combined value is (o << 5) | x or 32 * o + x. – dan04 Dec 04 '21 at 08:11
  • 1
    It means that O would be equivalent to a sequence of 32 >s, and o to a sequence of 32 <s. Or maybe vice-versa. Or maybe they represent a different related pair of operations like double and halve. – dan04 Dec 04 '21 at 08:22