| Bytes | Lang | Time | Link |
|---|---|---|---|
| 058 | Scratch 3.0 + Pen extension | 241225T183249Z | madeforl |
| nan | 241125T211618Z | Mark Jer | |
| nan | 241017T165813Z | ccprog | |
| nan | 241015T214758Z | General | |
| nan | 241016T202552Z | Jordan | |
| 738 | Python | 241016T112517Z | alephalp |
| nan | 241011T172746Z | ayreguit | |
| nan | 241009T223609Z | Greg Mar | |
| nan | 241010T140202Z | madeforl | |
| nan | 241010T015259Z | south | |
| nan | 241010T004245Z | Neil | |
| nan | 241009T124041Z | Luis Men |
Floater (385 pixels)
Enlarged:
Image after execution:
Higher fidelity shot by changing the first pushed value from 6 to 12:
Bonus work-in-progress shot:
[Edit] Actually this can be smaller, but right now I can't be bothered. I spotted an unused value initialized on memory location 4.
HTML+CSS
The animation, depending on device performance, might give a few artifacts and obscure a bit which ring is drawn in front of which one. (which actually is fine, since otherwise it might be more obvious this solution is not really perfect.)
Edit: Tweaked the nature of the animation and the order of the rings in such a way that they are now mostly correctly aligned.
@property --r {
syntax: "<number>";
inherits: true;
initial-value: 0;
}
body {
display: flex;
justify-content: center;
}
.base {
width: 400px;
animation: grow 1s linear infinite;
}
.ring {
position: absolute;
width: 400px;
height: 400px;
transform-style: preserve-3d;
transform: rotateX(60deg) rotateZ(-20deg);
}
.ring::before {
content: "";
position: absolute;
width: calc((var(--s) + var(--r)) * 100px);
height: calc((var(--s) + var(--r)) * 100px);
top: calc(200px - (var(--s) + var(--r)) * 50px);
left: calc(200px - (var(--s) + var(--r)) * 50px);
border: 6px solid hsl(calc((var(--s) + var(--r)) * 1rad) 100% 50%);
border-radius: 50%;
clip-path: inset(calc((var(--s) + var(--r)) * 50px - 200px));
transform: translateZ(calc(sin((var(--s) + var(--r)) * 1rad) * 100px))
}
@keyframes grow {
from { --r: 0 }
to { --r: 0.2 }
}
<div class="base">
<div class="ring" style="--s: 4.8"></div>
<div class="ring" style="--s: 4.6"></div>
<div class="ring" style="--s: 5"></div>
<div class="ring" style="--s: 4.4"></div>
<div class="ring" style="--s: 5.2"></div>
<div class="ring" style="--s: 4.2"></div>
<div class="ring" style="--s: 5.4"></div>
<div class="ring" style="--s: 4"></div>
<div class="ring" style="--s: 5.6"></div>
<div class="ring" style="--s: 3.8"></div>
<div class="ring" style="--s: 3.6"></div>
<div class="ring" style="--s: 3.4"></div>
<div class="ring" style="--s: 3.2"></div>
<div class="ring" style="--s: 0"></div>
<div class="ring" style="--s: 3"></div>
<div class="ring" style="--s: 0.2"></div>
<div class="ring" style="--s: 2.8"></div>
<div class="ring" style="--s: 0.4"></div>
<div class="ring" style="--s: 2.6"></div>
<div class="ring" style="--s: 0.6"></div>
<div class="ring" style="--s: 2.4"></div>
<div class="ring" style="--s: 0.8"></div>
<div class="ring" style="--s: 2.2"></div>
<div class="ring" style="--s: 1"></div>
<div class="ring" style="--s: 2"></div>
<div class="ring" style="--s: 1.2"></div>
<div class="ring" style="--s: 1.8"></div>
<div class="ring" style="--s: 1.4"></div>
<div class="ring" style="--s: 1.6"></div>
</div>
If you want the HTML part a bit more compact, preprocessing with Pug will help; see it live.
Microsoft Excel
This is not at all optimized for character count, but that's not really a criterion for this one anyway.
Speed Optimizations:
- Originally, I had a plot function that plotted a single point at a time. This required copying the entire "canvas" every time I wanted to plot a point, which was O(n2m2), where n and m are canvas and sample area widths respectively.
- Then I realized I could just make a sorted lookup table for the points (sort is both for depth buffer and lookup efficiency). Now it's O(n2 log(m) + m2), assuming the sort is sub-O(m2) and sorted lookups is O(log m).
- Sorting by numeric values is way faster than sorting by text values, which is why I'm multiplying by 1000. Using a comma-separated string takes over twice as long.
MATCHwith 2INDEXes is about 2x faster than 2VLOOKUPs.
=LET(
tableWidth,80,
resX,0.0625,resY,0.0625,
width,8,
dimX,width/resX,
dimY,width/resY, thX,RADIANS(30),
thZ,RADIANS(60),
scale,8,
sX,SIN(thX),cX,COS(thX),
sZ,SIN(thZ),cZ,COS(thZ),
rotMatrix,VSTACK(
HSTACK(cX,-sX*cZ,sX*sZ),
HSTACK(sX,cX*cZ,-cX*sZ),
HSTACK(0,sZ,cZ)
),
z,LAMBDA(i,j,SIN(SQRT(i*i+j*j))),
plotAll,LAMBDA(pts,
LET(
zBufs,MAP(pts,LAMBDA(pt,0+INDEX(TEXTSPLIT(pt,"|"),1))),
coords,MAP(pts,LAMBDA(pt,0+INDEX(TEXTSPLIT(pt,"|"),2))),
vals,MAP(pts,LAMBDA(pt,0+INDEX(TEXTSPLIT(pt,"|"),3))),
sorted,SORT(SORT(HSTACK(zBufs,coords,vals),1,1),2,1),
indexCol,CHOOSECOLS(sorted,2),
valueCol,CHOOSECOLS(sorted,3),
MAKEARRAY(tableWidth,tableWidth,LAMBDA(row,col,
LET(
id,1000*col+row,
check,MATCH(id,indexCol,1),
IF(IFNA(INDEX(indexCol,check),2)=id,INDEX(valueCol,check),"")
)
))
)
),
plotAll(
TOCOL(MAKEARRAY(dimX,dimY,LAMBDA(row,col,
LET(
i,(col-1)*resX-width/2,
j,(row-1)*resY-width/2,
k,z(i,j),
newPt,MMULT(rotMatrix,VSTACK(i*scale,j*scale,k*scale)),
INDEX(newPt,3)&"|"
&(1000*ROUND(40+INDEX(newPt,1),0)
+ROUND(30+INDEX(newPt,2),0))&"|"
&k
)
)))
)
)
I added a Color Scale formatter for ease of viewing.
Google Sheets port
=LET(
tableWidth,80,
resX,0.0625,resY,0.0625,
width,8,
dimX,width/resX,
dimY,width/resY,
thX,RADIANS(30),
thZ,RADIANS(60),
scale,8,
sX,SIN(thX),cX,COS(thX),
sZ,SIN(thZ),cZ,COS(thZ),
rotMatrix,{
{cX,-sX*cZ,sX*sZ};
{sX,cX*cZ,-cX*sZ};
{0,sZ,cZ}
},
z,LAMBDA(i,j,SIN(SQRT(i*i+j*j))),
plotAll,LAMBDA(pts,
LET(
sorted,SORT(pts,1,1,2,1),
indexCol,CHOOSECOLS(sorted,1),
valueCol,CHOOSECOLS(sorted,3),
MAKEARRAY(tableWidth,tableWidth,LAMBDA(row,col,
LET(
id,1000*col+row,
check,MATCH(id,indexCol,1),
IF(IFNA(INDEX(indexCol,check),2)=id,INDEX(valueCol,check),"")
)
))
)
),
plotAll(
MAKEARRAY(dimX*dimY,1,LAMBDA(ptNo,_,
LET(
i,MOD(ptNo,dimX)*resX-width/2,
j,INT(ptNo/dimX)*resY-width/2,
k,z(i,j),
newPt,MMULT(rotMatrix,VSTACK(i*scale,j*scale,k*scale)),
{1000*ROUND(40+INDEX(newPt,1),0)
+ROUND(30+INDEX(newPt,2),0),INDEX(newPt,3),k}
)
))
)
)
Port notes:
- Google Sheets
SORTis capable of multi-column sort. All it needs is the column indexes, which is nice. - Sheets accepts variables in array literals, so no need to do as many H/VSTACKs. There's just the one I can't get rid of because it errors for some reason.
- You can also return nested arrays with array lambdas, so no need to do any parsing.
- Google Sheets' render time is faster than Excel's somehow (theweb-app seems to be about as fast as the Desktop version). Whatever Google is doing in its lookup algorithms, it's much more optimized.
JavaScript
This was generated almost entirely by v0, an LLM programming assistant. I'm marking it as community wiki since there's currently no consensus on AI-generated answers. Maybe this will get some discussion moving.
After clicking on "Run code snippet" below you might have to scroll the iframe to see the hat. Click on "Full page" to see a bigger view of it.
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
function drawPlot(rotationX, rotationY) {
ctx.clearRect(0, 0, width, height);
const scale = Math.min(width, height) / 8;
const centerX = width / 2;
const centerY = height / 2;
// Create a depth buffer to handle overlapping points
const depthBuffer = new Array(width * height).fill(Infinity);
for (let x = -4; x <= 4; x += 0.1) {
for (let y = -4; y <= 4; y += 0.1) {
const distance = Math.sqrt(x * x + y * y);
const z = Math.sin(distance);
// 3D rotation
const rotatedX = x * Math.cos(rotationY) + y * Math.sin(rotationY);
const rotatedY = -x * Math.sin(rotationY) * Math.sin(rotationX) + y * Math.cos(rotationY) * Math.sin(rotationX) + z * Math.cos(rotationX);
const rotatedZ = x * Math.sin(rotationY) * Math.cos(rotationX) - y * Math.cos(rotationY) * Math.cos(rotationX) + z * Math.sin(rotationX);
// Project 3D to 2D
const screenX = Math.round(centerX + rotatedX * scale);
const screenY = Math.round(centerY - rotatedZ * scale);
// Check if this point is closer than the previous point at this pixel
const bufferIndex = screenY * width + screenX;
if (screenX >= 0 && screenX < width && screenY >= 0 && screenY < height && rotatedY < depthBuffer[bufferIndex]) {
depthBuffer[bufferIndex] = rotatedY;
// Map z value to color
const r = Math.floor(255 * (0.5 + 0.5 * Math.sin(Math.PI * z)));
const g = Math.floor(255 * (0.5 + 0.5 * Math.cos(Math.PI * z / 2)));
const b = Math.floor(255 * (0.5 + 0.5 * Math.sin(Math.PI * z / 4)));
// Apply depth shading
const depthFactor = 0.5 + (rotatedY + 4) / 8; // Normalize to 0.5-1 range
ctx.fillStyle = `rgb(${r * depthFactor},${g * depthFactor},${b * depthFactor})`;
ctx.fillRect(screenX, screenY, 2, 2);
}
}
}
}
let rotationY = 0;
function animate() {
drawPlot(Math.PI / 2.5, rotationY);
rotationY += 0.01;
requestAnimationFrame(animate);
}
animate();
body{background-color: #1a202c;}
<canvas id=canvas width=800 height=600></canvas>
Python, 738 bytes
import math
data = [[' '] * 100 for _ in range(30)]
for i in range(81):
for j in range(81):
x = -4 + i * 0.1
y = -4 + j * 0.1
r = math.sqrt(x**2 + y**2)
z = math.sin(r)
# normal vector
length = math.sqrt(1 + math.cos(r)**2)
nx = -x * math.cos(r) / r / length if r else 0
ny = -y * math.cos(r) / r / length if r else 0
nz = 1 / length
# light intensity
light = (ny + nz) / math.sqrt(2)
char = " .-:=+*#%@"[int(light * 10)]
# project to screen
screen_x = 50 - round(x * 6 - y * 6)
screen_y = 12 - round(z * 5 - x * 1.5 - y * 1.5)
data[screen_y][screen_x] = char
for row in data:
print(''.join(row))
ASCII art with simple lighting.
==++*******++
:+**###%%%%%###########**
-:+**##%%@%@@@%%%%%####****#####*
.-:=+*##%%@@@@@@@@@%%##***++++**######*
.::=+**###%%%@@@@@@@%%#**+=====+**##%%%%#
.--:==++**#####%@@@@@@%##*=::::=+**#%%%%%%%%%*
.--::==+++***###**+@@@@%#++-:=+**##%%@@@@@@@%%%##
..--::===+++****#########*######%%%%%@@@@@@@@@@@%%%#
. ..--:::===+++***#######%%%%%%%%%%@@@@@@@@@@@@@@@@@%%%###
:......---:::===+++****#####%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@%%%%###
=:--....----:::===++++****#####%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@%%%%####
*+=:----.-----::::====+++****######%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%####
%%%%%%%##**==:--------::::=====++++****######%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%###*+==::--
%%%%%%#**+==::::---:::::====+++++*****######%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%##*+==:--
%%%%###*++==::::::::::=====+++++*****######%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%#**++:::
%%###**+++==:::::=======++++++****#######%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%###*+==
###**+++==========+++++++******#######%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%##**
***++++++++=+++++++++*******#######%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%#
+++++++++++*********#######%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++**********#########%%%%%%%%%@@@@@@@@@@@@@@@@@@@@@
****###########%%%%%%%%%%%@@@@@@@@@@@@@@@@@
###########%%%%%%%%%%%%@@@@@@@@@@@@@@
#########%%%%%%%%%%%%%%%%%%%%%%@@
###########%%%%%%%%%%####%%
##*++==::----::=++*##
Thumby MicroPython
import thumby
import math
while 1:
m=[-100]*72
thumby.display.fill(0)
ry=(y/4 for y in range(-16, 17))
for y in ry:
a=2*y
rx=(x/4 for x in range(-16, 17))
for x in rx:
z=12*math.sin(math.sqrt(x*x+y*y))
x1=int(x*4+a)
y1=int(z+a)
if y1>m[x1]:
m[x1]=y1
thumby.display.setPixel(x1+36,18-y1,1)
thumby.display.update()
Thumby is a tiny device the size of your thumb, programmed in Micropython with 72x40 pixel black & white screen. Try the above code by copy/pasting into the emulator here and clicking RESTART (assuming your browser can cope - works with most Chrome based browsers)
Wolfram Language (Mathematica)
Plot3D[Sin@Norm@{,y},{,-4,4},{y,-4,4}]
Mostly the obvious implementation, although Norm is a short way to access the square root of the sum of squares, and I did remember to save 2 bytes by letting one of the variables be the invisible Nulls before the commas (not that this is code-golf, but habits die hard) :p
YASEPL
this is a translation of Neil's answer in ZX Spectrum BASIC. really cool dude!
=i£1`1!1©0!+}2,255$-5`2=j-4`3!o$j^!z$i^+o&≈0,z!o$j*4!x$i*16+128-o!o$j*8!l$z*32!y$i*2+96+o+l!q$x(!r$y(!t¥q,1}5,y,4!1¤x,y!p$27›$91›!r/3(!n$50-r~!p$59›!q/2(~#"H">"o"`4!h$/4!j+h}2,4,3!h$/16!i+h}2,4,2
how it works:
=i£1`1!1©0!+}2,255 - create list1 with 255 0s
$-5 - set I to -4
`2 - do {
=j-4 - set J to -4
`3 - do {
!o$j^!z$i^+o&≈0,z - set Z to sin(sqrt(I^2+J^2))
!o$j*4!x$i*16+128-o - set X to (I*16)+128-(J*4)
!o$j*8!l$z*32!y$i*2+96+o+l - set Y to (I*2)+96+(J*8)+(Z*32)
!q$x(!r$y( - set Q & R to integer versions of X and Y
!t¥q,1}5,y,4 - if list1(Q) < Y {
!1¤x,y - set list1(X) to Y
!p$27›$91›!r/3(!n$50-r~!p$59›!q/2(~#"H">"o" - plot Q and R on places on the screen
`4 - }
!h$/4!j+h - J += 0.25
}2,4,3 - } while J < 4
!h$/16!i+h - I += 0.0625
}2,4,2 - } while I > 4
J plot
plot _4 4([;;)'1 o.|@j.'
For more information on how function plots work, see wiki/Plot/Function. For the golfers, this is 24 bytes.
plot _4 4([;;)'1 o.|@j.'
'1 o.|@j.' NB. string repr of a dyadic fork used by plot
|@j. NB. magnitude of the complex number xjy
1 o. NB. sin
_4 4 NB. plot range
([;;) NB. dyadic fork
; NB. build a boxed list of _4 4 and the function string
[ NB. _4 4
; NB. box again
plot NB. plot
ZX Spectrum Basic
Very Slow Program
Output
Less Slow Program
Output
Sorry for source screenshots but I was too lazy to retype everything.
MATL
KUQ_ZvqK/t!YyY,lYH
Try it at MATL Online!
Some obscure features:
- The code does not use any numeric characters;
- The hat plot is rather dark;
- The language itself?
How it works
KUQ % Push 4, square, add 1: gives 17
_Zv % Symmetric range: gives row vector [17 16 ... 2 1 2 ... 16 17]
q % Subtract 1, element-wise: gives [16 15 ... 1 0 1 ... 15 16]
K/ % Divide by 4, element-wise: gives [4. 3.75 ... 0.25 0 0.25 ... 3.75 4]
t! % Duplicate, transpose
Yy % Hypotenuse (square root of sum of squares), with implicit expansion.
% Gives a square matrix
Y, % Sine, element-wise
lYH % Plot as surface














