Java (JDK), 153 bytes
v->{var s=0;for(var c:"HJ!DR!BV!AGBFBG!AX!@Z!@Z!@ECJCE!AECICE!AFLF!BV!DR!HJ".getBytes())System.out.print("\n* ".split("")[c/64+(s^=c/64)].repeat(c%32));}
Explanation
The idea is to have toggle, s
, which will tell us when to print spaces or stars. The number of those spaces or spaces is defined by theeach character used in the long string. Any letter is their corresponding number (A=1, B=2, ...
), @
actually is zero, and !
also means 1, but it's in a lower range than A
to know when to go to the next line.
We can see the smiley as a sequence of [0,26] spaces followed by stars [1,26], possibly repeated. This makes sure that if we provide 2 chars, the first char represent the spaces and the second char represent the stars. This toggling is done using s^=1
.
But it happens that I have to insert new lines in that sequence. A new character would then mess up with that s^=1
, so I changed that to s^=c/64
, meaning that only letters and @
actually trigger the toggle, while !
result in s^=0
which is a no-op.
s |
c |
s^(c/64) |
c/64+(s^(c/64)) |
Result |
---|---|---|---|---|
0 |
! |
0 |
0 |
\n |
0 |
[@-Z] |
1 |
2 |
(space) |
1 |
! |
1 |
01 |
Never occurs |
1 |
[@-Z] |
0 |
1 |
* |
After the character is selected (but kept as a string, not as a character), it is repeated c%32
times. It is to note that '!' % 32 = 33 % 32 = 1
and '@' % 32 = 64 % 32 = 0
. Java's .repeat(0)
will indeed result in the empty string (""
).