오늘은 여러분께 작은 선물을 준비했다.
낯선 표현들이 나오지만 다음강에서 설명할테니 잠시만 어리둥절 하자.
//==============================================================================================
#pragma warning(disable: 4996) // _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include <array>
#include <stdio.h>
#include <conio.h> // _kbhit
#include <Windows.h>
//------------------------------------------------------------------------------------------------
#define CRE // constructor mark
using u8 = unsigned char;
using u16 = unsigned short;
using u32 = unsigned int;
using uu = std::size_t;
//------------------------------------------------------------------------------------------------
constexpr auto make_color16( u8 l, u8 r, u8 g, u8 b )
{
return u8( l << 3 | r << 2 | g << 1 | b );
}
enum class C4 : u8
{
// + R G B
black = make_color16( 0, 0, 0, 0 ),
navy = make_color16( 0, 0, 0, 1 ),
green = make_color16( 0, 0, 1, 0 ),
teal = make_color16( 0, 0, 1, 1 ),
maroon = make_color16( 0, 1, 0, 0 ),
purple = make_color16( 0, 1, 0, 1 ),
olive = make_color16( 0, 1, 1, 0 ),
silver = make_color16( 0, 1, 1, 1 ),
gray = make_color16( 1, 0, 0, 0 ),
blue = make_color16( 1, 0, 0, 1 ),
lime = make_color16( 1, 0, 1, 0 ),
aqua = make_color16( 1, 0, 1, 1 ),
red = make_color16( 1, 1, 0, 0 ),
fuchsia = make_color16( 1, 1, 0, 1 ),
yellow = make_color16( 1, 1, 1, 0 ),
white = make_color16( 1, 1, 1, 1 ),
};
constexpr auto operator/( const C4 fore, const C4 back )
{
return u8( static_cast< u8 >( back ) << 4 | static_cast< u8 >( fore ) );
};
//------------------------------------------------------------------------------------------------
class CONSOLE
{
struct LETTER
{
u8 color;
char tex;
};
static const int width = 80;
static const int height = 25;
static const int size = width * height;
using MATRIX = LETTER (&)[ height ][ width ];
char buffer_[ 8192 ];
std::array< LETTER, size > buffer;
MATRIX& screen = (MATRIX&)buffer;
HANDLE handle;
void go( const short x, const short y ) const
{
SetConsoleCursorPosition( handle, { x, y } );
}
void color( const u8 c ) const
{
SetConsoleTextAttribute( handle, c );
}
void resize( int w, int h ) const
{
COORD coord { w, h };
SetConsoleScreenBufferSize( handle, coord );
SMALL_RECT rect = { 0,0, w - 1, h - 1 };
SetConsoleWindowInfo( handle, TRUE, &rect );
}
public:
CRE CONSOLE( bool full_screen = false )
: handle( GetStdHandle( STD_OUTPUT_HANDLE ) )
{
setvbuf( stdout, (char*)&buffer_, _IOFBF, sizeof buffer_ );
cursor( false );
if( full_screen )
SetConsoleDisplayMode( handle, CONSOLE_FULLSCREEN_MODE, NULL );
clear();
}
void cursor( const bool show ) const
{
CONSOLE_CURSOR_INFO info = { 1, show };
SetConsoleCursorInfo( handle, &info );
}
void flush( const int s = size - 1 ) const
{
resize( width, height );
go( 0, 0 );
u8 old_color;
color( old_color = buffer[ 0 ].color );
putchar( buffer[ 0 ].tex );
for( int i = 1; i < s; ++i )
{
if( old_color != buffer[ i ].color )
{
fflush( stdout );
color( old_color = buffer[ i ].color );
}
putchar( buffer[ i ].tex );
}
fflush( stdout );
go( 0, 0 );
}
void clear()
{
buffer.fill( { text_color, ' ' } );
flush( size );
}
u8 text_color = 0x07;
u8 number_color = 0x07;
u8 number_size = 11;
bool right_alignment = true;
void put( const u32 x, const u32 y, const LETTER tex )
{
screen[ y ][ x ] = tex;
}
void put( const u32 x, const u32 y, const char c )
{
put( x, y, { text_color, c } );
}
auto puts( const u32 x, const u32 y, const char* str )
{
u32 i;
for( i = 0; str[ i ]; ++i )
put( x + i, y, { text_color, str[ i ] } );
return x + i;
}
template< uu SIZE >
auto puts( const u32 x, const u32 y, const char* str,
const u8( &colors )[ SIZE ], const int offset = 0 )
{
u32 i;
for( i = 0; str[ i ]; ++i )
put( x + i, y, { colors[ ( i + offset ) % SIZE ], str[ i ] } );
return x + i;
}
auto to_string( const int n ) const
{
static char numstr[ 14 ];
int* c = (int*)numstr;
c[ 2 ] = c[ 1 ] = c[ 0 ] = 0x20202020;
bool neg = false;
u32 u = n;
if( n < 0 ) neg = true, u = -n;
char* p = numstr + ( sizeof numstr - 1 );
char* end = p - number_size;
do *--p = u % 10 + '0', u /= 10; while( u );
if( neg ) *--p = '-';
if( !right_alignment )
return p;
return end;
}
auto text_number( const u32 x, const u32 y,
const char* s, const int n )
{
return puts( puts( x, y, s ), y, to_string( n ) );
}
};
//------------------------------------------------------------------------------------------------
int main()
{
CONSOLE stage;
u8 color_set1[] = { 15, 7, 8 };
stage.puts( 2, 1, "Hello teX", color_set1 );
u8 color_set2[] = { (u8)C4::red, (u8)C4::white, (u8)C4::white, (u8)C4::white };
stage.puts( 2, 3, "Codesafer's C++ programming guide", color_set2 );
int i = 0;
while( !_kbhit() )
{
stage.puts( 2, 5, "Codesafer's C++ programming guide", color_set2, i++ );
stage.flush();
}
getchar();
int frames = 0;
while( !_kbhit() )
{
for( int i = (int)C4::blue; i < 256; i += 16 )
{
stage.text_color = i;
stage.clear();
stage.text_number( 30, 12, "Hello teX", ++frames );
stage.flush();
}
}
getchar();
return 0;
}
//==============================================================================================
안타깝게도 Windows API 를 사용했기 때문에 VC++ 에서 밖에 컴파일되지 않는다.
내가 C++14 문법에 재미를 들인고로 Visual Studio 2015 이상을 권한다.
모든 학문이 그렇듯, 프로그래밍은 무조건 재밌게 공부해야 한다.
실행하면 다음과 같은 텍스트 애니메이션 화면이 나온다.
짧은 프레임웍이지만 이걸론 뭔가 할 수 있을 것 같은 기분이 들지 않는가?
형 여기 추천 누르면 돼죠?
코드 복사해서 컴파일 하시면 됩니다~
와개전다
콘솔겜 ?
부리전해
부럽당
코세님 c11에비해 c14 기능 많이추가됫나요?
C99랑 11은 완전 딴판이던데
99 <<<< >>>> 11 <> 14 예유~ 크게 많이 바뀌진 않았슴다.
근데 C++0x 를 이야기하신듯~
언어 하나 만들어보세요
어릴땐 컴파일러도 만들고 운영체제도 만들고 했는데 이젠 그런데 별 관심이 없어서리. 그때야 배우는 재미지만 지금은 생산성이 더 중요함유~
다양한 명령어와 그 명령어에 대한 도움말로 구성된 프로그램을 짤 때, 어떤 구조가 효율적인가요? - dc App
그림은 님 머리속에만 있으니 구체적인 제안을 드릴 순 없겠네요. 저라면 일단 어떻게 하면 명령어 수를 줄일까를 고민할테고, 키보드 커맨드 입력방식을 쓸지, GUI 를 쓸지, 음성인식을 쓸지 고민해볼 것 같아요.
파우//됫->됐 (되어 = 돼임) [리듬 맞춤법 봇♬]
제가 그 프로그램을 실제로 만드려는 건 아니고요, 그냥 궁금하기도 하고, 나중에 유용할 것 같아서 질문드리는겁니다. 윈도우의 cmd처럼 help를 통해 모든 명령어(와 설명)를 볼 수 있고, help <명령어>를 통해 특정 명령어의 설명을 볼 수 있는 뭐 그런 거요. 명령어 객체마다 설명이 담긴 변수를 선언해야 하는지, 그렇다면 그 객체는 어떤 타입을 쓰는 게 좋은지. 아니면 명령어는 함수만 선언해놓고 설명은 다른 자료형에 담아야 하는지, 코세님 잘하시는 C++ 기준으로요.
ㅋㅋㅋ 그냥 쉽게 하시려면 Dictionary 타입을 쓰세요. std::map 같은거요.
네 감사합니다 - dc App
빈 프로젝트로 생성하면 #include "stdafx.h" 이거 빨간줄 아님?
구래? 그럼 위로 옮겨줘~
내 환경에선 암소리 없어서 일일이 체크 안함 ㅋㅋ
u8은 utf-8문자열 리터럴지시하는 건데 컴파일 무사히됨?
되네...
ㅋㅋ 그건 u8" 까지니깐 당연 되지.
c:\users\admin\desktop\study\sharku2011\labcpp\labcpp\labcpp.cpp(107): error C2662: 'void CONSOLE::resize(int,int)': 'this' 포인터를 'const CONSOLE'에서 'CONSOLE &'(으)로 변환할 수 없습니다.1> c:\users\admin\desktop\study\sharku2011\labcpp\labcpp\labcpp.cpp(107): note: 변환하면서 한정자가 손실됩니다.
이런 에러가 나는데 뭐가 문제일까요
아, 그건 resize 함수 뒤에 const 를 빼먹어서 그래요.
그게 호출되는 flush 함수가 const 로 선언되어 있어서 멤버를 건드리지 않겠다고 약속한거거든요.
근데 멤버를 건드리지 않는 함수 안에서 멤버를 건드릴지도 모르는 함수를 호출하면, 멤버를 알기위해 this 포인터가 필요하죠.
객체란, 메모리에 생성되어 개체가 될 경우 서로 다른 고유의 멤버들을 갖게 되니까요.
읽기 전용 ( const )으로 쓰던 this 포인터를 쓰기 가능한 타입으로 접근하려니까 오류가 난다는 뜻입니다.
즉, resize 함수 const 만 붙여주면 둘 다 똑같이 '손만 잡고 잘게' 하게 되어서 실행하는데 문제가 없어지죠.
일단 임시변통으로 flush 함수에 const 붙어있던걸 제거했더니 돌아는 가네요
아 테스트해보는 사이에 답변 달아주셨네요 감사합니다
크윽 언리얼로 블프 위주로 만지다 보니까 기초가 너무 취약해졌네요. 좋은 글 보고 잘 배우고 있습니당
피드백 감사합니다 ~ ^ㅡ^
오오 깔끔해!! 모던 c++를 남용하지도 않았고 과한OOP추상화가 있는것도 아니고, 이해하기쉽고 간결하고 깔끔한 프레임웤 잘봤습니다
하지만 저 데이터 타입 정의를 스탠다드 타입으로 했으면 더 좋았을거같네요. stdint.h 인클루드하고 using u8 = uint8_t 이렇게.