PNG  IHDR!@ PLTE>O`jqv MltEXtPage
Turn the background from 2D to 3D - metalympiada
git clone git://metalympiada.org/
Log | Files | README | LICENSE

commit 6005300a6d6d37296a0a236b5e7e292bea3f601e
parent f24996017e337c8f6d5b2de19979d6a17e03ad41
Author: Metalympiáda <metalympiada@matfyz.cz>
Date:   Mon,  6 May 2024 14:48:54 +0200

Turn the background from 2D to 3D

Diffstat:
Mpngenerator.c | 113++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mroutes.scm | 2+-
Mtexts/problems | 4++--
3 files changed, 101 insertions(+), 18 deletions(-)

diff --git a/pngenerator.c b/pngenerator.c @@ -1,14 +1,48 @@ +#include <math.h> #include <png.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -const uint16_t WIDTH = 256; -const uint16_t HEIGHT = 222; -const uint16_t ITERATIONS = 5020; +#define WIDTH 256 +#define HEIGHT 256 +const uint16_t ITERATIONS = 201; +const uint16_t MAX_STEPS = 14; +const double MIN_DISTANCE = 0.008; const size_t CAPACITY = 16384; +typedef struct vec3 { + double x, y, z; +} vec3; + +static vec3 vec3_add(const vec3 a, const vec3 b) { + vec3 v = {a.x + b.x, a.y + b.y, a.z + b.z}; + return v; +} + +static vec3 vec3_sub(const vec3 a, const vec3 b) { + vec3 v = {a.x - b.x, a.y - b.y, a.z - b.z}; + return v; +} + +static vec3 vec3_mult(const vec3 a, const double c) { + vec3 v = {c*a.x, c*a.y, c*a.z}; + return v; +} + +static double sqnorm(const vec3 v) { + return v.x*v.x + v.y*v.y + v.z*v.z; +} + +static double norm(const vec3 v) { + return sqrt(sqnorm(v)); +} + +static double vec3_sqdist(const vec3 v, const vec3 w) { + return sqnorm(vec3_sub(v, w)); +} + typedef struct slice { char* buffer; size_t len; @@ -50,11 +84,18 @@ pngenerate(char * const text, const uint32_t background, const uint32_t foregrou png_infop info_ptr = png_create_info_struct(png_ptr); png_set_compression_level(png_ptr, 9); - const png_color palette[2] = {num2col(background), num2col(foreground)}; - png_set_IHDR(png_ptr, info_ptr, WIDTH, HEIGHT, 1, PNG_COLOR_TYPE_PALETTE, + png_color b = num2col(background), f = num2col(foreground); + png_color step = {(f.red - b.red) / 4, (f.green - b.green) / 4, (f.blue - b.blue) / 4}; + png_color palette[4]; + palette[0] = b; + for (size_t i = 0; i < 3; i++) { + png_color c = {f.red - i*step.red, f.green - i*step.green, f.blue - i*step.blue}; + palette[3 - i] = c; + } + png_set_IHDR(png_ptr, info_ptr, WIDTH, HEIGHT, 2, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - png_set_PLTE(png_ptr, info_ptr, palette, 2); + png_set_PLTE(png_ptr, info_ptr, palette, 4); const png_text page = { .compression = PNG_TEXT_COMPRESSION_NONE, @@ -63,20 +104,62 @@ pngenerate(char * const text, const uint32_t background, const uint32_t foregrou }; png_set_text(png_ptr, info_ptr, &page, 1); - png_bytep buffer = calloc(WIDTH * HEIGHT / 8, sizeof(png_byte)); + png_bytep buffer = calloc(WIDTH * HEIGHT / 4, sizeof(png_byte)); png_bytep rows[HEIGHT]; for (size_t i = 0; i < HEIGHT; i++) - rows[i] = buffer + i * WIDTH / 8; + rows[i] = buffer + i * WIDTH / 4; time_t t; srand((unsigned) time(&t)); - size_t x = rand() % WIDTH, y = rand() % HEIGHT; - for (int i = 0; i < ITERATIONS; i++) { - size_t r = rand() % 3; - x = (x + r*(WIDTH >> 1)) >> 1; - y = (y + ((r&1)^1)*HEIGHT) >> 1; - rows[y][x >> 3] |= 1 << ((x & 7) ^ 7); + vec3 v[4] = {{-sqrt(3), -sqrt(2), -1}, {sqrt(3), -sqrt(2), -1}, {0, -sqrt(2), 2}, {0, sqrt(2), 0}}; + double s = -sqrt(3) * ((double) rand() / RAND_MAX - 0.5); + double c = sqrt(1.0 - s*s); + for (size_t i = 0; i < 3; i++) { + double ox = v[i].x; + v[i].x = c*v[i].x - s*v[i].z; + v[i].z = s*ox + c*v[i].z; + } + for (size_t j = 0; j < HEIGHT; j++) { + for (size_t i = 0; i < WIDTH; i++) { + double x = (double) i * 2 / (double) WIDTH - 1.0; + double y = (double) j * -2 / (double) HEIGHT + 1.0; + vec3 position = {x, y, -1.1}; + vec3 dir = {x, y, 2.2}; + double distance = norm(dir); + const vec3 direction = vec3_mult(dir, 1.0/distance); + + uint16_t steps; + for(steps = 0; steps < MAX_STEPS; steps++) { + double d; + vec3 p = position; + for (int i = 0; i < 9; i++) { + vec3 center = v[0]; + d = vec3_sqdist(p, v[0]); + for (int j = 1; j < 4; j++) { + double di = vec3_sqdist(p, v[j]); + if (di < d) { + d = di; + center = v[j]; + } + } + p = vec3_sub(vec3_mult(p, 2), center); + } + d = sqrt(d) / (double) (1 << 8); + + if (d < MIN_DISTANCE) { + break; + } + distance += d; + if (distance >= 6.0) { + steps = MAX_STEPS; + break; + } + position = vec3_add(position, vec3_mult(direction, d)); + } + char val = (char) (3.6 - 3.0*steps/MAX_STEPS) & 3; + buffer[j*(WIDTH >> 2) + (i >> 2)] |= val << (((i & 3) ^ 3) << 1); + } } png_set_rows(png_ptr, info_ptr, rows); @@ -90,7 +173,7 @@ int main() { FILE* fp = fopen("test.png", "wb"); - const slice s = pngenerate("Hello!!<img src=\"#\">", 0x002a1c, 0x143e30); + const slice s = pngenerate("<h1>Title</h1>Hello!!<img src=\"#\">", 0x153e4f, 0x118282); fwrite(s.buffer, 1, s.len, fp); fclose(fp); return 0; diff --git a/routes.scm b/routes.scm @@ -143,7 +143,7 @@ (hr)))) (archive-problems a) (archive-solutions a) - (iota (length problems)))))))) + (iota (length (archive-problems a))))))))) (define (score-page rnd) (let ((results (select-results rnd)) diff --git a/texts/problems b/texts/problems @@ -2,7 +2,7 @@ Ivana ovládol prúd nekontrolovateľnej zúrivosti na autorov Metalympiády, pr Na to Ivan odvetil:`To mi je na milú Jarmilu, vy oplanci sopľaví!' Nuž teda autori boli nútení ďalej napovedať. `Riešením prvej úlohy bude počet riešiteľových číselných odpovedí na toto kolo Metalympiády s párnou hodnotou.' `Nateraz vám odpúšťam. Trúby...' -~Boris cestoval vlakom, kde sa mu zjavil boh. Poprosil boha o zdelenie tajomstva vesmíru, v ktorom sa nachádza a boh naňnho prehovoril. +~Boris cestoval vlakom, kde sa mu zjavil boh. Poprosil boha o zdelenie tajomstva vesmíru, v ktorom sa nachádza a boh naňho prehovoril. `Toto je (2, 3, 1).' Borisovi bolo ihneď jasné, že pre túto úlohu mu zdelené poznanie nebude relevantné a poslal boha k čertom. Povzdychol si. `Ach, keby mi bol radšej povedal súčet číselných odpovedí na úlohy tohto kola Metalympiády!' Aké je hodnota čísla, ktoré by sa Boris radšej dozvedel od boha? @@ -17,7 +17,7 @@ Vyriešte Jolaninu úlohu. ~(4, 6, 1)(3, 2, 13)(2, 4, 8)(4, 1, 5)(8, 2, 9)(6, 1, 6)(2, 6, 12)(3, 1, 9)(3, 2, 16)(3, 5, 14)(1, 3, 5)(3, 5, 3) ~Boris vyvinul revolučnú umelú inteligenciu MetatronGPT postavenú na blockchaine, ktorá vie rozhodovať o pravdivosti slovenských viet. Nie vždy rozozná pravdivú vetu, ale vždy, keď nejakú vetu rozozná ako pravdivú, je takou naozaj. Napíšte pravdivú vetu, ktorú MetatronGPT nerozozná ako pravdivú. -~Vladislav si kúpli lístok na prehliadku trikov slávneho kúzelníka Metapokustóna. Vystúpenie sa Metapokustón rozhodol začať svojim slávnym číslom s hypnotizovaním leva. +~Vladislav si kúpil lístok na prehliadku trikov slávneho kúzelníka Metapokustóna. Vystúpenie sa Metapokustón rozhodol začať svojim slávnym číslom s hypnotizovaním leva. Metapokustón doviezol klietku s levom a otvoril ju. Lev vyskočil vonku a zakúsol sa kúzelníkovi do ľavej ruky. Kúzelník začal kričať a dav začal tlieskať. Lev začal Metapokustóna hádzať po zemi, zatiaľ čo kričal:`Pomóc! Toto nie je show! Som vážne zranený! Je to hrozná bolesť! Prosím, pomôžte mi niekto!' Nakoniec kúzelníka lev celého zožral. Vladislav bol trikom veľmi ohromený, ale stále nemohol prísť na to, v čom trik spočíval. Vie však, že kúzelníci svoje tajomstvá nikdy neprezrádzajú.
/o:IDATxoGv[j*M0ˀ&d<<4gf"o baH@Kt B^^@\ @.{aqk` k$O|Pq!Cɚu~k,_^;mKu( ^JHXp_L ^ `/k,@[,[HZHDq9?XD "lhXÚE9WBR'hmĠ7Z55-w!@J # DUjnwt") s4`-۟s r5+@c)ikNK8yC>$;snmJ&ڼ%[-w2oDy#\ >'@|-Ё0QZ[|i6HM;9oi1\ o!|!ig'>:,1+1lRUT:Aw㍸:aVPDkc-a>]_ks ̐sP~/I|lɍr6Om9ȣ@)|X(# a[pi(MY֌r-%| XէrcMD[31ʃw`T[waD̦'p+$D򌀵S]KS'YbF@ gXbRj9w4-hwzӲgJ_fE:`(.2Y+{ 6 i=;mV0N `oC!A8aƀ`g{=LJ;S@`]*%@K>$bg`'UpX.F˚`a|׍Ehxaflc3Ѧ҈< fp6!vg3xxYzMcv ʰ\` K.wNv % Je1$34`@a @fPfJCưv Lǀ01O\td*>7XcBSN;n MHZc 3Jޜ`Q$"POȜ`sj)8eH ʮī8 * Ct,|-DžhF? :Syr8ְBkk ( :K9}h1k soʠX> @g 9%`Icu$0>ŵ- =a&XRM)Do6Z9U?&wL-J?0)$\)My{ ۚw)h~M'> L!֊gYTFEU^c?Vk't[pm㲸\vN 1}unk&_oZ _N9F/M1Qֿn:Yŵtw)e:@O(hQ|CX;yU7=^-pLǽ^ u>Ǫz8ߤEwVz?V:iYuk,k=̪[cu+RJ1pރL.3n`qJJQ;+O•Fٖ /}5 bbkֲk+g?-֨8&֯Ir?͢1*=*X_eKQisԾ߲jǠG(^W)q4Cp-K0ы@L3vU'CJ֣U3y+qeCtlju(~Co2`iÆMJxpBUuK= p|KO&Sph˻E2,%o 1ފQ˔~xZ[;z7-/ ;l'Rԉ{Ǔ;zL'Bӧ%PKO鳿-t`_᎞ȍ}[wET&R$kO?=/JOV=! dځw)ˢhwN ~3LxD_(EXǯ^?\R-<`ub 0 .N= *Gu_=]'$_/&4-v œLq%Zc<~|A N<^A_M `h);Z uϗ &d#y=#~}Z5`Js=Pg1YD,w!g+<7EbИ^'dX#p|r"4Zӓ2t #>'ՓeEib63op$xҾ;q͖5:<X}X@[l!nS7{`-{ \e'Y t4~d<`E6ucj%T do2okszc>>b*RSEI[Szީ'I`?7"KXĔI)F{_5-Cq8ҷ-VYNqI| R %c nhs6eZ8^) oKT TQa¸r._+"# ~a5;ox 3ۡNdJRAyV- /yb:`t+v(ˍ꿠1V3FmF  뻢`+\zYi7DeeE )TyE?R#mBTC?Jx!e\ }4׹5H 4Hu?z|y uP˂GTizBVe|/jP#*-M!P(UIaWI `hi*ʊp0d *ʀA0}F9<[In{| #pbQ vurW$[ 7%̓0}ŷ1h{2n"g==Yˡ.;Z03<.ihV6Q P&NOgTCg}=Y 22=!NTz90W_?fe1];fkN F"׷y$>;b :)BI/#-~ RZ5>PVM4Yp@)>4eۄ#X!eП hX."`(;b(p򤐰_/zjK{Jnu,ZRJA< NQPt(6a--t8Ar/%"?ԘuSɕ˔uXckWJѝσa|mw7;b jK[e?,'&a?tlǏ똘h ,Jtg XkV,01 r&+^B\}Y9TmmmeaR!:.,Sx9T-˭@Rˁ0q և+PhUIKhu& dY@E'Tv^j@Ao)8(,۳l>tn MOJ7=(-#!Q*ə # փN[>m4ʔ;΀t+KmBT7RN %*Pfy}@dϠƠ%j<wFzjt nܥv2 \M_팴w5쪔nD'!ĥΩXOrx56_L܁ rC0w?/=0)5\p;W `V yQ! f}(b*o]1_rGXQmIENDB`