コンソールウィンドウでマンデルブロ集合
Windows のコンソールウィンドウにマンデルブロ集合を表示します。
マウスでぐりぐり動かして、[i] / [o] キーでズームイン / アウト。
暇があればマルチサンプリングで表示を改善したり、コードを整備したりする予定です。
Visual C++ 2010 / Visual Studio 2012 で動作します。実行ファイル (64kB)
// // Mandelbrot Console // Version : 1.0 // Author : @Reputeless, @agehama_ // # include <string> # include <Windows.h> # include <conio.h> struct Vec2 { double x,y; Vec2(){} Vec2( double _x, double _y ): x(_x),y(_y){} }; int Mandelbrot( double a, double b ) { double x=0.0, y=0.0; for(int n=0; n<300; ++n) { const double x1 = x*x - y*y +a; const double y1= 2.0*x*y + b; if(x1*x1 + y1*y1 > 4.0) { return n; // 発散 } x = x1; y = y1; } return 0; } void CreateOutput( int width, int height, std::string& buffer, const Vec2& center, const Vec2& range ) { const Vec2 pixelSize(range.x/width,range.y/height); const Vec2 beginPos(center.x-(pixelSize.x*width/2), center.y-(pixelSize.y*height/2)); for(int y=0; y<height; ++y) { const double py = beginPos.y + pixelSize.y*y; for(int x=0; x<width; ++x) { const double px = beginPos.x + pixelSize.x*x; buffer[y*width+x] = Mandelbrot(px,py) ? '*' : ' '; } } } // マウスカーソルの位置 [0.0,1.0] を返す Vec2 GetMousePos() { RECT rc; ::GetWindowRect(::GetForegroundWindow(),&rc); POINT pos; ::GetCursorPos(&pos); return Vec2(1.0*pos.x/(rc.right-rc.left),1.0*pos.y/(rc.bottom-rc.top)); } class Console { public: Console() : m_center(0.0,0.0),m_scale(4.0),m_aspect(1.0) { ::SetConsoleTitleW(L"Mandelbrot Console / zoom [i]n / zoom [o]ut / [q]uit"); m_console = ::GetStdHandle(STD_OUTPUT_HANDLE); COORD size = ::GetLargestConsoleWindowSize(m_console); ::SetConsoleScreenBufferSize(m_console,size); SMALL_RECT dw = {0,0,size.X-2,size.Y-1}; ::SetConsoleWindowInfo(m_console,TRUE,&dw); m_width = size.X; m_height = size.Y-2; m_aspect = 1.0*m_width/m_height*0.4; ::SetConsoleScreenBufferSize(m_console,size); m_output.resize(m_width*m_height,' '); } ~Console() { ::CloseHandle(m_console); } void draw() { const Vec2 mousePos = GetMousePos(); m_center.x += (mousePos.x-0.5)*m_scale*0.1*m_aspect; m_center.y += (mousePos.y-0.5)*m_scale*0.1; CreateOutput(m_width,m_height,m_output,m_center,Vec2(m_scale*m_aspect,m_scale)); COORD cp = {0,0}; DWORD n; ::WriteConsoleOutputCharacterA(m_console,m_output.c_str(),m_output.length(),cp,&n); } void zoomIn() { m_scale *= 0.75; } void zoomOut() { m_scale /= 0.75; } private: HANDLE m_console; int m_width, m_height; std::string m_output; Vec2 m_center; double m_scale, m_aspect; }; int main() { Console console; for(;;) { console.draw(); if(_kbhit()) { switch(_getch()) { case 'i': console.zoomIn(); break; case 'o': console.zoomOut(); break; case 'q': return 0; } } ::Sleep(80); } }