昨晚在微信公众号看到 《有没有一段代码,让你觉得人类的智慧也可以璀璨无比》里面介绍了一个叫《Tweetable Mathematical Art》的代码游戏,看完我激动不已,这些人都太NB了。
我迫不及待要试一下,可惜该代码游戏原来的框架生成的图片是ppm格式的,ppm格式的图片在Windwos上打开比较麻烦,所以我索性写了一个生成bmp格式的代码框架。
在这个代码框架下,如果有新idea,只需在body.hpp中加入一个新类,然后用REG注册,就可以生成新的图片了。
这个代码框架支持gcc和msvc.
pic.hpp
#ifndef _PIC_HPP_
#define _PIC_HPP_
#include <cstdio>
#include <cstring>
class pic {
public:
pic() {}
virtual ~pic() {}
// ----x--------->
// |
// y
// |
// v
virtual void set(unsigned int x, unsigned int y, unsigned char r, unsigned char g, unsigned char b) = 0;
bool save(const char * fname) {
char * new_name = new char[strlen(fname) + strlen(ext) + 2];
sprintf(new_name, "%s.%s", fname, ext);
FILE * f = fopen(new_name, "wb");
delete [] new_name;
if(f == NULL)
return false;
fwrite(p, 1, sz, f);
fclose(f);
return true;
}
protected:
unsigned char * p;
unsigned int sz;
unsigned int w;
unsigned int h;
char ext[8];
};
class ppm : public pic {
public:
ppm(unsigned int width, unsigned int height) {
w = width & 0xFFF;
h = height & 0xFFF;
char hdr[64];
sprintf(hdr, "P6\n%u %u\n255\n", w, h);
hdr_offset = strlen(hdr);
sz = hdr_offset + (w * 3 * h);
p = new unsigned char[sz];
memcpy(p, hdr, hdr_offset);
memset(p + hdr_offset, 0xFF, sz - hdr_offset);
strcpy(ext, "ppm");
}
~ppm() { delete [] p; }
void set(unsigned int x, unsigned int y, unsigned char r, unsigned char g, unsigned char b) {
if(x < w && y < h) {
unsigned int offset = hdr_offset + (w * 3 * y) + (x * 3);
p[offset] = r;
p[offset + 1] = g;
p[offset + 2] = b;
}
}
private:
unsigned int hdr_offset;
};
class bmp : public pic {
public:
bmp(unsigned int width, unsigned int height) {
w = width & 0xFFF;
h = height & 0xFFF;
w3 = (w * 3 + 3) & ~3;
sz = 54 + (w3 * h);
p = new unsigned char[sz];
memset(p, 0, 54);
memset(p + 54, 0xFF, sz - 54);
p[0] = 'B';
p[1] = 'M';
p[2] = sz;
p[3] = sz >> 8;
p[4] = sz >> 16;
p[5] = sz >> 24;
p[10] = 54;
p[14] = 40;
p[18] = w;
p[19] = w >> 8;
p[22] = h;
p[23] = h >> 8;
p[26] = 1;
p[28] = 24;
p[34] = sz - 54;
p[35] = (sz - 54) >> 8;
p[36] = (sz - 54) >> 16;
p[37] = (sz - 54) >> 24;
strcpy(ext, "bmp");
}
~bmp() { delete [] p; }
void set(unsigned int x, unsigned int y, unsigned char r, unsigned char g, unsigned char b) {
if(x < w && y < h) {
unsigned int offset = 54 + w3 * (h - 1 - y) + x * 3;
p[offset] = b;
p[offset + 1] = g;
p[offset + 2] = r;
}
}
private:
unsigned int w3;
};
#endif
core.hpp
#ifndef _CORE_HPP_
#define _CORE_HPP_
#include <cstdio>
#include <cstdlib>
#include <cstring>
struct core {
core():DIM(1024) {}
virtual ~core() {}
virtual unsigned char RD(int i, int j) = 0;
virtual unsigned char GR(int i, int j) = 0;
virtual unsigned char BL(int i, int j) = 0;
unsigned int DIM;
};
typedef core * (*CTOR)();
struct name_ctor {
char name[64];
CTOR ctor;
};
static name_ctor nc[128];
static unsigned int nc_num = 0;
static int reg_nc(const char * name, CTOR ctor){
if(strlen(name) >= sizeof(nc[0].name) || nc_num >= sizeof(nc)/sizeof(nc[0])) {
printf("Error at %s line %d\n", __FILE__, __LINE__);
exit(1);
}
strcpy(nc[nc_num].name, name);
nc[nc_num].ctor = ctor;
nc_num++;
return 0;
}
#define REG(NAME) \
static core * NAME##_ctor_() { return new NAME; } \
static int NAME##_reg_ = reg_nc(#NAME, NAME##_ctor_);
#endif
body.cc
#ifndef _BODY_HPP_
#define _BODY_HPP_
#include "core.hpp"
#include <cmath>
#define _sq(x) ((x)*(x)) // square
#define _cb(x) abs((x)*(x)*(x)) // absolute value of cube
#define _cr(x) (unsigned char)(pow((x),1./3)) // cube root
struct colorful : public core {
unsigned char RD(int i,int j){
return (char)(_sq(cos(atan2(j-512.,i-512)/2))*255);
}
unsigned char GR(int i,int j){
return (char)(_sq(cos(atan2(j-512.,i-512)/2-2*acos(-1.)/3))*255);
}
unsigned char BL(int i,int j){
return (char)(_sq(cos(atan2(j-512.,i-512)/2+2*acos(-1.)/3))*255);
}
};
REG(colorful);
struct flat : public core {
unsigned char RD(int i,int j){
float s=3./(j+99);
return (int((i+DIM)*s+j*s)%2+int((DIM*2-i)*s+j*s)%2)*127;
}
unsigned char GR(int i,int j){
float s=3./(j+99);
return (int((i+DIM)*s+j*s)%2+int((DIM*2-i)*s+j*s)%2)*127;
}
unsigned char BL(int i,int j){
float s=3./(j+99);
return (int((i+DIM)*s+j*s)%2+int((DIM*2-i)*s+j*s)%2)*127;
}
};
REG(flat);
struct ripple : public core {
unsigned char RD(int i,int j){
float s=3./(j+99);
float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s;
return (int((i+DIM)*s+y)%2+int((DIM*2-i)*s+y)%2)*127;
}
unsigned char GR(int i,int j){
float s=3./(j+99);
float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s;
return (int((i+DIM)*s+y)%2+int((DIM*2-i)*s+y)%2)*127;
}
unsigned char BL(int i,int j){
float s=3./(j+99);
float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s;
return (int((i+DIM)*s+y)%2+int((DIM*2-i)*s+y)%2)*127;
}
};
REG(ripple);
struct cripple : public core {
unsigned char RD(int i,int j){
float s=3./(j+99);
float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s;
return (int((i+DIM)*s+y)%2+int((DIM*2-i)*s+y)%2)*127;
}
unsigned char GR(int i,int j){
float s=3./(j+99);
float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s;
return (int(5*((i+DIM)*s+y))%2+int(5*((DIM*2-i)*s+y))%2)*127;
}
unsigned char BL(int i,int j){
float s=3./(j+99);
float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s;
return (int(29*((i+DIM)*s+y))%2+int(29*((DIM*2-i)*s+y))%2)*127;
}
};
REG(cripple);
struct randx: public core {
#define r(n)(rand()%n)
unsigned char RD(int i,int j){
static char c[1024][1024];return!c[i][j]?c[i][j]=!r(999)?r(256):RD((i+r(2))%1024,(j+r(2))%1024):c[i][j];
}
unsigned char GR(int i,int j){
static char c[1024][1024];return!c[i][j]?c[i][j]=!r(999)?r(256):GR((i+r(2))%1024,(j+r(2))%1024):c[i][j];
}
unsigned char BL(int i,int j){
static char c[1024][1024];return!c[i][j]?c[i][j]=!r(999)?r(256):BL((i+r(2))%1024,(j+r(2))%1024):c[i][j];
}
};
REG(randx);
struct omg1: public core {
unsigned char RD(int i,int j){
float x=0,y=0;int k;for(k=0;k++<256;){float a=x*x-y*y+(i-768.0)/512;y=2*x*y+(j-512.0)/512;x=a;if(x*x+y*y>4)break;}return k>31?256:k*8;
}
unsigned char GR(int i,int j){
float x=0,y=0;int k;for(k=0;k++<256;){float a=x*x-y*y+(i-768.0)/512;y=2*x*y+(j-512.0)/512;x=a;if(x*x+y*y>4)break;}return k>63?256:k*4;
}
unsigned char BL(int i,int j){
float x=0,y=0;int k;for(k=0;k++<256;){float a=x*x-y*y+(i-768.0)/512;y=2*x*y+(j-512.0)/512;x=a;if(x*x+y*y>4)break;}return k;
}
};
REG(omg1);
struct omg2: public core {
unsigned char RD(int i,int j){
double a=0,b=0,c,d,n=0;
while((c=a*a)+(d=b*b)<4&&n++<880)
{b=2*a*b+j*8e-9-.645411;a=c-d+i*8e-9+.356888;}
return 255*pow((n-80)/800,3.);
}
unsigned char GR(int i,int j){
double a=0,b=0,c,d,n=0;
while((c=a*a)+(d=b*b)<4&&n++<880)
{b=2*a*b+j*8e-9-.645411;a=c-d+i*8e-9+.356888;}
return 255*pow((n-80)/800,.7);
}
unsigned char BL(int i,int j){
double a=0,b=0,c,d,n=0;
while((c=a*a)+(d=b*b)<4&&n++<880)
{b=2*a*b+j*8e-9-.645411;a=c-d+i*8e-9+.356888;}
return 255*pow((n-80)/800,.5);
}
};
REG(omg2);
struct size800 : public core {
size800() { DIM = 640; }
unsigned char RD(int i,int j){
return (unsigned short)sqrt((double)(_sq(i-DIM/2)*_sq(j-DIM/2))*2.0);
}
unsigned char GR(int i,int j){
return (unsigned short)sqrt((double)((_sq(i-DIM/2)|_sq(j-DIM/2))*(_sq(i-DIM/2)&_sq(j-DIM/2))));
}
unsigned char BL(int i,int j){
return (unsigned short)sqrt((double)(_sq(i-DIM/2)&_sq(j-DIM/2))*2.0);
}
};
REG(size800);
#endif
main.cc
/*
http://www.zhihu.com/question/30262900
http://www.matrix67.com/blog/archives/6039
http://codegolf.stackexchange.com/questions/35569/tweetable-mathematical-art
*/
#include "body.hpp"
#include "pic.hpp"
int main(int argc, char * argv[]) {
if(argc < 2) {
printf("Usage: %s <-all|name> [bmp|ppm]\n", argv[0]);
printf("name list:\n");
for(unsigned int i = 0; i < nc_num; i++) {
printf("\t%s\n", nc[i].name);
}
return 1;
}
for(unsigned int i = 0; i < nc_num; i++) {
if(strcmp(argv[1], nc[i].name)==0 || strcmp(argv[1], "-all")==0) {
core * c = nc[i].ctor();
pic * p;
if(argc > 2 && strcmp(argv[2],"ppm") == 0) {
p = new ppm(c->DIM, c->DIM);
} else {
p = new bmp(c->DIM, c->DIM);
}
for(unsigned int y = 0; y < c->DIM; y++)
for(unsigned int x = 0; x < c->DIM; x++)
p->set(x, y, c->RD(x,y), c->GR(x,y), c->BL(x,y));
p->save(nc[i].name);
delete p;
delete c;
}
}
return 0;
}
Makefile
ifndef T
A=-all
endif
run :: math_art
./math_art $A
math_art : pic.hpp core.hpp body.hpp main.cc
g++ -Wall main.cc -lm -o math_art
clean ::
rm -f math_art *.bmp *.ppm
build.bat
@echo off
call "C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86
del *.bmp 2>nul
cl main.cc & main.exe -all & del main.obj main.exe
pause