けめこのあじと
Linux超初心者がLinuxで遊んでる様子です。あざ笑っていいよ… 主に自分用の覚え書き。
って、うわーー
yuribotu.jpg

古い原稿整理してたら懐かしいのが出てきた。

…アホや。そりゃぁボツにもなるわ…w
キリッ
a.jpg


自分のヘタさにムカついてくる
1/48スケール SV000/o 箱絵
sv000o.jpg

メタルスラッグにでてくるフチコマです。(フチコマて…!)
プラモの箱絵ふうに。

ロクに資料見ないでうろおぼえで描いたので、キャタピラがフィン状になってます…w ほんとうは爪状が正解。だからプロトタイプなのであ〜る…(汗orz
タンクのくせしてサスがしなやかです。ロールしております。床下スカスカ、おまいはクラシックカーか!(いや、ロマンですw)

追伸:
メーカーは”たいヴぃーや模型”という設定でおねがいします。くれぐれも某★★模型とは無関係という設定でおねがいしまっす!(・_;/おろおろ

ノーボーダー
noboder_t.jpg

このお姉さんはチーズケーキを1ホールいっき食いするつもりなのでしょうか… 一人で。
なんたるブルジョワ…
そしてどっさりクッキー。
太るぞ。末はでぶちんでしょう。あぁ、おそろしや。だが、そこがいい♪(なにっ!?

人の描いた線画を塗って練習しよう
20100108_01xx.jpg


ある人が、塗り絵用に線画を公開してらっしゃったので、かってに塗ってみたですよ。無許可ですよ。

こういう絵の髪の塗り方がわかんない。
ブラック★ロックシューター
20100107_brs.jpg

『ロック・カノン!』とか『ブラック・スウォ〜〜ド』とか♪ 中2全開なネーミングが逆にイカス!!
あれってワザとやってるんだろうけど。あ〜いう感覚って大切よね…けっこう。世界観を創る上で。
teto (0.1.0)
チラチラしなくした
teto010.mp3
( mp3 -> zip )

起動方法
win:
efg01.exe teto.g01

linux:
./t

アバンチュちゃん
20091231_01.jpg


あばんちゅカラーはおちつくなぁ〜…(^_^

…あ、
ほんとはubuntuはウブンツって読むのが正解らしいです。
し、しらなかた…(・_;ほろり
あとボク今までAMDはアンドって呼んでました…あ、アムドが正解らしいです… し、しらなかた…(・_;は、はずぅい…ほろり
メリーメリー
20091218_01.png

20091218_02.png


teto (0.0.8)
いちおう遊べる感じにはなってきた。
まだゲーム的な点数とかレベルとか、そういう部分はまだ作ってないですが…

teto008.jpg

linux ネイティブ : teto008linux.mp3

win (efg01使用) : teto008win.mp3
(拡張子を mp3 から zip に書き換えて解凍してください)

操作方法:
J:左移動 K:右移動 N:下移動
F:右回転 D:左回転
スペース:ハードドロップ
Q:終了

linuxの場合、コンソール表示にして実行した方がレスポンスがマシです。
tty?表示に移動:(Ctrl + Alt + F1〜F6)
gnome表示に戻る: (Cttl + Alt + F7)

コンパイル方法:
linux:
gcc -o t teto.c -lc -lpthread

efg01:
1行目の#define __OSASK__ を有効にして
tolset を使用

linux vga(おまけ、efg01 にVRAMへのピクセル書き込みがサポートされた場合は、この部分で対応する予定)
2行目#define __LINUX_VGA__を有効にして
gcc -o t teto.c -lc -lpthread -lvga -lvgagl

teto.c (0.0.8)
//#define __OSASK__
//#define __LINUX_VGA__

#ifdef __OSASK__

#include <guigui01.h>
#include <stdio.h>
#include <stdlib.h>

#define _COLOR_BLACK     0
#define _COLOR_RED         4
#define _COLOR_GREEN    2
#define _COLOR_YELLO    6
#define _COLOR_BLUE        1
#define _COLOR_PARPLE    13
#define _COLOR_LBLUE    3
#define _COLOR_WHITE    15
#define _COLOR_ORENGE    5

void vsync(int w)
{
    int i;
    for(i=0;i<w;i++){
//        jg01_sleep1(32-5, 1);        // x = 32-5 = 27,   weit_time = 2^(x-32) = 2^(27-32) = 2^(-5) = 1/32
        jg01_sleep1(32-6, 1);
    }
}

static int old_set_put_c_s_color  = 0;
static int old_set_put_c_bg_color = 0;
void set_put_c_color( int s_color, int bg_color )
{
    jg01_consctrl2( s_color, bg_color );
    old_set_put_c_s_color  = s_color;    old_set_put_c_bg_color = bg_color;
}

static int old_set_cur_x=0;
static int old_set_cur_y=0;
void set_cur( int x, int y )
{
    if((x>=0&&x<80)&&(y>=0&&y<25)){
        jg01_consctrl1(x,y);
    }
    else {
        jg01_consctrl1(0,0);
    }
    old_set_cur_x=x;    old_set_cur_y=y;
}

void put_c( unsigned char c )
{
    if((old_set_cur_x>=0&&old_set_cur_x<80)&&(old_set_cur_y>=0&&old_set_cur_y<25)){
        g01_putc(c);
    }
}

unsigned char get_c( void )
{
    unsigned char c = jg01_inkey2();
    if(c==0){return(0xFF);}else{return(c);}
}

void clr_scr(void)
{
    jg01_consctrl3();
}

void init_sys(void)
{
    srand(jg01_randomseed());

    jg01_consctrl4(80,25);
    jg01_consctrl2(15,0);
}

void close_sys(void)
{
    clr_scr();
    set_put_c_color( 7, 0 );
}

#endif // __OSASK__

#ifndef __OSASK__

#include <stdio.h>
#include <stdlib.h>

#include <linux/input.h>
#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <time.h>
#include <pthread.h>

#ifdef __LINUX_VGA__
#include <vga.h>
#include <vgagl.h>
#endif //__LINUX_VGA

#define _COLOR_BLACK     1
#define _COLOR_RED         2
#define _COLOR_GREEN    3
#define _COLOR_YELLO    4
#define _COLOR_BLUE        5
#define _COLOR_PARPLE    6
#define _COLOR_LBLUE    7
#define _COLOR_WHITE    8
#ifdef __LINUX_VGA__
#define _COLOR_ORENGE    9
#else
#define _COLOR_ORENGE    _COLOR_WHITE
#endif //__LINUX_VGA_\

static int                 flg_init_termios = 0;
static struct termios     save_term;
static struct termios     temp_term;
static struct timeval    old_tv;
static struct timezone    old_tz;

void* __vsync(void* pParam )
{
    static struct timeval    tv;
    static struct timezone    tz;
    gettimeofday(&tv, &tz);
   
    static struct timespec     req;
    static struct timespec     rem;
    req.tv_sec  = 0;
//    req.tv_nsec = 31250000 - (tv.tv_usec - old_tv.tv_usec);        // 1/32(s)
    req.tv_nsec = 15625000 - (tv.tv_usec - old_tv.tv_usec);

    nanosleep(&req,&rem);

    old_tv.tv_usec = tv.tv_usec;
   
    return(0);
}

void vsync(int w)
{
    fflush(stdout);

    int i;
    pthread_t pt;

    for(i=0;i<w;i++){
        pthread_create(&pt, NULL, __vsync, NULL );
        pthread_join(pt,NULL);
    }
}

#ifdef __LINUX_VGA__
static int old_set_put_c_s_color  = 0;
static int old_set_put_c_bg_color = 0;
void set_put_c_color( int s_color, int bg_color )
{
/*
    switch(s_color){
    case _COLOR_BLACK:    old_set_put_c_s_color = 0x00; break;
    case _COLOR_RED:    old_set_put_c_s_color = 0xF0; break;
    case _COLOR_GREEN:    old_set_put_c_s_color = 0xCC; break;
    case _COLOR_YELLO:    old_set_put_c_s_color = 0xFC; break;
    case _COLOR_BLUE:    old_set_put_c_s_color = 0xC3; break;
    case _COLOR_PARPLE:    old_set_put_c_s_color = 0xF3; break;
    case _COLOR_LBLUE:    old_set_put_c_s_color = 0xCF; break;
    case _COLOR_WHITE:    old_set_put_c_s_color = 0xFF; break;
    default:             old_set_put_c_s_color = 0x00; break;
    }

    switch(bg_color){
    case _COLOR_BLACK:    old_set_put_c_bg_color = 0x00; break;
    case _COLOR_RED:    old_set_put_c_bg_color = 0xF0; break;
    case _COLOR_GREEN:    old_set_put_c_bg_color = 0xCC; break;
    case _COLOR_YELLO:    old_set_put_c_bg_color = 0xFC; break;
    case _COLOR_BLUE:    old_set_put_c_bg_color = 0xC3; break;
    case _COLOR_PARPLE:    old_set_put_c_bg_color = 0xF3; break;
    case _COLOR_LBLUE:    old_set_put_c_bg_color = 0xCF; break;
    case _COLOR_WHITE:    old_set_put_c_bg_color = 0xFF; break;
    default:             old_set_put_c_bg_color = 0x00; break;
    }
*/
    switch(s_color){
    case _COLOR_BLACK:    old_set_put_c_s_color = 0;     break;
    case _COLOR_RED:    old_set_put_c_s_color = 4;    break;
    case _COLOR_GREEN:    old_set_put_c_s_color = 2;    break;
    case _COLOR_YELLO:    old_set_put_c_s_color = 6;    break;
    case _COLOR_BLUE:    old_set_put_c_s_color = 1;    break;
    case _COLOR_PARPLE:    old_set_put_c_s_color = 13;    break;
    case _COLOR_LBLUE:    old_set_put_c_s_color = 3;    break;
    case _COLOR_ORENGE:    old_set_put_c_s_color = 5;    break;
    case _COLOR_WHITE:    old_set_put_c_s_color = 15;    break;
    default:             old_set_put_c_s_color = 0;
    }

    switch(bg_color){
    case _COLOR_BLACK:    old_set_put_c_bg_color = 0;     break;
    case _COLOR_RED:    old_set_put_c_bg_color = 4;        break;
    case _COLOR_GREEN:    old_set_put_c_bg_color = 2;        break;
    case _COLOR_YELLO:    old_set_put_c_bg_color = 6;        break;
    case _COLOR_BLUE:    old_set_put_c_bg_color = 1;        break;
    case _COLOR_PARPLE:    old_set_put_c_bg_color = 13;    break;
    case _COLOR_LBLUE:    old_set_put_c_bg_color = 3;        break;
    case _COLOR_ORENGE:    old_set_put_c_bg_color = 5;        break;
    case _COLOR_WHITE:    old_set_put_c_bg_color = 15;    break;
    default:             old_set_put_c_bg_color = 0;
    }

    vga_setcolor(old_set_put_c_bg_color);
}
#else
static int old_set_put_c_s_color  = 0;
static int old_set_put_c_bg_color = 0;
void set_put_c_color( int s_color, int bg_color )
{
    switch(s_color){
    case _COLOR_BLACK:    printf("%c[%dm",0x1b, 30 ); break;
    case _COLOR_RED:    printf("%c[%dm",0x1b, 31 ); break;
    case _COLOR_GREEN:    printf("%c[%dm",0x1b, 32 ); break;
    case _COLOR_YELLO:    printf("%c[%dm",0x1b, 33 ); break;
    case _COLOR_BLUE:    printf("%c[%dm",0x1b, 34 ); break;
    case _COLOR_PARPLE:    printf("%c[%dm",0x1b, 35 ); break;
    case _COLOR_LBLUE:    printf("%c[%dm",0x1b, 36 ); break;
    case _COLOR_WHITE:    printf("%c[%dm",0x1b, 37 ); break;
    default:             printf("%c[%dm",0x1b, 0  ); break;
    }

    switch(bg_color){
    case _COLOR_BLACK:    printf("%c[%dm",0x1b, 40 ); break;
    case _COLOR_RED:    printf("%c[%dm",0x1b, 41 ); break;
    case _COLOR_GREEN:    printf("%c[%dm",0x1b, 42 ); break;
    case _COLOR_YELLO:    printf("%c[%dm",0x1b, 43 ); break;
    case _COLOR_BLUE:    printf("%c[%dm",0x1b, 44 ); break;
    case _COLOR_PARPLE:    printf("%c[%dm",0x1b, 45 ); break;
    case _COLOR_LBLUE:    printf("%c[%dm",0x1b, 46 ); break;
    case _COLOR_WHITE:    printf("%c[%dm",0x1b, 47 ); break;
    default:             printf("%c[%dm",0x1b, 0  ); break;
    }
   
    old_set_put_c_s_color  = s_color;    old_set_put_c_bg_color = bg_color;
}
#endif // __LINUX_VGA__

#ifdef __LINUX_VGA__
static int old_set_cur_x = 0;
static int old_set_cur_y = 0;
void set_cur( int x, int y )
{
    old_set_cur_x=x;    old_set_cur_y=y;
}
#else
static int old_set_cur_x = 0;
static int old_set_cur_y = 0;
void set_cur( int x, int y )
{
    if((x>=0&&x<80)&&(y>=0&&y<25)){
        printf("%c[%d;%dH",0x1b, y+1, x+1 );
    }
    else {
        printf("%c[%d;%dH",0x1b, 1, 1 );
    }
    old_set_cur_x=x;    old_set_cur_y=y;
}
#endif //__LINUX_VGA__

#ifdef __LINUX_VGA__
void clr_scr(void)
{
    vga_clear();
}
#else
void clr_scr(void)
{
    printf("%c[2J",0x1B );
}
#endif //__LINUX_VGA__

#ifdef __LINUX_VGA__
void put_c( unsigned char c )
{
    if((old_set_cur_x>=0&&old_set_cur_x<80)&&(old_set_cur_y>=0&&old_set_cur_y<25)){
        #define PUT_C_W 8
        #define PUT_C_H 16
        int i,j;
        for(j=0;j<PUT_C_H;j++){
            for(i=0;i<PUT_C_W;i++){
                vga_drawpixel(old_set_cur_x*PUT_C_W+i, old_set_cur_y*PUT_C_H+j);
            }
        }
    }
}
#else
void put_c( unsigned char c )
{
    if((old_set_cur_x>=0&&old_set_cur_x<80)&&(old_set_cur_y>=0&&old_set_cur_y<25)){
        putchar((int)c);
    }
}
#endif //__LINUX_VGA__

/*
static unsigned char    old_get_k=0;
unsigned char get_k( void )
{
    unsigned char c;
    c = getchar();
    if( c == 0xFF){ c = old_get_k; }else{ old_get_k = c; }
    return(c);
}
*/

unsigned char get_c( void )
{
    unsigned char c;
    c = getchar();
    return(c);
}

#ifdef __LINUX_VGA__
void init_sys(void)
{
//     int vgamode=G1024x768x256;
      int vgamode=G640x480x256;
    vga_init();
    vga_setmode(vgamode);
    gl_setcontextvga(vgamode);

    if( flg_init_termios == 0 ) {
          tcgetattr(fileno(stdin), &save_term);
          temp_term = save_term;
          temp_term.c_iflag &= ~IGNCR;
          temp_term.c_lflag &= ~ICANON;
          temp_term.c_lflag &= ~ECHO;
          temp_term.c_lflag &= ~ISIG;
          temp_term.c_cc[VMIN]=0;
//        temp_term.c_cc[VMIN]=1;
          temp_term.c_cc[VTIME]=0;
          tcsetattr(fileno(stdin), TCSANOW, &temp_term);
    }
    flg_init_termios += 1;                                    // ユニークカウンタ(これでシステム全体での起動数を把握しておく)

    srand((unsigned int)time(0));
   
    gettimeofday(&old_tv, &old_tz);
}
#else
void init_sys(void)
{
    if( flg_init_termios == 0 ) {
          tcgetattr(fileno(stdin), &save_term);
          temp_term = save_term;
          temp_term.c_iflag &= ~IGNCR;
          temp_term.c_lflag &= ~ICANON;
          temp_term.c_lflag &= ~ECHO;
          temp_term.c_lflag &= ~ISIG;
          temp_term.c_cc[VMIN]=0;
//        temp_term.c_cc[VMIN]=1;
          temp_term.c_cc[VTIME]=0;
          tcsetattr(fileno(stdin), TCSANOW, &temp_term);
    }
    flg_init_termios += 1;                                    // ユニークカウンタ(これでシステム全体での起動数を把握しておく)
   
    srand((unsigned int)time(0));
   
    gettimeofday(&old_tv, &old_tz);
}
#endif //__LINUX_VGA__

#ifdef __LINUX_VGA__
void close_sys(void)
{
    flg_init_termios -= 1;                                    // ユニークカウンタを一つ減らす
    if( flg_init_termios == 0 ) {
        tcsetattr(fileno(stdin), TCSANOW, &save_term );        // すべては、これを複数回起動してしまうのを防止するため。(ユニークカウンタ
    }

    clr_scr();
    set_put_c_color( 0, 0 );
    put_c( '\n');
}
#else
void close_sys(void)
{
    flg_init_termios -= 1;                                    // ユニークカウンタを一つ減らす
    if( flg_init_termios == 0 ) {
        tcsetattr(fileno(stdin), TCSANOW, &save_term );        // すべては、これを複数回起動してしまうのを防止するため。(ユニークカウンタ
    }

    clr_scr();
    set_put_c_color( 0, 0 );
    put_c( '\n');
}
#endif //__LINUX_VGA__

#endif // __OSASK__





#define PAD_R_UP        1
#define PAD_R_DOWN        2
#define PAD_R_RIGHT        4
#define PAD_R_LEFT        8
#define PAD_L_UP        16
#define PAD_L_DOWN        32
#define PAD_L_RIGHT        64
#define PAD_L_LEFT        128
#define PAD_START        256
#define PAD_SELECT        512
#define PAD_L1            1024
#define PAD_L2            2048
#define PAD_R1            4096
#define PAD_R2            8192

static unsigned short PAD1;
static unsigned short PAD2;

typedef struct tagPOS {
    int x;
    int y;
} POS;

typedef struct tagBLOCK {
    unsigned char     b[2];
    POS                p;
    int                str_col;
    int                bg_col;
} BLOCK;

#define PANEL_W        12
#define PANEL_H        25
typedef struct tagPANEL {
    BLOCK     b[PANEL_W*PANEL_H*2];
    POS        p;
} PANEL;

#define NPANEL_W    5
#define NPANEL_H    6
typedef struct tagNPANEL {
    BLOCK    b[NPANEL_W*NPANEL_H*2];
    POS        p;
} NPANEL;

typedef struct tagMINO {
    int        t;
    BLOCK     b[4];
    POS        p;
    POS        cp;
} MINO;

typedef struct tagAI {
    PANEL     CPP;
    MINO      CPM;
    int        CTV,CTH,CTR;
} __AI;

#define NINGEN         0
#define KIKAI          1
#define MUJINKUN    2
typedef struct tagTETO{
    int                    pmd;
    POS                    nmp;
    POS                    cmp;
    PANEL                 P;
    NPANEL                NP;
    int                 comp_line[PANEL_H]; // = {0,0,0,0,0,    0,0,0,0,0,    0,0,0,0,0,    0,0,0,0,0,    0,0};
    int                    cur_flsP;            // =0;
    #define DM_LEN 7
    MINO                DM[DM_LEN];
    MINO                GM[DM_LEN];
    int                    rand_box[DM_LEN*2];    //={0,1,2,3,4,5,6,0,1,2,3,4,5,6};
    int                    cur_rand_box_len;    //=DM_LEN*2;
    __AI                 AI;
    int                 snc;                //=0;
    int                 f;                    //=0;
    MINO                 cur_mino;
    MINO                 next_mino;
    MINO                cur_ghost_mino;
    MINO                next_ghost_mino;
    int                    ojl;
    int                    ojls;
    int                    awt;
    int                    cawt;
} TETO;

/*
// a^inv
int _pow(int a, int inv )
{
    int r=a;

    if(inv==0) r=1;
    if(inv==1) r=a;

    int i;
    for(i=2;i<=inv;i++){r*=a;}

    return(r);
}

// 基数による桁数
int _dig(int a, int cardinal )
{
    if( cardinal ==0 ){printf("err: dig() cardinal¥n");exit(1);}

    int count=0;

    while(a>0){
        count++;
        a/=cardinal;
        if( a <= 0 ) { break; }
    }

    return(count);
}

// 数値型から文字列型
void itos( char* dst, int src )
{
    if(src > 0){
        int p;
        int unit;
        int sub=0;
        int dig=_dig(src,10);
        int i;
        for(i=0;i<dig;i++){
            p=_pow(10,i+1);
            sub+=((src%p)-sub);
            unit=sub / _pow(10, i);

            switch(unit){
                case 0:dst[dig-1-i]='0';break;
                case 1:dst[dig-1-i]='1';break;
                case 2:dst[dig-1-i]='2';break;
                case 3:dst[dig-1-i]='3';break;
                case 4:dst[dig-1-i]='4';break;
                case 5:dst[dig-1-i]='5';break;
                case 6:dst[dig-1-i]='6';break;
                case 7:dst[dig-1-i]='7';break;
                case 8:dst[dig-1-i]='8';break;
                case 9:dst[dig-1-i]='9';break;
                default:printf("err: itos() dst[%d]¥n",dig-1-i ); exit(1); break;
            }
        }
        dst[dig]='\0';
    }
    else {
        dst[0]='0';
        dst[1]='\0';
    }
}

double factoriol( long a )
{
    double v = 1;

    int i;
    for(i = 1; i <= a; i++ ) {
        v *= (double)i;
    }

    return( v );
}

double pow_f( double a, long inv )
{
    double r=a;

    if(inv==0){r=1;}
    if(inv==1){r=a;}
   
    int i;
    for(i=2; i <= inv; i++ ){ r *= a; }

    return(r);
   
}

double exp_taylor( double a )
{
    double v=0;

    int i;
    for(i = 0; i < 10; i++ ) {
        v += ( 1.0 / factoriol(i) ) * pow_f(a,i);
    }   
   
    return( v );
}

double sin_taylor( double a )
{
    double v=0;
    double fugou=1.0;

    int i;
    for(i=1; i<20; i+=2 ) {
        v += fugou * ( ( 1.0 / factoriol(i) ) * pow_f(a, i) );
        fugou=-fugou;
    }

    return( v );
}
*/
/*
static double ETC_MATH_t_table_rd( ( (double)ETC_MATH_TABLE_SIZE / 2 ) / 3.14159265358979 );
double sin_t( double a )
{
    unsigned long l = (unsigned long)( a * ETC_MATH_t_table_rd );
    l %= ETC_MATH_TABLE_SIZE;
    return( ETC_MATHsin_table[l]);
}

double cos_t( double a )
{
    unsigned long l = (unsigned long)( a * ETC_MATH_t_table_rd );
    l %= ETC_MATH_TABLE_SIZE;
    return( ETC_MATHcos_table[l]);
}

double tan_t( double a )
{
    unsigned long l = (unsigned long)( a * ETC_MATH_t_table_rd );
    l %= ETC_MATH_TABLE_SIZE;
    return( ETC_MATHtan_table[l]);
}
*/





void syncPAD(void)
{
    int i;
    unsigned char c;
    unsigned short pad_l_nl  = PAD_L_RIGHT | PAD_L_LEFT;

    if( ((PAD1&PAD_L1)!=0) || ((PAD1&PAD_R1)!=0) ) { PAD1 = 0; } else { PAD1 &= pad_l_nl; }
    PAD2 =  0;

    do {
        c=get_c();
        switch(c){
        case 'k': case 'K':    PAD1 |= PAD_R1;     PAD1|=PAD_L_RIGHT;    break;
        case 'j': case 'J':    PAD1 |= PAD_L1;     PAD1|=PAD_L_LEFT;    break;
        case 'n': case 'N':    PAD1 |= PAD_L_DOWN;                        break;
        case 'i': case 'I':    PAD1 &= ~pad_l_nl;     PAD1|=PAD_L_RIGHT;    break;
        case 'u': case 'U':    PAD1 &= ~pad_l_nl;     PAD1|=PAD_L_LEFT;    break;
        case ' ':            PAD1 |= PAD_L_UP;                        break;
        case 'f': case 'F':    PAD1 |= PAD_R_UP;    PAD1 &= ~pad_l_nl;     break;
        case 'd': case 'D':    PAD1 |= PAD_R_LEFT;    PAD1 &= ~pad_l_nl;     break;
        case 'q': case 'Q':    PAD1 |= PAD_START;    break;
        }
    } while(c!=0xFF);
}





void initB(BLOCK* B)
{
    B->b[0]        =' ';
    B->b[1]        =' ';
    B->p.x        =0;
    B->p.y        =0;
    B->str_col    =0;
    B->bg_col     =0;
}

void cpyB(BLOCK* dst, BLOCK* src )
{
    dst->b[0]        = src->b[0];
    dst->b[1]        = src->b[1];
    dst->p.x         = src->p.x;
    dst->p.y         = src->p.y;
    dst->str_col     = src->str_col;
    dst->bg_col     = src->bg_col;
}

void posB(BLOCK* b, int x, int y)
{
    b->p.x=x;
    b->p.y=y;
}

void colB(BLOCK* b, int col)
{
    switch(col){
    case 0:    b->str_col = b->bg_col = _COLOR_BLACK;    break;
//    case 0:    b->str_col = b->bg_col = 0;                break;
    case 1:    b->str_col = b->bg_col = _COLOR_LBLUE;    break;
    case 2:    b->str_col = b->bg_col = _COLOR_ORENGE;    break;
    case 3:    b->str_col = b->bg_col = _COLOR_PARPLE;    break;
    case 4:    b->str_col = b->bg_col = _COLOR_RED;    break;
    case 5:    b->str_col = b->bg_col = _COLOR_GREEN;    break;
    case 6:    b->str_col = b->bg_col = _COLOR_YELLO;    break;
    case 7:    b->str_col = b->bg_col = _COLOR_BLUE;    break;
    case 8:    b->str_col = b->bg_col = _COLOR_WHITE;    break;
    }
}

void colGB(BLOCK* b)
{
    b->str_col = _COLOR_WHITE; b->bg_col = _COLOR_BLACK;
}

void prtB(BLOCK* b, int x, int y)
{
    set_put_c_color(b->str_col,b->bg_col);

    set_cur(2*(b->p.x+x)+0,b->p.y+y+0);        put_c(b->b[0]);
    set_cur(2*(b->p.x+x)+1,b->p.y+y+0);        put_c(b->b[1]);

    set_put_c_color(0,0);   
}

void clrB(BLOCK* b, int x, int y)
{
    set_put_c_color(_COLOR_BLACK,_COLOR_BLACK);

    set_cur(2*(b->p.x+x)+0,b->p.y+y+0);        put_c(b->b[0]);
    set_cur(2*(b->p.x+x)+1,b->p.y+y+0);        put_c(b->b[1]);

    set_put_c_color(0,0);   
}





void initP(TETO*teto, int x, int y)
{
    PANEL* P = &(teto->P);
    int i,j;
    BLOCK* bp;
   
    P->p.x=x;
    P->p.y=y;
   
    for(j=0;j<PANEL_H;j++) {
        i=0;
        bp=&(P->b[j*PANEL_W]);
     
        switch(j){
        case PANEL_H-1:
            for(i=-0;i<PANEL_W;i++) {
                initB(bp); posB(bp,i,j); colB(bp,8); bp++;
            }
            break;

        default:
            initB(bp); posB(bp,i,j); colB(bp,8); bp++;
            for(i=1;i<PANEL_W-1;i++) {
                initB(bp); posB(bp,i,j); colB(bp,0); bp++;
            }
            initB(bp); posB(bp,i,j); colB(bp,8); bp++;
            break;
        }
    }   
}

void initNP(TETO* teto, int x, int y)
{
    NPANEL* NP = &(teto->NP);
    int i,j;
    BLOCK* bp;
   
    NP->p.x=x;
    NP->p.y=y;

    for(j=0;j<NPANEL_H;j++) {
        i=0;
        bp=&(NP->b[j*NPANEL_W]);
     
        switch(j){
        case 0: case NPANEL_H-1:
            for(i=-0;i<NPANEL_W;i++) {
                initB(bp); posB(bp,i,j); colB(bp,8); bp++;
            }
            break;

        default:
            initB(bp); posB(bp,i,j); colB(bp,8); bp++;
            for(i=1;i<NPANEL_W-1;i++) {
                initB(bp); posB(bp,i,j); colB(bp,0); bp++;
            }
            initB(bp); posB(bp,i,j); colB(bp,8); bp++;
            break;
        }
    }   
}

int chkP(TETO* teto)
{
    PANEL* P = &(teto->P);
    int j,i;
    int c;
    int ret =0;
    BLOCK* bp;
   
    for(j=0;j<PANEL_H-1;j++){
        bp=&(P->b[j*PANEL_W+1]);
        c=0;
        for(i=1;i<PANEL_W-1;i++){
            if( bp->bg_col != _COLOR_BLACK ){ c++; }
            bp++;
        }
        if(c==PANEL_W-1-1) {
            teto->comp_line[j]=1;
            ret++;
        }
        else {
            teto->comp_line[j]=0;
        }
    }
   
    return(ret);
}

int flsP(TETO* teto)
{
    PANEL* P = &(teto->P);
    int i,j;
    BLOCK* bp;
    int ret = 0;
   
    int col;
    switch(teto->cur_flsP) {
    case 0: col=_COLOR_LBLUE;    teto->cur_flsP=1;    break;
    case 1: col=_COLOR_YELLO;     teto->cur_flsP=0;    break;
    }
     
    for(j=0;j<PANEL_H-1;j++){
        if(teto->comp_line[j]!=0){
            bp = &(P->b[j*PANEL_W+1]);
            for(i=1;i<PANEL_W-1;i++){
                bp->str_col = col;
                bp->bg_col  = col;
                bp++;
            }
        }
    }

    return(ret);
}

void dllP(TETO* teto)
{
    PANEL* P = &(teto->P);
    int i,j;
    BLOCK* bp;
   
    for(j=0;j<PANEL_H-1;j++){
        if(teto->comp_line[j]!=0){
            bp = &(P->b[j*PANEL_W+1]);
            for(i=1;i<PANEL_W-1;i++){
                bp->str_col = _COLOR_BLACK;
                bp->bg_col  = _COLOR_BLACK;
                bp++;
            }
        }
    }
}

int dwnP(TETO* teto)
{
    PANEL* P =&(teto->P);
    int i,j;
    BLOCK* bp;
    BLOCK* ubp;
    int c;
    int ret=0;
   
    for(j=PANEL_H-1-1; j>0; j--){
        bp = &(P->b[j*PANEL_W+1]);
        c=0;
        for(i=1;i<PANEL_W-1;i++){
            if( bp->bg_col == _COLOR_BLACK ) { c++; };
            bp++;
        }
        if(c==PANEL_W-1-1){
            bp  = &(P->b[(j+0)*PANEL_W+1]);
            ubp = &(P->b[(j-1)*PANEL_W+1]);
            for(i=1;i<PANEL_W-1;i++){
                bp->str_col = ubp->str_col;
                bp->bg_col  = ubp->bg_col;
                ubp->str_col = _COLOR_BLACK;
                ubp->bg_col  = _COLOR_BLACK;
                bp++;
                ubp++;
            }
           
            ret++;
        }
    }
   
    return(ret);
}

void ojlP(TETO* teto)
{
    PANEL* P =&(teto->P);
    int i,j;
    BLOCK* bp;
    BLOCK* ubp;
   
    for(j=1;j<PANEL_H;j++){
        ubp = &(P->b[(j-1)*PANEL_W+1]);
        bp  = &(P->b[(j+0)*PANEL_W+1]);
        for(i=1;i<PANEL_W-1;i++){
            ubp->str_col = bp->str_col;
            ubp->bg_col  = bp->bg_col;
            bp++;
            ubp++;
        }
    }
   
    bp  = &(P->b[(PANEL_H-1-1)*PANEL_W+1]);
    for(i=1;i<PANEL_W-1;i++){
        bp->str_col = _COLOR_WHITE;
        bp->bg_col  = _COLOR_WHITE;
        bp++;
    }   

    bp = &(P->b[(PANEL_H-1-1)*PANEL_W+1]);
    bp += teto->ojls;
//    bp += rand()%(PANEL_W-1-1);
    bp->str_col    = _COLOR_BLACK;
    bp->bg_col  = _COLOR_BLACK;
}

void prtP(TETO* teto)
{
    PANEL* P = &(teto->P);
    int i,j;
    BLOCK* bp;
   
    for(j=0;j<PANEL_H;j++){
        i=0;
        bp=&(P->b[j*PANEL_W]);
       
        for(i=0;i<PANEL_W;i++){
              prtB(bp++,P->p.x, P->p.y);
        }
    }
}

void prtNP(TETO* teto)
{
    PANEL*    P  = &(teto->P);
    NPANEL*    NP = &(teto->NP);
    int i,j;
    BLOCK* bp;

    for(j=0;j<NPANEL_H;j++){
        i=0;
        bp=&(NP->b[j*NPANEL_W]);
       
        for(i=0;i<NPANEL_W;i++){
              prtB(bp++,P->p.x+NP->p.x, P->p.y+NP->p.y);
        }
    }
}

int apB(TETO* teto, BLOCK* b,int x, int y)
{
    PANEL* P = &(teto->P);
    int cx=b->p.x+x;
    int cy=b->p.y+y;

    switch( P->b[cy*PANEL_W+cx].bg_col ){
    case _COLOR_BLACK:    return(0);    break;
    default:            return(1);    break;
    }
}





void initMINO(TETO* teto, MINO* m, int t)
{
    register BLOCK* bp = m->b;

    m->p.x = teto->cmp.x;
    m->p.y = teto->cmp.y;
   
    m->cp.x=0;
    m->cp.y=0;
       
    initB(bp++);    initB(bp++);    initB(bp++);    initB(bp++);

    bp = m->b;   
    switch(t) {
    case 0:    colB(bp++,1);    colB(bp++,1);    colB(bp++,1);    colB(bp++,1);    break;
    case 1:    colB(bp++,2);    colB(bp++,2);    colB(bp++,2);    colB(bp++,2);    break;
    case 2:    colB(bp++,3);    colB(bp++,3);    colB(bp++,3);    colB(bp++,3);    break;
    case 3:    colB(bp++,4);    colB(bp++,4);    colB(bp++,4);    colB(bp++,4);    break;
    case 4:    colB(bp++,5);    colB(bp++,5);    colB(bp++,5);    colB(bp++,5);    break;
    case 5:    colB(bp++,6);    colB(bp++,6);    colB(bp++,6);    colB(bp++,6);    break;
    case 6:    colB(bp++,7);    colB(bp++,7);    colB(bp++,7);    colB(bp++,7);    break;
    }   
   
    bp = m->b;   
    switch(t) {
    case 0:    posB(bp++,0,-1);    posB(bp++,0,0);        posB(bp++,0,1);        posB(bp++,0,2);        break;        // ----
    case 1:    posB(bp++,0,0);        posB(bp++,0,1);        posB(bp++,1,0);        posB(bp++,1,1);        break;        // []
    case 2:    posB(bp++,-1,0);    posB(bp++,0,0);        posB(bp++,1,0);        posB(bp++,0,-1);    break;        // T
    case 3:    posB(bp++,-1,0);    posB(bp++,0,0);        posB(bp++,0,1);        posB(bp++,1,1);        break;        // N
    case 4:    posB(bp++,-1,1);    posB(bp++,0,1);        posB(bp++,0,0);        posB(bp++,1,0);        break;        // !N
    case 5:    posB(bp++,0,-1);    posB(bp++,0,0);        posB(bp++,0,1);        posB(bp++,1,1);        break;        // L
    case 6:    posB(bp++,0,-1);    posB(bp++,0,0);        posB(bp++,0,1);        posB(bp++,-1,1);    break;        // !L
    }
   
    m->t=t;
}

void initGHOSTMINO(TETO* teto, MINO* m, int t)
{
    initMINO(teto,m,t);

    register BLOCK* bp = m->b;
    colGB(bp);    bp->b[0]='[';    bp->b[1]=']';    bp++;
    colGB(bp);    bp->b[0]='[';    bp->b[1]=']';    bp++;
    colGB(bp);    bp->b[0]='[';    bp->b[1]=']';    bp++;
    colGB(bp);    bp->b[0]='[';    bp->b[1]=']';    bp++;
}

void cpyMINO( MINO* dst, MINO* src )
{
    dst->t = src->t;
   
    dst->p.x = src->p.x;
    dst->p.y = src->p.y;

    dst->cp.x = src->cp.x;
    dst->cp.y = src->cp.y;

    BLOCK* dbp = dst->b;
    BLOCK* sbp = src->b;
    cpyB(dbp++,sbp++);    cpyB(dbp++,sbp++);    cpyB(dbp++,sbp++);    cpyB(dbp++,sbp++);
}

int apMINO(TETO* teto, MINO* m)
{
    int i;
    int x=m->p.x+m->cp.x;
    int y=m->p.y+m->cp.y;
    int ret=0;
    BLOCK* bp = m->b;
    ret+=apB(teto, bp++,x,y);    ret+=apB(teto, bp++,x,y);    ret+=apB(teto, bp++,x,y);    ret+=apB(teto, bp++,x,y);
   
    return(ret);
}

void __rotMINO( MINO* m, int r )
{
    BLOCK* bp = m->b;
   
    if(r >= +1){
        posB(bp, +bp->p.y,-bp->p.x ); bp++;
        posB(bp, +bp->p.y,-bp->p.x ); bp++;
        posB(bp, +bp->p.y,-bp->p.x ); bp++;
        posB(bp, +bp->p.y,-bp->p.x );
    }
    else if( r <= -1){
        posB(bp, -bp->p.y,+bp->p.x ); bp++;
        posB(bp, -bp->p.y,+bp->p.x ); bp++;
        posB(bp, -bp->p.y,+bp->p.x ); bp++;
        posB(bp, -bp->p.y,+bp->p.x );       
    }
}

int __movMINO(TETO* teto, MINO* m, int x, int y)
{
    m->p.x += x;
    m->p.y += y;
   
    if(apMINO(teto,m)!=0){
        m->p.x -= x;    m->p.y -= y;
        return(1);
    }
    m->p.x += m->cp.x;    m->p.y += m->cp.y;
    m->cp.x=0;            m->cp.y=0;
    return(0);
}

void rot_rMINO( TETO* teto, MINO* m )
{
    if(m->t==1){return;}

    __rotMINO( m, -1 );

    m->cp.x=0;    m->cp.y=0;
    if(apMINO(teto,m)!=0){
        m->cp.x=0;
        m->cp.y=-1; if(apMINO(teto,m)==0){ return; }

        m->cp.y=0;
        m->cp.x=+1; if(apMINO(teto,m)==0){ return; }
        m->cp.x=-1; if(apMINO(teto,m)==0){ return; }

        if(m->t==0){
            m->cp.x=0;
            m->cp.y=-2; if(apMINO(teto,m)==0){ return; }

            m->cp.y=0;
            m->cp.x=+2; if(apMINO(teto,m)==0){ return; }
            m->cp.x=-2; if(apMINO(teto,m)==0){ return; }
        }
           
        m->cp.x=0;    m->cp.y=0;
           
        __rotMINO( m, +1 );
    }
}

void rot_lMINO( TETO* teto, MINO* m )
{
    if(m->t==1){return;}
 
    __rotMINO( m, +1 );   

    m->cp.x=0;    m->cp.y=0;
    if(apMINO(teto, m)!=0){
        m->cp.x=0;
        m->cp.y=-1; if(apMINO(teto,m)==0){ return; }

        m->cp.y=0;
        m->cp.x=+1; if(apMINO(teto,m)==0){ return; }
        m->cp.x=-1; if(apMINO(teto,m)==0){ return; }

        if(m->t==0){
            m->cp.x=0;
            m->cp.y=-2; if(apMINO(teto,m)==0){ return; }

            m->cp.y=0;
            m->cp.x=+2; if(apMINO(teto,m)==0){ return; }
            m->cp.x=-2; if(apMINO(teto,m)==0){ return; }
        }
       
        m->cp.x=0;    m->cp.y=0;
        __rotMINO( m, -1 );
    }
}

int mov_dMINO(TETO* teto, MINO* m)
{
    return(__movMINO(teto,m,0,1));
}

int mov_rMINO(TETO* teto, MINO* m)
{
    return(__movMINO(teto,m,+1,0));
}

int mov_lMINO(TETO* teto, MINO* m)
{
    return(__movMINO(teto,m,-1,0));
}

void prtMINO( TETO* teto, MINO* m )
{
    PANEL* P = &(teto->P);
    BLOCK* mbp = m->b;
    int x = P->p.x + m->p.x + m->cp.x;
    int y = P->p.y + m->p.y + m->cp.y;

    prtB(mbp,x,y); mbp++;
    prtB(mbp,x,y); mbp++;
    prtB(mbp,x,y); mbp++;
    prtB(mbp,x,y); mbp++;
}

void clrMINO( TETO* teto, MINO* m )
{
    PANEL* P = &(teto->P);
    BLOCK* mbp = m->b;
    int x = P->p.x + m->p.x + m->cp.x;
    int y = P->p.y + m->p.y + m->cp.y;

    clrB(mbp,x,y); mbp++;
    clrB(mbp,x,y); mbp++;
    clrB(mbp,x,y); mbp++;
    clrB(mbp,x,y); mbp++;
}

void prtGHOSTMINO( TETO* teto, MINO* gm )
{
    clrMINO(teto,gm);
 
    gm->p.x  = teto->cur_mino.p.x + teto->cur_mino.cp.x;
     gm->p.y     = teto->cur_mino.p.y + teto->cur_mino.cp.y;
    gm->cp.x = 0;
    gm->cp.y = 0;
   
    int i;
   
    for(i=0; i<PANEL_H; i++){
        if(mov_dMINO(teto,gm)!=0){break;}
    }

    prtMINO(teto,gm);
}

void initDM(TETO* teto)
{
    int i;
    for(i=0;i<DM_LEN;i++){ initMINO(teto, &(teto->DM[i]),i); }
}

void initGM(TETO* teto)
{
    int i;
      for(i=0;i<DM_LEN;i++){ initGHOSTMINO(teto, &(teto->GM[i]),i); }
}

void newMINO( TETO* teto, MINO* m, MINO* gm)
{
    int i;
    if(teto->cur_rand_box_len<=0){
        for(i=0;i<DM_LEN;i++){teto->rand_box[i+0]=i; teto->rand_box[i+DM_LEN]=i;}
        teto->cur_rand_box_len=DM_LEN;
    }

    int rnd = rand()%(teto->cur_rand_box_len);
    cpyMINO(  m, &(teto->DM[(teto->rand_box[rnd])]) );
    cpyMINO( gm, &(teto->GM[(teto->rand_box[rnd])]) );

    for(i=rnd;i<teto->cur_rand_box_len-1;i++){teto->rand_box[i]=teto->rand_box[i+1];}
    teto->cur_rand_box_len--;
}

void M2P( TETO* teto, MINO* m )
{
    PANEL* P = &(teto->P);
    int i;
    BLOCK* mbp = m->b;
    BLOCK* pbp;

    for(i=0;i<4;i++){
        mbp = &(m->b[i]);

        mbp->p.x += m->p.x + m->cp.x;
        mbp->p.y += m->p.y + m->cp.y;

        pbp = &(P->b[ mbp->p.y*PANEL_W +mbp->p.x ]);
        cpyB(pbp, mbp);
    }
}





int stAI(TETO* teto)
{
    PANEL* P = &(teto->P);
    int i,j;
    int sc=0;
    int h;
    int nl=_COLOR_BLACK;
    BLOCK* bp;
    BLOCK* lbp;
    BLOCK* rbp;
    BLOCK* ubp;
    BLOCK* dbp;
    for(j=1;j<PANEL_H-1;j++){
        bp=&(P->b[j*PANEL_W+1]);
        lbp=bp-1;
        rbp=bp+1;
        ubp=bp-PANEL_W;
        dbp=bp+PANEL_W;
        for(i=1;i<PANEL_W-1;i++){
            if(j>PANEL_H-6){
                if(bp->bg_col!=nl){
                    h=(PANEL_H-j);
                    sc+=h;
                    if(lbp->bg_col!=nl){if(i>=2&&i<=PANEL_W-1){sc-=2;}}
                    if(rbp->bg_col!=nl){if(i>=1&&i<=PANEL_W-2){sc-=2;}}
                    if(lbp->bg_col!=nl){if(i==1)        {sc-=1;}}
                    if(rbp->bg_col!=nl){if(i==PANEL_W-1){sc-=1;}}
                    if(dbp->bg_col==nl){sc+=10;}
                }
                if(bp->bg_col==nl){
                    if(lbp->bg_col!=nl&&ubp->bg_col!=nl){sc+=10;}
                    if(rbp->bg_col!=nl&&ubp->bg_col!=nl){sc+=10;}
                    if(lbp->bg_col!=nl&&rbp->bg_col!=nl&&ubp->bg_col==nl){sc-=1;};
                    if(lbp->bg_col!=nl&&rbp->bg_col!=nl&&ubp->bg_col==nl&&dbp->bg_col==nl){sc-=1;};
                }
            }
            else {
                if(bp->bg_col!=nl){
                    h=(PANEL_H-j);
                    sc+=h*2;
                    if(lbp->bg_col!=nl){if(i>=2&&i<=PANEL_W-1){sc-=2;}}
                    if(rbp->bg_col!=nl){if(i>=1&&i<=PANEL_W-2){sc-=2;}}
                    if(lbp->bg_col!=nl){if(i==1)        {sc-=2;}}
                    if(rbp->bg_col!=nl){if(i==PANEL_W-1){sc-=2;}}
                    if(dbp->bg_col==nl){sc+=10;}
                }
                if(bp->bg_col==nl){
                    if(lbp->bg_col!=nl&&ubp->bg_col!=nl){sc+=10;}
                    if(rbp->bg_col!=nl&&ubp->bg_col!=nl){sc+=10;}
                    if(rbp->bg_col!=nl&&lbp->bg_col!=nl){sc+=5;}
//                    if(lbp->bg_col!=nl&&rbp->bg_col!=nl&&ubp->bg_col==nl){sc-=1;};
//                    if(lbp->bg_col!=nl&&rbp->bg_col!=nl&&ubp->bg_col==nl&&dbp->bg_col==nl){sc-=1;};
                }
            }

            bp++;
            lbp=bp-1;
            rbp=bp+1;
            ubp=bp-PANEL_W;
            dbp=bp+PANEL_W;
        }
    }
   
    return(sc);
}

void sncAI(TETO* teto, MINO* cm)
{
      PANEL* CPP = &(teto->AI.CPP);
    MINO* CPM = &(teto->AI.CPM);
    int* CTV = &(teto->AI.CTV);
    int* CTH = &(teto->AI.CTH);
    int* CTR = &(teto->AI.CTR);
    PANEL* P = &(teto->P);
    int i,j,k,l;
    int ls=0xFFFFFFF;
    int sp=cm->p.x;
    int    tv=0,th=0,tr=0;
    BLOCK* pbp=P->b;
    BLOCK* cbp=CPP->b;
    for(i=0;i<PANEL_H*PANEL_W;i++){*cbp++ = *pbp++;}
    cpyMINO( CPM, cm );

    for(l=0;l<4;l++){
        for(k=1;k<PANEL_W-1;k++){
            pbp=P->b;
            cbp=CPP->b;
            for(i=0;i<PANEL_H*PANEL_W;i++){*pbp++ = *cbp++;}
            cpyMINO( cm, CPM );
           
            for(i=0;i<l;i++){ tr=l; rot_lMINO(teto,cm); }
           
            int hm=k-sp;
            th=0;
            if(hm<0){
                hm=-hm;
                for(i=0;i<hm;i++){ th--; mov_lMINO(teto,cm); }
            }
            else {
                for(i=0;i<hm;i++){ th++; mov_rMINO(teto,cm); }
            }
            tv=0;
            for(j=0;j<PANEL_H-1;j++){
                tv++;
                if(mov_dMINO(teto,cm)!=0){break;}
            }

            M2P(teto,cm);
            int st=stAI(teto);
            if(st<ls){ls=st;*CTH=th;*CTV=tv;*CTR=tr;}
        }
    }
 
    pbp=P->b;
    cbp=CPP->b;
    for(i=0;i<PANEL_H*PANEL_W;i++){*pbp++ = *cbp++;}
    cpyMINO( cm, CPM );
}






void initTETO(TETO* teto, int pmd, int x, int y, int nx, int ny )
{
    int i;
    for(i=0;i<PANEL_H;i++){teto->comp_line[i]=0;}
    teto->cur_flsP=0;
    for(i=0;i<DM_LEN*2;i++){teto->rand_box[i]=i%7;}    //={0,1,2,3,4,5,6,0,1,2,3,4,5,6};
    teto->cur_rand_box_len=DM_LEN*2;
    teto->snc=0;
    teto->f=0;
   
    teto->pmd=pmd;
    teto->nmp.x=nx; teto->nmp.y=ny;
    teto->cmp.x=6;  teto->cmp.y=3;
   
    initP(teto,x,y);
    initNP(teto,nx-2,ny-2);
    initDM(teto);
    initGM(teto);
   
    newMINO( teto, &teto->next_mino, &teto->next_ghost_mino);
    cpyMINO( &teto->cur_mino,         &teto->next_mino );        teto->cur_mino.p.x= teto->cmp.x;    teto->cur_mino.p.y= teto->cmp.y;
    cpyMINO( &teto->cur_ghost_mino,    &teto->next_ghost_mino );

    newMINO( teto, &teto->next_mino, &teto->next_ghost_mino);    teto->next_mino.p.x= teto->nmp.x;    teto->next_mino.p.y= teto->nmp.y;
   
    teto->ojl=0;
    teto->ojls=rand()%(PANEL_W-1-1);

    teto->awt  = 60;    // 1s
    teto->cawt = 0;
   
    PAD1=0;
    PAD2=0;
}

int calcTETO(TETO* teto, unsigned short pad, int dp)
{
    int ret = 0;
   
    if(teto->pmd==MUJINKUN){return(0);}
   
    teto->cur_ghost_mino.p.y  = teto->cur_mino.p.y;
    teto->cur_ghost_mino.p.x  = teto->cur_mino.p.x;
    teto->cur_ghost_mino.cp.y = teto->cur_mino.cp.y;
    teto->cur_ghost_mino.cp.x = teto->cur_mino.cp.x;
    prtGHOSTMINO(teto, &teto->cur_ghost_mino);
    prtMINO(teto,&teto->cur_mino);

    if(teto->pmd==KIKAI){
        if(teto->f==0&&teto->snc==0){
            sncAI(teto,&teto->cur_mino);teto->snc=1;
        }

        if(teto->snc==1){
            if(teto->AI.CTR>=1){ teto->AI.CTR--; pad|=PAD_R_LEFT;}
            else if(teto->AI.CTH>=+1){ teto->AI.CTH--; pad|=PAD_L_RIGHT;}
            else if(teto->AI.CTH<=-1){ teto->AI.CTH++; pad|=PAD_L_LEFT;}
            else { pad|=PAD_L_DOWN;}
        }
    }
   
    if(teto->f==0){
        if( ((pad&PAD_L_DOWN)!=0) || dp==1 || ((pad&PAD_L_UP)!=0) ){
            clrMINO(teto,&teto->cur_mino);   

            if( (pad&PAD_L_UP)!=0 ) {
                while(mov_dMINO(teto,&teto->cur_mino)==0){;}
            }
   
            if(mov_dMINO(teto,&teto->cur_mino)!=0){
                teto->cawt++;
                if((pad&PAD_L_UP)!=0){ teto->cawt = teto->awt; }
            }
           
            prtMINO(teto,&teto->cur_mino);
        }
       
        if(teto->cawt > 0){
            clrMINO(teto,&teto->cur_mino);   

            if(mov_dMINO(teto,&teto->cur_mino)!=0){
                if(teto->cawt >= teto->awt){
                    teto->cawt=0;
                 
                    if(teto->ojl>0){teto->f=30;}
                 
                    teto->snc=0;
                    M2P(teto,&teto->cur_mino);
                    prtP(teto);
                                   
                    clrMINO(teto,&teto->next_mino);   
                    cpyMINO( &teto->cur_mino, &teto->next_mino );    teto->cur_mino.p.x = teto->cmp.x;    teto->cur_mino.p.y = teto->cmp.y;
                    cpyMINO( &teto->cur_ghost_mino, &teto->next_ghost_mino );
                   
                    newMINO( teto, &teto->next_mino, &teto->next_ghost_mino );
                    teto->next_mino.p.x= teto->nmp.x;    teto->next_mino.p.y= teto->nmp.y;
                   
                    prtMINO(teto,&teto->next_mino);
                }
                else{
                    teto->cawt++;
                }
            }
            else{
                teto->cawt=0;
            }
           
            prtMINO(teto,&teto->cur_mino);
        }
           
        if(pad&PAD_L_LEFT ){
            clrMINO(teto, &teto->cur_mino);    mov_lMINO(teto, &teto->cur_mino);
            prtGHOSTMINO(teto, &teto->cur_ghost_mino);    prtMINO(teto,&teto->cur_mino);
        }
        if(pad&PAD_L_RIGHT){
            clrMINO(teto, &teto->cur_mino);    mov_rMINO(teto, &teto->cur_mino);
            prtGHOSTMINO(teto, &teto->cur_ghost_mino);    prtMINO(teto,&teto->cur_mino);
        }
       
        if(pad&PAD_R_UP   ){
            clrMINO(teto, &teto->cur_mino);                clrMINO(teto, &teto->cur_ghost_mino);
            teto->cur_ghost_mino.p.y  = teto->cur_mino.p.y;
            teto->cur_ghost_mino.p.x  = teto->cur_mino.p.x;
            teto->cur_ghost_mino.cp.y = teto->cur_mino.cp.y;
            teto->cur_ghost_mino.cp.x = teto->cur_mino.cp.x;
            rot_rMINO(teto, &teto->cur_mino);            rot_rMINO(teto, &teto->cur_ghost_mino);
            prtGHOSTMINO(teto, &teto->cur_ghost_mino);    prtMINO(teto,&teto->cur_mino);
        }
        if(pad&PAD_R_LEFT ){
            clrMINO(teto, &teto->cur_mino);                clrMINO(teto, &teto->cur_ghost_mino);
            teto->cur_ghost_mino.p.y  = teto->cur_mino.p.y;
            teto->cur_ghost_mino.p.x  = teto->cur_mino.p.x;
            teto->cur_ghost_mino.cp.y = teto->cur_mino.cp.y;
            teto->cur_ghost_mino.cp.x = teto->cur_mino.cp.x;
            rot_lMINO(teto, &teto->cur_mino);            rot_lMINO(teto, &teto->cur_ghost_mino);
            prtGHOSTMINO(teto, &teto->cur_ghost_mino);    prtMINO(teto,&teto->cur_mino);
        }
    }
   
    if(teto->f==0){
        ret=chkP(teto); if(ret!=0){teto->f=1;}
    }
    else if(teto->f>=1&&teto->f<=6){
        flsP(teto);teto->f++; prtP(teto); prtMINO(teto,&teto->cur_mino);
    }
    else if(teto->f==7) {
        dllP(teto); prtP(teto); prtMINO(teto,&teto->cur_mino); teto->f++;
    }
    else if(teto->f>=8&&teto->f<=11) {
        dwnP(teto); prtP(teto); prtMINO(teto,&teto->cur_mino); teto->f++;
    }
    else if(teto->f==12){
        prtP(teto);

        teto->cur_ghost_mino.p.y  = teto->cur_mino.p.y;
        teto->cur_ghost_mino.p.x  = teto->cur_mino.p.x;
        teto->cur_ghost_mino.cp.y = teto->cur_mino.cp.y;
        teto->cur_ghost_mino.cp.x = teto->cur_mino.cp.x;
        prtGHOSTMINO(teto, &teto->cur_ghost_mino);    prtMINO(teto,&teto->cur_mino);

        teto->f=0;
    }
   
    if(teto->f==30){
        ojlP(teto);
        prtP(teto);
        prtMINO(teto,&teto->cur_mino);
        teto->ojl--;
        if(teto->ojl<=0){teto->f=0;}

        ret=chkP(teto);
        if(ret!=0){teto->f=1;}
    }
   
    return(ret);
}




#ifdef __OSASK__
int G01Main()
#else
int main()
#endif //__OSASK__
{
    int e = 0;
    int i;

    TETO             t[2];
    int                dll[2];
   
    int                wt=20;
    int                cwt=0;
    int                dp=0;
   
    init_sys();
    initTETO(&t[0], NINGEN,   1, -4,   15,7 );        initTETO(&t[1], KIKAI,   27, -4,   -4,7 );
//    initTETO(&t[0], KIKAI,    1, -4,   15,7 );        initTETO(&t[1], KIKAI,   27, -4,   -4,7 );
//    initTETO(&t[0], NINGEN,   1, -4,   15,7 );        initTETO(&t[1], MUJINKUN,27, -4,   -4,7 );
   
    clr_scr();
   
    prtP(&t[0]);                    prtP(&t[1]);
    prtNP(&t[0]);                    prtNP(&t[1]);
    prtMINO(&t[0],&t[0].next_mino);    prtMINO(&t[1],&t[1].next_mino);   
   
    do{
        dll[0] = calcTETO(&t[0],PAD1,dp);
        dll[1] = calcTETO(&t[1],PAD2,dp);
        if( dll[0] >= 1 ){ t[1].ojl += dll[0]-1; }
        if( dll[1] >= 1 ){ t[0].ojl += dll[1]-1; }
       
        vsync(1);
        syncPAD();
        dp=0;if(cwt++>=wt){dp=1;cwt=0;}
    } while((PAD1&PAD_START)==0);

    close_sys();
    return(0);
}




teto (0.0.3)
なんか efg01 にタイマーあるみたいなんでテトリスつくろうと思った。
えっ?クリスマス? なんすか?それ(まさに自分とのたたかい・_;ほろり

20091223_01.jpg

「どうせなら、CPU対戦できるように、AIを書いちゃおうかなぁ…(^_^;だれもやってなさそうだし」
って思ってとりあえずAI書いたんだけど、なんか、ことのほか強くなってしまって、なんか

「これ・・・勝てる人間いるのか・・・?(涙orz」

みたいな…w

アルゴリズムはチェスのAIとかでお馴染みの、基本的な「総当たりして最適解をみつける」って方法なんですが、
実は「現在のミノ」だけで最適解を考慮してて、まだ「次の予定のミノ」は考慮してないので、ほんとうはこれをやれば
さらに強くなる余地が有ります…(処理ステップが指数関数的に増えますが)

いや・・・すでにもぅ人間じゃ勝てなさそうなレベルだし、もぅ充分でしょうけど…ははw(orz



コンパイル済みのバイナリコードです。(操作方法、何かキーを押しっぱなしで動きます。 終了は q です)
linux用 teto_linux.mp3  実行方法は ./t
win用(OSASKバイナリー)teto_win.mp3 実行方法は efg01.exe teto.g01
(*:拡張子を mp3 から zip に書き換えて、zip解凍してください。)(←fc2はzipをアップロードできないので)

ソースです。
コンパイルはlinuxで gcc -o t teto.c -lc
./t
です。
OSASKのtolsetでもコンパイルできます。その場合一行目の#define__OSASK__を有効にしてね。

teto.c (0.0.3)
//#define __OSASK__

#ifdef __OSASK__

#include <guigui01.h>
#include <stdio.h>
#include <stdlib.h>

#define _COLOR_BLACK     0
#define _COLOR_RED         2
#define _COLOR_GREEN    3
#define _COLOR_YELLO    4
#define _COLOR_BLUE        5
#define _COLOR_PARPLE    6
#define _COLOR_LBLUE    7
#define _COLOR_WHITE    8

void vsync(int w)
{
    int i;
    for(i=0;i<w;i++){
        jg01_sleep1(32-5, 1);        // x = 32-5 = 27,   weit_time = 2^(x-32) = 2^(27-32) = 2^(-5) = 1/32
    }
}

void set_put_c_color( int s_color, int bg_color )
{
    jg01_consctrl2( s_color, bg_color );
}

void put_c( unsigned char c )
{
    g01_putc(c);
}

unsigned char get_c( void )
{
    return( (unsigned char)jg01_inkey3() );
}

void set_cur( int x, int y )
{
    jg01_consctrl1(x,y);
}

void clr_scr(void)
{
    jg01_consctrl3();
}

void init_sys(void)
{
    srand(jg01_randomseed());

    jg01_consctrl4(80,25);
    jg01_consctrl2(15,0);
}

void close_sys(void)
{
    clr_scr();
    set_put_c_color( 7, 0 );
}

#endif // __OSASK__

#ifndef __OSASK__

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include <unistd.h>
#include <termios.h>
#include <sys/time.h>

#define _COLOR_BLACK     1
#define _COLOR_RED         2
#define _COLOR_GREEN    3
#define _COLOR_YELLO    4
#define _COLOR_BLUE        5
#define _COLOR_PARPLE    6
#define _COLOR_LBLUE    7
#define _COLOR_WHITE    8

static int flg_init_termios = 0;
static struct termios save_term;
static struct termios temp_term;

void vsync(int w)
{
    getchar();
}

void set_put_c_color( int s_color, int bg_color )
{
    switch(s_color){
    case _COLOR_BLACK:    printf("%c[%dm",0x1b, 30 ); break;
    case _COLOR_RED:    printf("%c[%dm",0x1b, 31 ); break;
    case _COLOR_GREEN:    printf("%c[%dm",0x1b, 32 ); break;
    case _COLOR_YELLO:    printf("%c[%dm",0x1b, 33 ); break;
    case _COLOR_BLUE:    printf("%c[%dm",0x1b, 34 ); break;
    case _COLOR_PARPLE:    printf("%c[%dm",0x1b, 35 ); break;
    case _COLOR_LBLUE:    printf("%c[%dm",0x1b, 36 ); break;
    case _COLOR_WHITE:    printf("%c[%dm",0x1b, 37 ); break;
    default:             printf("%c[%dm",0x1b, 0  ); break;
    }

    switch(bg_color){
    case _COLOR_BLACK:    printf("%c[%dm",0x1b, 40 ); break;
    case _COLOR_RED:    printf("%c[%dm",0x1b, 41 ); break;
    case _COLOR_GREEN:    printf("%c[%dm",0x1b, 42 ); break;
    case _COLOR_YELLO:    printf("%c[%dm",0x1b, 43 ); break;
    case _COLOR_BLUE:    printf("%c[%dm",0x1b, 44 ); break;
    case _COLOR_PARPLE:    printf("%c[%dm",0x1b, 45 ); break;
    case _COLOR_LBLUE:    printf("%c[%dm",0x1b, 46 ); break;
    case _COLOR_WHITE:    printf("%c[%dm",0x1b, 47 ); break;
    default:             printf("%c[%dm",0x1b, 0  ); break;
    }
}

void put_c( unsigned char c )
{
    putchar((int)c);
}

unsigned char get_c( void )
{
    return( (unsigned char)getchar() );
}

void set_cur( int x, int y )
{
    printf("%c[%d;%dH",0x1b, y+1, x+1 );
}

void clr_scr(void)
{
    printf("%c[2J",0x1B );
}

void init_sys(void)
{
    if( flg_init_termios == 0 ) {
          tcgetattr(fileno(stdin), &save_term);
          temp_term = save_term;
          temp_term.c_iflag &= IGNCR;
          temp_term.c_lflag &= ~ICANON;
          temp_term.c_lflag &= ~ECHO;
          temp_term.c_lflag &= ~ISIG;
          temp_term.c_cc[VMIN]=1;
          temp_term.c_cc[VTIME]=0;
          tcsetattr(fileno(stdin), TCSANOW, &temp_term);
    }
    flg_init_termios += 1;                                    // ユニークカウンタ(これでシステム全体での起動数を把握しておく)

    srand((unsigned int)time(0));
}

void close_sys(void)
{
    flg_init_termios -= 1;                                    // ユニークカウンタを一つ減らす
    if( flg_init_termios == 0 ) {
        tcsetattr(fileno(stdin), TCSANOW, &save_term );        // すべては、これを複数回起動してしまうのを防止するため。(ユニークカウンタ
    }

    clr_scr();
    set_put_c_color( 0, 0 );
    put_c( '\n');
}

#endif // __OSASK__




typedef struct tagPOS {
    int x;
    int y;
} POS;

typedef struct tagBLOCK {
    unsigned char     b[2];
    POS                p;
    int                str_col;
    int                bg_col;
} BLOCK;

void initB(BLOCK* B)
{
    B->b[0]        =' ';
    B->b[1]        =' ';
    B->p.x        =0;
    B->p.y        =0;
    B->str_col    =0;
    B->bg_col     =0;
}

void cpyB(BLOCK* dst, BLOCK* src )
{
    dst->b[0]        = src->b[0];
    dst->b[1]        = src->b[1];
    dst->p.x         = src->p.x;
    dst->p.y         = src->p.y;
    dst->str_col     = src->str_col;
    dst->bg_col     = src->bg_col;
}

void posB(BLOCK* b, int x, int y)
{
    b->p.x=x;
    b->p.y=y;
}

void colB(BLOCK* b, int col)
{
    switch(col){
    case 0:    b->str_col = b->bg_col = _COLOR_BLACK;    break;
//    case 0:    b->str_col = b->bg_col = 0;                break;
    case 1:    b->str_col = b->bg_col = _COLOR_WHITE;    break;
    case 2:    b->str_col = b->bg_col = _COLOR_RED;    break;
    case 3:    b->str_col = b->bg_col = _COLOR_GREEN;    break;
    case 4:    b->str_col = b->bg_col = _COLOR_BLUE;    break;
    case 5:    b->str_col = b->bg_col = _COLOR_YELLO;    break;
    case 6:    b->str_col = b->bg_col = _COLOR_LBLUE;    break;
    case 7:    b->str_col = b->bg_col = _COLOR_PARPLE;    break;
    }
}

void prtB(BLOCK* b, int x, int y)
{
    set_put_c_color(b->str_col,b->bg_col);

    set_cur(2*(b->p.x+x)+0,b->p.y+y+0);        put_c(b->b[0]);
    set_cur(2*(b->p.x+x)+1,b->p.y+y+0);        put_c(b->b[1]);

    set_put_c_color(0,0);   
}

void clrB(BLOCK* b, int x, int y)
{
    set_put_c_color(_COLOR_BLACK,_COLOR_BLACK);

    set_cur(2*(b->p.x+x)+0,b->p.y+y+0);        put_c(b->b[0]);
    set_cur(2*(b->p.x+x)+1,b->p.y+y+0);        put_c(b->b[1]);

    set_put_c_color(0,0);   
}

#define PANEL_W        11
#define PANEL_H        22
typedef struct tagPANEL {
    BLOCK     b[PANEL_W*PANEL_H*10];
    POS        p;
} PANEL;

static PANEL P;

void initP(int x, int y)
{
    int i,j;
    BLOCK* bp;
   
    P.p.x=x;
    P.p.y=y;
   
    for(j=0;j<PANEL_H;j++) {
        i=0;
        bp=&(P.b[j*PANEL_W]);
     
        switch(j){
        case PANEL_H-1:
            for(i=-0;i<PANEL_W;i++) {
                initB(bp); posB(bp,i,j); colB(bp,1); bp++;
            }
            break;

        default:
            initB(bp); posB(bp,i,j); colB(bp,1); bp++;
            for(i=1;i<PANEL_W-1;i++) {
                initB(bp); posB(bp,i,j); colB(bp,0); bp++;
            }
            initB(bp); posB(bp,i,j); colB(bp,1); bp++;
            break;
        }
    }   
}

static int comp_line[PANEL_H] = {0,0,0,0,0,    0,0,0,0,0,    0,0,0,0,0,    0,0,0,0,0,    0,0};
int chkP(void)
{
    int j,i;
    int c;
    int ret =0;
    BLOCK* bp;
   
    for(j=0;j<PANEL_H-1;j++){
        bp=&(P.b[j*PANEL_W+1]);
        c=0;
        for(i=1;i<PANEL_W-1;i++){
            if( bp->bg_col != _COLOR_BLACK ){ c++; }
            bp++;
        }
        if(c==PANEL_W-1-1) {
            comp_line[j]=1;
            ret++;
        }
        else {
            comp_line[j]=0;
        }
    }
   
    return(ret);
}

static int cur_flsP=0;
int flsP(void)
{
    int i,j;
    BLOCK* bp;
    int ret = 0;
   
    int col;
    switch(cur_flsP) {
    case 0: col=_COLOR_LBLUE;    cur_flsP=1;    break;
    case 1: col=_COLOR_YELLO;     cur_flsP=0;    break;
    }
     
    for(j=0;j<PANEL_H-1;j++){
        if(comp_line[j]!=0){
            bp = &(P.b[j*PANEL_W+1]);
            for(i=1;i<PANEL_W-1;i++){
                bp->str_col = col;
                bp->bg_col  = col;
                bp++;
            }
        }
    }

    return(ret);
}

void dllP(void)
{
    int i,j;
    BLOCK* bp;
   
    for(j=0;j<PANEL_H-1;j++){
        if(comp_line[j]!=0){
            bp = &(P.b[j*PANEL_W+1]);
            for(i=1;i<PANEL_W-1;i++){
                bp->str_col = _COLOR_BLACK;
                bp->bg_col  = _COLOR_BLACK;
                bp++;
            }
        }
    }
}

int dwnP(void)
{
    int i,j;
    BLOCK* bp;
    BLOCK* ubp;
    int c;
    int ret=0;
   
    for(j=PANEL_H-1-1; j>0; j--){
        bp = &(P.b[j*PANEL_W+1]);
        c=0;
        for(i=1;i<PANEL_W-1;i++){
            if( bp->bg_col == _COLOR_BLACK ) { c++; };
            bp++;
        }
        if(c==PANEL_W-1-1){
            bp  = &(P.b[(j+0)*PANEL_W+1]);
            ubp = &(P.b[(j-1)*PANEL_W+1]);
            for(i=1;i<PANEL_W-1;i++){
                bp->str_col = ubp->str_col;
                bp->bg_col  = ubp->bg_col;
                ubp->str_col = _COLOR_BLACK;
                ubp->bg_col  = _COLOR_BLACK;
                bp++;
                ubp++;
            }
           
            ret++;
        }
    }
   
    return(ret);
}

void prtP(void)
{
    int i,j;
    BLOCK* bp;
   
    for(j=0;j<PANEL_H;j++){
        i=0;
        bp=&(P.b[j*PANEL_W]);
       
        for(i=0;i<PANEL_W;i++){
              prtB(bp++,P.p.x, P.p.y);
        }
    }
}

int apB(BLOCK* b,int x, int y)
{
    int cx=b->p.x+x;
    int cy=b->p.y+y;

    switch( P.b[cy*PANEL_W+cx].bg_col ){
    case _COLOR_BLACK:    return(0);    break;
    default:            return(1);    break;
    }
}


typedef struct tagMINO {
    BLOCK     b[4];
    POS        p;
} MINO;

void initMINO(MINO* m, int t)
{
    int i;
    register BLOCK* bp = m->b;

    m->p.x = 3;
    m->p.y = 2;
       
    initB(bp++);    initB(bp++);    initB(bp++);    initB(bp++);

    bp = m->b;   
    switch(t) {
    case 0:    colB(bp++,1);    colB(bp++,1);    colB(bp++,1);    colB(bp++,1);    break;
    case 1:    colB(bp++,2);    colB(bp++,2);    colB(bp++,2);    colB(bp++,2);    break;
    case 2:    colB(bp++,3);    colB(bp++,3);    colB(bp++,3);    colB(bp++,3);    break;
    case 3:    colB(bp++,4);    colB(bp++,4);    colB(bp++,4);    colB(bp++,4);    break;
    case 4:    colB(bp++,5);    colB(bp++,5);    colB(bp++,5);    colB(bp++,5);    break;
    case 5:    colB(bp++,6);    colB(bp++,6);    colB(bp++,6);    colB(bp++,6);    break;
    case 6:    colB(bp++,7);    colB(bp++,7);    colB(bp++,7);    colB(bp++,7);    break;
    }   
   
    bp = m->b;   
    switch(t) {
    case 0:    posB(bp++,0,-1);    posB(bp++,0,0);        posB(bp++,0,1);        posB(bp++,0,2);        break;        // ----
    case 1:    posB(bp++,0,0);        posB(bp++,0,1);        posB(bp++,1,0);        posB(bp++,1,1);        break;        // []
    case 2:    posB(bp++,-1,0);    posB(bp++,0,0);        posB(bp++,1,0);        posB(bp++,0,-1);    break;        // T
    case 3:    posB(bp++,-1,0);    posB(bp++,0,0);        posB(bp++,0,1);        posB(bp++,1,1);        break;        // N
    case 4:    posB(bp++,-1,1);    posB(bp++,0,1);        posB(bp++,0,0);        posB(bp++,1,0);        break;        // !N
    case 5:    posB(bp++,0,-1);    posB(bp++,0,0);        posB(bp++,0,1);        posB(bp++,1,1);        break;        // L
    case 6:    posB(bp++,0,-1);    posB(bp++,0,0);        posB(bp++,0,1);        posB(bp++,-1,1);    break;        // !L
    }
}

void cpyMINO( MINO* dst, MINO* src )
{
    dst->p.x = src->p.x;
    dst->p.y = src->p.y;

    BLOCK* dbp = dst->b;
    BLOCK* sbp = src->b;
    cpyB(dbp++,sbp++);    cpyB(dbp++,sbp++);    cpyB(dbp++,sbp++);    cpyB(dbp++,sbp++);
}

int apMINO(MINO* m)
{
    int i;
    int x=m->p.x;
    int y=m->p.y;
    int ret=0;
    BLOCK* bp = m->b;
    ret+=apB(bp++,x,y);    ret+=apB(bp++,x,y);    ret+=apB(bp++,x,y);    ret+=apB(bp++,x,y);
   
    return(ret);
}

void __rotMINO( MINO* m, int r )
{
    BLOCK* bp = m->b;
   
    if(r >= +1){
        posB(bp, +bp->p.y,-bp->p.x ); bp++;
        posB(bp, +bp->p.y,-bp->p.x ); bp++;
        posB(bp, +bp->p.y,-bp->p.x ); bp++;
        posB(bp, +bp->p.y,-bp->p.x );
    }
    else if( r <= -1){
        posB(bp, -bp->p.y,+bp->p.x ); bp++;
        posB(bp, -bp->p.y,+bp->p.x ); bp++;
        posB(bp, -bp->p.y,+bp->p.x ); bp++;
        posB(bp, -bp->p.y,+bp->p.x );       
    }
}

void rot_rMINO( MINO* m )
{
    __rotMINO( m, -1 );   
    if(apMINO(m)!=0){ __rotMINO( m, +1 ); }
}

void rot_lMINO( MINO* m )
{
    __rotMINO( m, +1 );   
    if(apMINO(m)!=0){ __rotMINO( m, -1 ); }
}

int __movMINO(MINO* m, int x, int y)
{
    m->p.x+=x;    m->p.y+=y;
   
    if(apMINO(m)!=0){
        m->p.x-=x;    m->p.y-=y;
        return(1);
    }
    return(0);
}

int mov_dMINO(MINO* m)
{
    return(__movMINO(m,0,1));
}

int mov_rMINO(MINO* m)
{
    return(__movMINO(m,+1,0));
}

int mov_lMINO(MINO* m)
{
    return(__movMINO(m,-1,0));
}

void prtMINO( MINO* m )
{
    BLOCK* mbp = m->b;
    int x = P.p.x + m->p.x;
    int y = P.p.y + m->p.y;
   
    prtB(mbp++,x,y);    prtB(mbp++,x,y);    prtB(mbp++,x,y);    prtB(mbp++,x,y);
}

void clrMINO( MINO* m )
{
    BLOCK* mbp = m->b;
    int x = P.p.x + m->p.x;
    int y = P.p.y + m->p.y;
   
    clrB(mbp++,x,y);    clrB(mbp++,x,y);    clrB(mbp++,x,y);    clrB(mbp++,x,y);
}

#define DM_LEN 7
static MINO DM[DM_LEN];
void initDM(void)
{
    int i;
    for(i=0;i<DM_LEN;i++){ initMINO(&DM[i],i); }
}

static int rand_box[DM_LEN*2]={0,1,2,3,4,5,6,0,1,2,3,4,5,6};
static int cur_rand_box_len=DM_LEN*2;
void newMINO( MINO* m )
{
    int i;
    if(cur_rand_box_len<=0){
        for(i=0;i<DM_LEN;i++){rand_box[i+0]=i; rand_box[i+DM_LEN]=i;}
        cur_rand_box_len=DM_LEN;
    }

    int rnd = rand()%(cur_rand_box_len);
    cpyMINO( m, &DM[rand_box[rnd]] );

    for(i=rnd;i<cur_rand_box_len-1;i++){rand_box[i]=rand_box[i+1];}
    cur_rand_box_len--;
}

void M2P( MINO* m )
{
    int i;
    BLOCK* mbp = m->b;
    BLOCK* pbp;

    for(i=0;i<4;i++){
        mbp = &(m->b[i]);

        mbp->p.x += m->p.x;
        mbp->p.y += m->p.y;

        pbp = &(P.b[ mbp->p.y*PANEL_W +mbp->p.x ]);
        cpyB(pbp, mbp);
    }
}







typedef struct tagAI {
} __AI;
//struct __AI AI;
static PANEL     CPP;
static MINO      CPM;
static int        CTV,CTH,CTR;
int stAI()
{
    int i,j;
    int sc=0;
    int h;
    int nl=_COLOR_BLACK;
    BLOCK* bp;
    BLOCK* lbp;
    BLOCK* rbp;
    BLOCK* ubp;
    BLOCK* dbp;
    for(j=1;j<PANEL_H-1;j++){
        bp=&(P.b[j*PANEL_W+1]);
        lbp=bp-1;
        rbp=bp+1;
        ubp=bp-PANEL_W;
        dbp=bp+PANEL_W;
        for(i=1;i<PANEL_W-1;i++){
            if(j>PANEL_H-6){
                if(bp->bg_col!=nl){
                    h=(PANEL_H-j);
                    sc+=h;
                    if(lbp->bg_col!=nl){if(i>=2&&i<=PANEL_W-1){sc-=2;}}
                    if(rbp->bg_col!=nl){if(i>=1&&i<=PANEL_W-2){sc-=2;}}
                    if(lbp->bg_col!=nl){if(i==1)        {sc-=1;}}
                    if(rbp->bg_col!=nl){if(i==PANEL_W-1){sc-=1;}}
                    if(dbp->bg_col==nl){sc+=10;}
                }
                if(bp->bg_col==nl){
                    if(lbp->bg_col!=nl&&ubp->bg_col!=nl){sc+=10;}
                    if(rbp->bg_col!=nl&&ubp->bg_col!=nl){sc+=10;}
                    if(lbp->bg_col!=nl&&rbp->bg_col!=nl&&ubp->bg_col==nl){sc-=1;};
                    if(lbp->bg_col!=nl&&rbp->bg_col!=nl&&ubp->bg_col==nl&&dbp->bg_col==nl){sc-=1;};
                }
            }
            else {
                if(bp->bg_col!=nl){
                    h=(PANEL_H-j);
                    sc+=h*2;
                    if(lbp->bg_col!=nl){if(i>=2&&i<=PANEL_W-1){sc-=2;}}
                    if(rbp->bg_col!=nl){if(i>=1&&i<=PANEL_W-2){sc-=2;}}
                    if(lbp->bg_col!=nl){if(i==1)        {sc-=2;}}
                    if(rbp->bg_col!=nl){if(i==PANEL_W-1){sc-=2;}}
                    if(dbp->bg_col==nl){sc+=10;}
                }
                if(bp->bg_col==nl){
                    if(lbp->bg_col!=nl&&ubp->bg_col!=nl){sc+=10;}
                    if(rbp->bg_col!=nl&&ubp->bg_col!=nl){sc+=10;}
                    if(rbp->bg_col!=nl&&lbp->bg_col!=nl){sc+=5;}
//                    if(lbp->bg_col!=nl&&rbp->bg_col!=nl&&ubp->bg_col==nl){sc-=1;};
//                    if(lbp->bg_col!=nl&&rbp->bg_col!=nl&&ubp->bg_col==nl&&dbp->bg_col==nl){sc-=1;};
                }
            }

            bp++;
            lbp=bp-1;
            rbp=bp+1;
            ubp=bp-PANEL_W;
            dbp=bp+PANEL_W;
        }
    }
   
    return(sc);
}

void sncAI(MINO* cm)
{
    int i,j,k,l;
    int ls=0xFFFFFFF;
    int sp=cm->p.x;
    int    tv=0,th=0,tr=0;
    BLOCK* pbp=P.b;
    BLOCK* cbp=CPP.b;
    for(i=0;i<PANEL_H*PANEL_W;i++){*cbp++ = *pbp++;}
    cpyMINO( &CPM, cm );

    for(l=0;l<4;l++){
        for(k=1;k<PANEL_W-1;k++){
            pbp=P.b;
            cbp=CPP.b;
            for(i=0;i<PANEL_H*PANEL_W;i++){*pbp++ = *cbp++;}
            cpyMINO( cm, &CPM );
           
            for(i=0;i<l;i++){ tr=l; rot_lMINO(cm); }
           
            int hm=k-sp;
            th=0;
            if(hm<0){
                hm=-hm;
                for(i=0;i<hm;i++){ th--; mov_lMINO(cm); }
            }
            else {
                for(i=0;i<hm;i++){ th++; mov_rMINO(cm); }
            }
            tv=0;
            for(j=0;j<PANEL_H-1;j++){
                tv++;
                if(mov_dMINO(cm)!=0){break;}
            }

            M2P(cm);
//            clr_scr();
//            prtP();
            int st=stAI();
//            set_cur(0,3);
//            set_put_c_color(0,0);
//            printf("st=%d, ",st);
//            get_c();
            if(st<ls){ls=st;CTH=th;CTV=tv;CTR=tr;}
        }
    }
 
    pbp=P.b;
    cbp=CPP.b;
    for(i=0;i<PANEL_H*PANEL_W;i++){*pbp++ = *cbp++;}
    cpyMINO( cm, &CPM );
   
//    CTR=3;
//    CTH=5;
}












#ifdef __OSASK__
int G01Main()
#else
int main()
#endif //__OSASK__
{
    unsigned char ky;
    int e = 0;
    int f=0;
    int snc=0;
   
    init_sys();
    initP(10,1);
    initDM();

    clr_scr();

    MINO cur_mino;
    MINO next_mino;    newMINO( &next_mino );
    cpyMINO( &cur_mino, &next_mino );
    newMINO( &next_mino );                 next_mino.p.x= 14;        prtMINO(&next_mino);

    prtP();
   
    do{
//clr_scr();
//        M2P(&DM[2]);
//        prtP();
        prtMINO(&cur_mino);
       
        ky=get_c();
        if(f==0&&snc==0){
            sncAI(&cur_mino);snc=1;
//            set_cur(0,0);
//            set_put_c_color(0,0);
//            printf("CTH=%d, CTV=%d, CTR=%d",CTH,CTV,CTR);
        }
        if(snc==1){
//            set_cur(0,1);
//            set_put_c_color(0,0);
//            printf("CTH=%d, CTV=%d, CTR=%d",CTH,CTV,CTR);
            if(ky=='q'){break;}
       
            if(CTR>=1){ CTR--; ky='u';}
            else if(CTH>=+1){ CTH--; ky='l';}
            else if(CTH<=-1){ CTH++; ky='j';}
            else { ky='k';}
        }
       
        switch(ky){
//        case 'n':
//            cpyMINO( &cur_mino, &next_mino );
//            newMINO( &next_mino );
//            break;
           
        case 'k':
            clrMINO(&cur_mino);   
            if(mov_dMINO(&cur_mino)!=0){
                snc=0;
                M2P(&cur_mino);
                prtP();
                cpyMINO( &cur_mino, &next_mino );    cur_mino.p.x = 6;
                newMINO( &next_mino );                 next_mino.p.x= 14;        prtMINO(&next_mino);
            }
            prtMINO(&cur_mino);
            break;
           
        case 'j': clrMINO(&cur_mino);    mov_lMINO(&cur_mino);    prtMINO(&cur_mino);        break;
        case 'l': clrMINO(&cur_mino);    mov_rMINO(&cur_mino);    prtMINO(&cur_mino);        break;
       
        case 'i': clrMINO(&cur_mino);    rot_rMINO(&cur_mino);    prtMINO(&cur_mino);        break;
        case 'u': clrMINO(&cur_mino);    rot_lMINO(&cur_mino);    prtMINO(&cur_mino);        break;
       
        case 'q':e=1; close_sys(); return(0);break;
        }
           
        if(f==0){
            if(chkP()!=0){f=1;}
        }
        else if(f>=1&&f<=6){
            flsP();f++;
            prtP();
        }
        else if(f==7) {
            dllP();
            prtP();
            f++;
        }
        else if(f>=8&&f<=11) {
            dwnP();
            prtP();
            f++;
        }
        else {
            prtP();
            f=0;
        }

       
    } while(e==0);

    close_sys();
    return(0);
}

数独(0.0.1)
20091220_sd.jpg

OSASKという自作OSがあって、それのコミュニティにて次世代のOSASKの開発がゆっくり進んでます。
現在はネイティブなOSではなくて、既存のOS上で動作する関数セットのような状態ですが、いちおう動作可能な状態です。

要するにJAVAの仮想マシンみたいなものだとボクは認識してます。
現在の実行環境としては、WindowsとLinux上で同様に動作する efg01 というプログラムに引数として与える形で実行します。

efg01は、現時点ではコンソールへの文字出力と、ファイル入出力、独自形式圧縮ファイルの入出力、
くらいしかサポートしてなくて、
まだグラフィック関連、サウンド関連、通信関連、その他雑多なIO諸々の関数は、まだ作られてない状態みたいです。 
画面に1ドットの点を打つことすらできません。
だから当然、ウインドウマネージャーなどまだ乗ってません。
あと、多バイト文字もサポートされてないので、日本語を表示できません。 UTF8もシフトJISすら表示できません。
まだ文字コードの変換テーブルが実装されてないみたいです。

と、まぁ、要するに今現在、efg01 でサポートしてる処理は「コンソールにAと打つ」って程度です。USBとかDVDRWとか、そういう機器も一切使えません。

この極端に貧弱な命令セットで、いったい何がつくれるの? と疑問に思ってたのですが、
OSASKのコミュニティーを見てると efg01 上で動くゲームを何点か公開してる人がいました。 「これはおもしろいかも…」

なんかDOSみたいで萌えました。いやマジで。


というわけで、何か efg01上で動くプログラムを書いて貢献しようと思いました。
「とりあえずテトリスでも書くか?」
って思ったんですが、どうやらタイマー(時間による制御)関連の使い方がよくわからないので、
タイマーを使わずに作れるゲームにしようと思いました。
そのうち誰かがタイマーを活用したコードを公開するでしょうから、それまで待ちます…w

というわけで数独。

問題のジェネレートは、あらかじめ自力で作った問題を、行列操作で混ぜるだけです。
ほんとうは、自分が問題を作ってるときの思考パターンをプログラムに置き換えて、それによって完全に(種なしで)ジェネレートするアルゴリズムを考える方が有意義なのでしょうけど、
ことのほか自分の自力で問題作るときの方法論は『確実性』がいまいちで、かならずしも毎回生成に成功するわけじゃないんですよね… 無限級数みたいな状態になったりして。
そういう『例外』が「なぜか?」がわかれば、それを糸口にアルゴリズムに確実性を持たせられるんでしょうけど、
どうにもボクの頭じゃ難しいです。
こういう時、数学に詳しい人はいいなぁ〜…ってうらやましく思います。
ルービックキューブの解法を群論で解いたりできる人って、こういうのも余裕でアルゴリズム思いつくんだろうなぁ…と。

もっとも、『ものすごく単純な方法』で、種をジェネレートすることは可能ですが、
その種は規則性が分かり易すぎて、あまり問題としてはおもしろくないんですよね。 反復が見え見えだったりして。
やっぱ、数独の問題は、人間が考えたものの方が面白いと思います。規則性がわかりにくくて。

この、『人間が作る』ってときの、思考パターンをアルゴリズムにできればなぁ…と。
いや、まぁ、ことのほか強敵っぽいので当分保留しときます…w(orz

あと、まだ判定とか、そういうゲーム的な部分が何も書かれてないです。
まぁ、おいおい直してきます。
それなりにゲームの体裁が整い次第、OSASKのコミュに投下でもしようかなぁ〜…と思ってます。いまのところ。
まぁ当分先でしょうけど。



コンパイル:

linux の gcc でコンパイルして実行できます。 gcc -o sd sd.c -lc
./sd
です。

efg01 用にコンパイルする場合は、efg01のtoolsetでコンパイルします。 その際、sd.c ソースコードの一行目のコメントアウト // #define __OSASK__ を解除して有効にしてください。



操作方法:

J カーソル右
K カーソル下
L カーソル左
I カーソル上

H カーソル位置の数を増やす
N カーソル位置の数を減らす

QQQ 終了(Qを3回押す)

sd.c (0.0.1)
//#define __OSASK__

#ifdef __OSASK__

#include <guigui01.h>
#include <stdio.h>
#include <stdlib.h>

#define _COLOR_BLACK     0
#define _COLOR_RED         2
#define _COLOR_GREEN    3
#define _COLOR_YELLO    4
#define _COLOR_BLUE        5
#define _COLOR_PARPLE    6
#define _COLOR_LBLUE    7
#define _COLOR_WHITE    8

void set_put_c_color( int s_color, int bg_color )
{
    jg01_consctrl2( s_color, bg_color );
}

void put_c( unsigned char c )
{
    g01_putc(c);
}

unsigned char get_c( void )
{
    return( (unsigned char)jg01_inkey3() );
}

void set_cur( int x, int y )
{
    jg01_consctrl1(x,y);
}

void clr_scr(void)
{
    jg01_consctrl3();
}

void init_sys(void)
{
    srand(jg01_randomseed());

    jg01_consctrl4(80,25);
    jg01_consctrl2(15,0);
}

void close_sys(void)
{
    clr_scr();
    set_put_c_color( 7, 0 );
}

#endif // __OSASK__

#ifndef __OSASK__

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include <unistd.h>
#include <termios.h>
#include <sys/time.h>

#define _COLOR_BLACK     1
#define _COLOR_RED         2
#define _COLOR_GREEN    3
#define _COLOR_YELLO    4
#define _COLOR_BLUE        5
#define _COLOR_PARPLE    6
#define _COLOR_LBLUE    7
#define _COLOR_WHITE    8

static int flg_init_termios = 0;
static struct termios save_term;
static struct termios temp_term;

void set_put_c_color( int s_color, int bg_color )
{
    switch(s_color){
    case _COLOR_BLACK:    printf("%c[%dm",0x1b, 30 ); break;
    case _COLOR_RED:    printf("%c[%dm",0x1b, 31 ); break;
    case _COLOR_GREEN:    printf("%c[%dm",0x1b, 32 ); break;
    case _COLOR_YELLO:    printf("%c[%dm",0x1b, 33 ); break;
    case _COLOR_BLUE:    printf("%c[%dm",0x1b, 34 ); break;
    case _COLOR_PARPLE:    printf("%c[%dm",0x1b, 35 ); break;
    case _COLOR_LBLUE:    printf("%c[%dm",0x1b, 36 ); break;
    case _COLOR_WHITE:    printf("%c[%dm",0x1b, 37 ); break;
    default:             printf("%c[%dm",0x1b, 0  ); break;
    }

    switch(bg_color){
    case _COLOR_BLACK:    printf("%c[%dm",0x1b, 40 ); break;
    case _COLOR_RED:    printf("%c[%dm",0x1b, 41 ); break;
    case _COLOR_GREEN:    printf("%c[%dm",0x1b, 42 ); break;
    case _COLOR_YELLO:    printf("%c[%dm",0x1b, 43 ); break;
    case _COLOR_BLUE:    printf("%c[%dm",0x1b, 44 ); break;
    case _COLOR_PARPLE:    printf("%c[%dm",0x1b, 45 ); break;
    case _COLOR_LBLUE:    printf("%c[%dm",0x1b, 46 ); break;
    case _COLOR_WHITE:    printf("%c[%dm",0x1b, 47 ); break;
    default:             printf("%c[%dm",0x1b, 0  ); break;
    }
}

void put_c( unsigned char c )
{
    putchar((int)c);
}

unsigned char get_c( void )
{
    return( (unsigned char)getchar() );
}

void set_cur( int x, int y )
{
    printf("%c[%d;%dH",0x1b, y+1, x+1 );
}

void clr_scr(void)
{
    printf("%c[2J",0x1B );
}

void init_sys(void)
{
    if( flg_init_termios == 0 ) {
          tcgetattr(fileno(stdin), &save_term);
          temp_term = save_term;
          temp_term.c_iflag &= IGNCR;
          temp_term.c_lflag &= ~ICANON;
          temp_term.c_lflag &= ~ECHO;
          temp_term.c_lflag &= ~ISIG;
          temp_term.c_cc[VMIN]=1;
          temp_term.c_cc[VTIME]=0;
          tcsetattr(fileno(stdin), TCSANOW, &temp_term);
    }
    flg_init_termios += 1;                                    // ユニークカウンタ(これでシステム全体での起動数を把握しておく)

    srand((unsigned int)time(0));
}

void close_sys(void)
{
    flg_init_termios -= 1;                                    // ユニークカウンタを一つ減らす
    if( flg_init_termios == 0 ) {
        tcsetattr(fileno(stdin), TCSANOW, &save_term );        // すべては、これを複数回起動してしまうのを防止するため。(ユニークカウンタ
    }

    clr_scr();
    set_put_c_color( 0, 0 );
    put_c( '\n');
}

#endif // __OSASK__



#define P00 0
#define P01 3
#define P02 6
#define P10 27
#define P11 30
#define P12 33
#define P20 54
#define P21 57
#define P22 60

typedef struct tagPOS {
    unsigned char x;
    unsigned char y;
} POS;

char defPseed[82]={
    2,8,3,    6,5,4,    7,1,9,
    4,7,6,    9,8,1,    2,3,5,
    9,5,1,    2,7,3,    6,4,8,
   
    1,3,9,    4,6,7,    8,5,2,
    6,2,5,    1,3,8,    4,9,7,
    7,4,8,    5,2,9,    1,6,3,
   
    5,1,2,    7,9,6,    3,8,4,
    3,9,4,    8,1,2,    5,7,6,
    8,6,7,    3,4,5,    9,2,1,
};

static unsigned char MP[82];
static unsigned char UNITP[82]={
    0xFF,0,0,    0,0,0,    0,0,0,
    0,0xFF,0,    0,0,0,    0,0,0,
    0,0,0xFF,    0,0,0,    0,0,0,
   
    0,0,0,    0xFF,0,0,    0,0,0,
    0,0,0,    0,0xFF,0,    0,0,0,
    0,0,0,    0,0,0xFF,    0,0,0,
   
    0,0,0,    0,0,0,    0xFF,0,0,
    0,0,0,    0,0,0,    0,0xFF,0,
    0,0,0,    0,0,0,    0,0,0xFF,
};
static unsigned char BP[82];



void tm33(char* m)
{
    char b[9];

    register char* bp = b;
    register char* mp = m;
    *bp++=*mp++;*bp++=*mp++;*bp++=*mp++;mp+=6;
    *bp++=*mp++;*bp++=*mp++;*bp++=*mp++;mp+=6;
    *bp++=*mp++;*bp++=*mp++;*bp++=*mp++;
   
    bp=b;
    mp=m;
    *mp++=*(bp+6);*mp++=*(bp+3);*mp++=*(bp+0);mp+=6;
    *mp++=*(bp+7);*mp++=*(bp+4);*mp++=*(bp+1);mp+=6;
    *mp++=*(bp+8);*mp++=*(bp+5);*mp++=*(bp+2);
}

void swpm33n(char* m, char a_, char b_ )
{
    register char* mp = m;
    register char a = a_;
    register char b = b_;
   
    if(*mp==a){*mp=b;}else if(*mp==b){*mp=a;} mp++;
    if(*mp==a){*mp=b;}else if(*mp==b){*mp=a;} mp++;
    if(*mp==a){*mp=b;}else if(*mp==b){*mp=a;} mp++; mp+=6;

    if(*mp==a){*mp=b;}else if(*mp==b){*mp=a;} mp++;
    if(*mp==a){*mp=b;}else if(*mp==b){*mp=a;} mp++;
    if(*mp==a){*mp=b;}else if(*mp==b){*mp=a;} mp++; mp+=6;

    if(*mp==a){*mp=b;}else if(*mp==b){*mp=a;} mp++;
    if(*mp==a){*mp=b;}else if(*mp==b){*mp=a;} mp++;
    if(*mp==a){*mp=b;}else if(*mp==b){*mp=a;} mp++;
}

void pP(char* P, POS* cp )
{
    int i;
    const unsigned char        o='0';
    const unsigned char        s=' ';
    unsigned char             cpx=cp->x;
    unsigned char             cpy=cp->y;

    register unsigned char*    pp = P;
    register unsigned char*    mp = MP;

    set_put_c_color( _COLOR_GREEN, _COLOR_WHITE );
    int c = 0;
    for(i=0;i<12;i++){
        if(c++>=3){
            c=0;
            cpy++;
        }
        else {
            cpx=cp->x;
            set_cur(2*cpx,cpy);
           
            set_cur(2*cpx++,cpy);if(*mp++!=0){put_c(s);put_c(o+*pp);put_c(s);} pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++!=0){put_c(s);put_c(o+*pp);put_c(s);} pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++!=0){put_c(s);put_c(o+*pp);put_c(s);} pp++; cpx++; cpx++;

            set_cur(2*cpx++,cpy);if(*mp++!=0){put_c(s);put_c(o+*pp);put_c(s);} pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++!=0){put_c(s);put_c(o+*pp);put_c(s);} pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++!=0){put_c(s);put_c(o+*pp);put_c(s);} pp++; cpx++; cpx++;

            set_cur(2*cpx++,cpy);if(*mp++!=0){put_c(s);put_c(o+*pp);put_c(s);} pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++!=0){put_c(s);put_c(o+*pp);put_c(s);} pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++!=0){put_c(s);put_c(o+*pp);put_c(s);} pp++; cpx++; cpx++;

            cpy+=2;
        }
    }
    set_put_c_color( 0, 0 );

   
    pp = P;
    mp = MP;
    cpy=cp->y;
   
    set_put_c_color( _COLOR_BLACK, _COLOR_WHITE );
    c = 0;
    for(i=0;i<12;i++){
        if(c++>=3){
            c=0;
            cpy++;
        }
        else {
            cpx=cp->x;
            set_cur(2*cpx,cpy);
           
            set_cur(2*cpx++,cpy);if(*mp++==0){ if(*pp!=0){put_c(s);put_c(o+*pp);put_c(s);}else{put_c(s);put_c(s);put_c(s);} } pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++==0){ if(*pp!=0){put_c(s);put_c(o+*pp);put_c(s);}else{put_c(s);put_c(s);put_c(s);} } pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++==0){ if(*pp!=0){put_c(s);put_c(o+*pp);put_c(s);}else{put_c(s);put_c(s);put_c(s);} } pp++; cpx++; cpx++;

            set_cur(2*cpx++,cpy);if(*mp++==0){ if(*pp!=0){put_c(s);put_c(o+*pp);put_c(s);}else{put_c(s);put_c(s);put_c(s);} } pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++==0){ if(*pp!=0){put_c(s);put_c(o+*pp);put_c(s);}else{put_c(s);put_c(s);put_c(s);} } pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++==0){ if(*pp!=0){put_c(s);put_c(o+*pp);put_c(s);}else{put_c(s);put_c(s);put_c(s);} } pp++; cpx++; cpx++;

            set_cur(2*cpx++,cpy);if(*mp++==0){ if(*pp!=0){put_c(s);put_c(o+*pp);put_c(s);}else{put_c(s);put_c(s);put_c(s);} } pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++==0){ if(*pp!=0){put_c(s);put_c(o+*pp);put_c(s);}else{put_c(s);put_c(s);put_c(s);} } pp++; cpx++;
            set_cur(2*cpx++,cpy);if(*mp++==0){ if(*pp!=0){put_c(s);put_c(o+*pp);put_c(s);}else{put_c(s);put_c(s);put_c(s);} } pp++; cpx++; cpx++;
           
            cpy+=2;
        }
    }
    set_put_c_color( 0, 0 );
}

void swpP(char* P, int a, int b )
{
    register char* ap=P+a;
    register char* bp=P+b;
    register char  c;

    c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c; ap+=6; bp+=6;
    c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c; ap+=6; bp+=6;
    c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c;
}

void swpPh(char*P, int la, int lb )
{
    register char* ap=P+9*la;
    register char* bp=P+9*lb;
    register char c;
   
    c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c;
    c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c;
    c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c; c=*ap;*ap++=*bp;*bp++=c;
}

void swpPv(char*P, int la, int lb )
{
    register char* ap=P+la;
    register char* bp=P+lb;
    register char c;
   
    c=*ap;*ap=*bp;*bp=c; ap+=9;bp+=9; c=*ap;*ap=*bp;*bp=c; ap+=9;bp+=9;    c=*ap;*ap=*bp;*bp=c; ap+=9;bp+=9;
    c=*ap;*ap=*bp;*bp=c; ap+=9;bp+=9; c=*ap;*ap=*bp;*bp=c; ap+=9;bp+=9;    c=*ap;*ap=*bp;*bp=c; ap+=9;bp+=9;
    c=*ap;*ap=*bp;*bp=c; ap+=9;bp+=9; c=*ap;*ap=*bp;*bp=c; ap+=9;bp+=9;    c=*ap;*ap=*bp;*bp=c; ap+=9;bp+=9;
}

void swpPn(char* P, char a, char b )
{
    swpm33n(P+P00,a,b); swpm33n(P+P01,a,b); swpm33n(P+P02,a,b);
    swpm33n(P+P10,a,b); swpm33n(P+P11,a,b); swpm33n(P+P12,a,b);
    swpm33n(P+P20,a,b); swpm33n(P+P21,a,b); swpm33n(P+P22,a,b);
}

void tP(char* P)
{
    tm33(P+P00);tm33(P+P01);tm33(P+P02);
    tm33(P+P10);tm33(P+P11);tm33(P+P12);
    tm33(P+P20);tm33(P+P21);tm33(P+P22);
   
    swpP(P,P00,P02); swpP(P,P20,P22); swpP(P,P00,P22);
    swpP(P,P01,P12); swpP(P,P10,P21); swpP(P,P01,P21);
}

void sflP(char* P )
{
    register int i;
    register int j;
    register int r;
   
    for(j=0;j<27;j++){
        for(i=0;i<3;i++){
            r=rand()%3;
            switch(r){
            case 0: swpPh(P,(i*3)+0,(i*3)+1);break;
            case 1: swpPh(P,(i*3)+1,(i*3)+2);break;
            case 2: swpPh(P,(i*3)+2,(i*3)+0);break;
            }

            r=rand()%3;
            switch(r){
            case 0: swpPv(P,(i*3)+0,(i*3)+1);break;
            case 1: swpPv(P,(i*3)+1,(i*3)+2);break;
            case 2: swpPv(P,(i*3)+2,(i*3)+0);break;
            }

            r=rand()%3;
            switch(r){
            case 0: swpP(P,P00,P10); swpP(P,P01,P11); swpP(P,P02,P12);break;
            case 1: swpP(P,P10,P20); swpP(P,P11,P21); swpP(P,P12,P22);break;
            case 2: swpP(P,P20,P00); swpP(P,P21,P01); swpP(P,P22,P02);break;
            }

            r=rand()%3;
            switch(r){
            case 0: swpP(P,P00,P01); swpP(P,P10,P11); swpP(P,P20,P21);break;
            case 1: swpP(P,P01,P02); swpP(P,P11,P12); swpP(P,P21,P22);break;
            case 2: swpP(P,P02,P00); swpP(P,P12,P10); swpP(P,P22,P20);break;
            }
           
            swpPn(P,(rand()%9)+1,(rand()%9)+1);
           
            r=rand()%2;
            switch(r) {
            case 0: tP(P); break;
            }
        }
    }
}

void genMP(int lv)
{
    if(lv< 0){lv=1;}
    if(lv>=9){lv=8;}
   
    int s,i,l;
    register unsigned char* cbp=BP;
    register unsigned char* cup=UNITP;
    register unsigned char* cmp=MP;
    for(l=0;l<1+8*2-lv*2;l++){
        cbp=BP;
        cup=UNITP;
        for(i=0;i<81;i++){*cbp++ = *cup++;}
       
        for(s=0;s<27;s++){
            swpPv(BP,rand()%9,rand()%9);
        }

        cbp=BP;
        cmp=MP;
        for(i=0;i<81;i++){*cmp++ |= *cbp++;}
    }
}

void genP(char* P, int lv)
{
    int i;
    register unsigned char* pp = P;
    register unsigned char* dp = defPseed;
    for(i=0;i<82;i++){*pp++ = *dp++;}
    sflP(P);
   
    genMP(lv);
    register unsigned char* mp = MP;
    pp = P;
    for(i=0;i<82;i++){*pp++ &= *mp++;}
}

void snP(char* P, POS* cp, unsigned char n)
{
    P[cp->y*9+cp->x]=n;
}

void siP(char* P, POS* cp )
{
    if(MP[9*cp->y+cp->x]==0){
        unsigned char* ap = &(P[cp->y*9+cp->x]);
        if(*ap<=9-1){(*ap)++;}
    }
}

void sdP(char* P, POS* cp )
{
    if(MP[9*cp->y+cp->x]==0){
        unsigned char* ap = &(P[cp->y*9+cp->x]);
        if(*ap>=0+1){(*ap)--;}   
    }
}





typedef struct tagUNDOP{
    int                ci;
    unsigned char     P[0x4FFFF];
}UNDOP;
static UNDOP _up={0};
void wUP( unsigned char* P )
{
    int i;
    register unsigned char* cup = &(_up.P[_up.ci*81]);
    register unsigned char* p   = P;
    for(i=0;i<81;i++){
      *cup++ = *p++;
    }
   
    _up.ci++;
}
void rUP( unsigned char* P, int sk )
{
    if(sk>=0){return;}
   
    int csk = _up.ci+sk;
    if(csk<0) {return;}
   
    int i;
    register unsigned char* cup = &(_up.P[csk*81]);
    register unsigned char* p   = P;
    for(i=0;i<81;i++){
        *p++ = *cup++;
    }
   
    wUP(P);
}



void mvcp(POS* cp, int tx, int ty)
{
    unsigned char nx=cp->x+tx;
    unsigned char ny=cp->y+ty;
    if(nx>=9||nx<0){;}else{cp->x=nx;}
    if(ny>=9||ny<0){;}else{cp->y=ny;}
}


static POS Scp;
void pScp(void)
{
    const unsigned char hl=' ';
    const unsigned char vl=' ';
    register POS* cp = &Scp;
   
    set_put_c_color(_COLOR_YELLO,_COLOR_YELLO);

    int cpx=cp->x-1; int cpy=cp->y-1;
    set_cur(cpx++, cpy);put_c(hl);
    set_cur(cpx++, cpy);put_c(hl);    set_cur(cpx++, cpy);put_c(hl);    set_cur(cpx++, cpy);put_c(hl);
    set_cur(cpx++, cpy);put_c(hl);

    cpx=cp->x-1; cpy++; set_cur(cpx, cpy);put_c(vl); cpx+=4; set_cur(cpx, cpy);set_cur(cpx, cpy);put_c(vl);

    cpx=cp->x-1; cpy=cp->y+1;
    set_cur(cpx++, cpy);put_c(hl);
    set_cur(cpx++, cpy);put_c(hl);    set_cur(cpx++, cpy);put_c(hl);    set_cur(cpx++, cpy);put_c(hl);
    set_cur(cpx++, cpy);put_c(hl);

    set_put_c_color(0,0);
}
void clrScp(void)
{
    const unsigned char hl=' ';
    const unsigned char vl=' ';
    register POS* cp = &Scp;
   
    set_put_c_color(0,0);

    int cpx=cp->x-1; int cpy=cp->y-1;
    set_cur(cpx++, cpy);put_c(hl);
    set_cur(cpx++, cpy);put_c(hl);    set_cur(cpx++, cpy);put_c(hl);    set_cur(cpx++, cpy);put_c(hl);
    set_cur(cpx++, cpy);put_c(hl);

    cpx=cp->x-1; cpy++; set_cur(cpx, cpy);put_c(vl); cpx+=4; set_cur(cpx, cpy);set_cur(cpx, cpy);put_c(vl);

    cpx=cp->x-1; cpy=cp->y+1;
    set_cur(cpx++, cpy);put_c(hl);
    set_cur(cpx++, cpy);put_c(hl);    set_cur(cpx++, cpy);put_c(hl);    set_cur(cpx++, cpy);put_c(hl);
    set_cur(cpx++, cpy);put_c(hl);

    set_put_c_color(0,0);
}




#ifdef __OSASK__
int G01Main()
#else
int main()
#endif //__OSASK__
{
//  put_c(0x82);
//  put_c(0x4F);
//  get_c();return 0;
 
    unsigned char P[82];
    POS Pcp={10, 1};
    POS cp={0.0};
    unsigned char ky;
    int e=0;
    int u=0;
   
    init_sys();
    clr_scr();

    genP(P,1);
   
    do{
        clrScp();
        Scp.x=2*(Pcp.x+(cp.x/3)*7+(cp.x%3)*2);
        Scp.y=(Pcp.y+((cp.y/3)*6)+((cp.y%3)*2)+(cp.y/3));

        pP(P,&Pcp);
        pScp();

        set_cur(Scp.x, Scp.y);
        ky=get_c();
        switch(ky){
        case 'j': case 'J': case 's': case 'S': mvcp(&cp,-1,0); set_cur(cp.x,cp.y);break;
        case 'l': case 'L': case 'f': case 'F': mvcp(&cp,+1,0); set_cur(cp.x,cp.y);break;
        case 'i': case 'I': case 'e': case 'E': mvcp(&cp,0,-1); set_cur(cp.x,cp.y);break;
        case 'k': case 'K': case 'd': case 'D': mvcp(&cp,0,+1); set_cur(cp.x,cp.y);break;
       
        case 'u': case 'U': case 't': case 'T': u++; break;

        case '0': snP(P,&cp,0); wUP(P); break;
        case '1': snP(P,&cp,1); wUP(P); break;
        case '2': snP(P,&cp,2); wUP(P); break;
        case '3': snP(P,&cp,3); wUP(P); break;
        case '4': snP(P,&cp,4); wUP(P); break;
        case '5': snP(P,&cp,5); wUP(P); break;
        case '6': snP(P,&cp,6); wUP(P); break;
        case '7': snP(P,&cp,7); wUP(P); break;
        case '8': snP(P,&cp,8); wUP(P); break;
        case '9': snP(P,&cp,9); wUP(P); break;
       
        case 'h': case 'H': case 'g': case 'G':    case ' ':    siP(P,&cp); wUP(P); break;
        case 'n': case 'N': case 'v': case 'V':                sdP(P,&cp); wUP(P); break;
        }
       
        switch(ky){
        case 'u': case 'U': case 't': case 'T': if(u>0){rUP(P,-(u*2-1));} put_c('A');continue; break;
        default: u=0; break;
        }
       
        switch(ky){
        case 'q': case 'Q': e++; break;
        default: e = 0;
        }
       
    } while(e<3);

    close_sys();
    return(0);
}








Chromium OS のコンパイル方法
Chromium OS のコンパイル方法

chromiumos_op.jpg



まずソースコードを入手します。




そのためには git と、 Subversion というツールが必要なので、インストールしておきます。

sudo apt-get install git-core
sudo apt-get install subversion





次に、コンパイルのためのツールをダウンロードします
http://src.chromium.org/svn/trunk/tools/depot_tools.tar.gz

これを解凍して、できあがったフォルダ depot_tools をホームディレクトリに置きます。
ちなみに、ホームディレクトリってのは、
cd $HOME
としたときの移動先のことです。普通は /home/ユーザー名/ のフォルダを指し示します。




bash にdepot_toolsの場所(パス)を追加設定します。
まず、ホームディレクトリに、普段は隠し表示に設定されてるファイルで
.bashrc
というテキストファイルがあります。 このテキストファイルに設定を追加して書きます。

.bashrc をメモ帳で開いて、最後の以降に、以下の文字列をコピペしてください。
(このまま張り付けるだけです。)

export PATH=`pwd`/depot_tools:"$PATH"




まず、ホームディレクトリ上に、ダウンロードするためのディレクトリを作ります。

ホームディレクトリってのは cd $HOME とした時の移動先のことです。

cd $HOME
mkdir chromiumos

つぎに git でダウンロードします。
まず、さっき作成したディレクトリ chromiumos に移動します。

cd chromiumos

つぎに、chromiumos ディレクトリに、ソースファイルのあるURLを登録します。(リポジトリを得る)

gclient config http://src.chromium.org/git/chromiuos.git

(すでにリポジトリが設定されてた場合は、『もうありますよ』というエラーが表示されます。問題ありません)

つぎに、リポジトリの同期をとります。(ダウンロード時間は30分〜1時間くらい)

gclient sync

これであとは1時間ほど待ってればソースファイルがダウンロードされてるはずです。
(一見、止まってるかのように見えますが、さわらないで待っててください)



<コンパイルのための設定>
ソースがダウンロードできたら、次はコンパイルですが、その前にシステムの設定をします。

まず、リンクを設定します。(なんで必要なのかよくわかりませんが...)
ln -s /usr/local/chromiumos/chromiumos.git ~/chromiumos
ln -s /usr/local/chromium/trunk ~/chromium

スクリプトのあるディレクトリに移動します
cd ~/chromiumos/chromiumos.git/src/scripts

ローカルレポジトリを作成します(30分くらい)
./make_local_repo.sh

ビルドに必要なファイルを用意します(30分くらい)
./make_chroot.sh
または
./make_chroot.sh --mirror=http://build.chromium.org/buildbot/packages --suite=chromeos_dev



<コンパイル>
作業場所をマウントします
./build_chrome.sh --chrome_dir ~/chromium
./enter_chroot.sh



OSにバックドアを設定します(設定しなくてもいいですが、設定した方が便利です)

バックドアのユーザー名を設定します。
以下の文字列の USERNAME のところを、適当な文字に書き換えて入力してください。
( cd ../platform/pam_google && ./enable_localaccount.sh USERNAME )

バックドアのパスワードを設定します
./set_shared_user_password.sh
設定したいパスワードを聞かれるので、なにか考えて入力してください。



カーネルをコンパイルします(30分くらい)
./build_platform_packages.sh
./build_kernel.sh



コンパイル結果をイメージファイルにまとめます
./build_image.sh

コンソールを閉じて終了します。


これでとりあえず完成です。



<仮想マシンへのインストール>
本当はUSBメモリにインストールして、ネットブックという特殊なノートパソコンで、実機で動作確認するのが速度的にベストなんですが、
当方、そんな高価な機械は持ってないんで、仮想マシンで動作確認することにします。
仮想マシンには VirtualBox というオープンソースのソフトを使います。
あと、イメージデータの変換のためにQemu というツールも必要です。これもオープンソースです。

VirtualBox と Qemu のインストール
sudo apt-get install virtualbox-ose
sudo apt-get install qemu



イメージファイルの内容を編集したい場合は、イメージファイルをマウントして行います。
まずイメージファイルのあるディレクトリに移動します。
以下の文字列の、SUBDIR のところを実際のディレクトリ名に書き換えて入力してください。(おそらくビルドバージョン毎に名前が異なるとおもいます。)
ちなみに私は今回は cd ~/chromiumos/chromiumos.git/src/build/images/0.5.25.0-a1 でした。

cd ~/chromiumos/chromiumos.git/src/build/images/SUBDIR

そしてマウントします
sudo mount -o loop rootfs.image rootfs

デスクトップにハードディスクのアイコンが表示されます。この中身を好きに書き換えてもOKです。
ディレクトリ構成はみるからに、あきらかにunixですw。 /bin/ には普通に vi などのアプリケーションが用意されてます。
python や perl のインタープリタも用意されてるみたいです。カーネルはlinuxの2.6.31が入ってますね。
多言語入力は iBus が用意されてるので、コンソールでsetupすれば日本語入力も使えるようになります。

追記:
キーボードを日本語配置に設定する方法
まず、マウントしたイメージ rootfs がマウントイメージとしてデスクトップに表示されるので、それを開き、
/etc/X11/ に移動し、
xorg.conf というファイルを管理者権限で開きます。
その中の以下の構造体

Section "InputDevice"
Identifier "Keyboard1"
Driver "kbd"
Option "AutoRepeat" "250 30"
Option "XkbRules" "xorg"
Option "XkbModel" "pc104"
Option "CoreKeyboard"
EndSection


Option "XkbLayout" "jp"
というメンバを追加します。つまり以下のように書き変えます。

Section "InputDevice"
Identifier "Keyboard1"
Driver "kbd"
Option "AutoRepeat" "250 30"
Option "XkbRules" "xorg"
Option "XkbModel" "pc104"
Option "XkbLayout" "jp"
Option "CoreKeyboard"
EndSection

これでキーボードの配置が日本語配置になります。(@とかも、ちゃんと打てるようになりますw)



<仮想マシン用にイメージファイルを変換>
VirtualBoxで読み込むために、イメージファイルの形式を変換します。(VMWare形式に変換します)

まず、script ディレクトリに移動します。
cd /$HOME/chromiumos/chromiumos.git/src/scripts/

以下の文字列を入力します。
SUBDIR はさっきと同じです。実際のディレクトリ名に書き換えて入力してください。
ちなみに私は今回は 0.5.25.0-a1 なので、
image_to_virtualbox.sh --from=~/chromiumos/chromiumos.git/src/build/images/0.5.25.0-a1 --to=~/chromiumos/chromiumos.git/src/build/images/0.5.25.0-a1/os.vdi でした。

./image_to_virtualbox.sh --from=~/chromiumos/src/build/images/SUBDIR --to=~/chromiumos/src/build/images/SUBDIR/os.vdi



まずVirtualBoxを起動します。
virtualbox

メニューから
ファイル → 仮想メディアマネージャー
を選択します。

『追加』を押します。

さっき作った ChromiumOS のイメージファイルの場所へ移動して、 ide.vmdk というファイルを選択します。
ちなみにさっきの場所は /$HOME/chromiumos/chromiumos.git/src/build/images/SUBDIR/ でしたよね。

これで、仮想ハードディスクが一覧に登録されました。

つぎに仮想マシンを設定します。
メインウインドウの 『新規』 と書いてあるボタンを押します。質問に答えて行きます。
名前は適当でいいです。
オペレーティングシステムのタイプは Linux にします。
バージョンは Linux2.6 です

メモリは1Gもあれば充分です。

機動ディスクです。
既存のハードディスクを使用です。一覧から、さっき登録した os.vdi を選択します。

これで仮想マシンが作られ、一覧に登録されました。
これをダブルクリックすれば仮想マシンが起動して、 Chromium OS が仮想マシン上で動きます。




gmail のアカウントを持ってる人は、gmail の『本物のアカウント』でログインできます。 本当はこの方法が正式。また、安定してます。
さっきのコンパイルの時に作ったバックドアでもログインできます。ただしこちらは不安定です。

あと、VirtualBoxの基本操作ですが、『右側のCtrlキー』を押すと、マウスカーソルが仮想マシンから戻ってきます。これ重要w



ChromiumOSで日本語を入力できるように設定する

デフォルトでは日本語入力ができませんが、ChromiumOSのコンソールで Linux のコマンドを打てば、iBus という多言語入力ツールの設定ができます。
これによって Anthy 日本語入力が使えるようになります。
まず、コンソール画面を表示します。

Alt + Ctrl + t

そして
cd /usr/bin/
に移動して
ibus-setup
を実行します。

Input Method タグへ移動し、Select an input method 一覧から Japanise -> Anthy を選択し Add ボタンを押します。
これで日本語入力ができるように設定できました。

テキストボックスなどで入力する際に、
キーボードの『半角/全角』キーで、入力モードを切り替えられるようになります。



ファイルの操作について

Ctrl + o

で、ファイルマネージャーが起動します。
また、コンソールで Linux のコマンドが普通に使えるので、 cp や rm などのコマンドでファイル操作することも可能です。



コンソールを見た感じだと、/bin/ や /usr/bin/ などに一通りのツールが用意されてるので、linuxの端末としても普通に使えると思います。
python や perl が用意されてます。もちろん普通に動きます。 テキストエディタには vi が用意されてます。 いたれりつくせりですね。

試してませんが、おそらく 第二世代OSASKも、このコンソール上で普通に動きそうな気がします。
けっこういろいろ遊べそうで楽しそうです。おもにコンソールがw (そっちかい!!



ウインドウの切り替え
F12

一覧表示になるのでマウスで選択します。カーソルキーでも選択できます。



終了方法について
よくわからないですが、おそらく ACPIシャットダウンでOKだとおもいます。ようするに電源ボタン直押しです。
ACPIシャットダウンじゃなくて、突発的なシャットダウンだとダメみたいです。 だから、必然的にインストールできるPCの種類が限定されてきますね。




search.c (0.0.1)
とりあえず組んでみました。

任意の検索文字列(今回は [(123)4]?5 )を、順序木によってツリー構造に変換してます。
インデントがノードの深さを意味します。 NODE[0x????]は、直上のノードのユニーク値です。(実際はポインタ)
直上がNODE[0x0]のノードは、ルートを意味してます。

次に文字列 TEXT 中から、 [(123)4]?5 に一致する単語を検索し、一致した結果を表示してます。
[ ] は、この中での いずれか1文字 を意味し、
( ) は、この中の 文字列を1文字として扱う を意味し、
? は、直前の1文字の 0 〜 2 回の繰り返しを意味します。 (0〜1じゃなくて、0〜2です、 *を組む時の練習しましたw)

ちなみに、 [(123)4]?5 が意味する単語は
1235
45
12345
41235
1231235
445
5
のいずれかですね。
TEXT中から、この単語を検索する形になります。

search001test.png
あ、NODE[875C008]がかぶってますね…
ソース見たら、ins_NODE() 関数の定義の最後に nn->d[0]->u = nn; の式が必要な気がしました…単純に書き忘れてた。w
たぶんそれで治ると思います。(まだ試してないのでわかりませんが…w)

一応ソースです。
コンパイル方法はいつもどうりです。Linuxで gcc -o s search.c -lc です。
この場合、コンパイル結果の s が実行ファイルです。 ./s と入力すれば実行できます。
( s じゃなくて任意の名前でも当然OKです)

search.c (0.0.1)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define d_len_max 0xFF
typedef struct tagNODE {
    struct tagNODE* u;
    struct tagNODE* d[d_len_max];
    int cur_dnode;
    char c;
} _NODE;

_NODE* new_NODE( void )
{
    int i;
    _NODE* n = (_NODE*)malloc(sizeof(_NODE));
    n->cur_dnode = -1;
    n->u = 0;
    for(i=0; i< d_len_max ;i++){ n->d[i] = 0; }
    n->c = 0;
   
    return( n );
}

void add_NODE( _NODE* n )
{
    n->cur_dnode++;
    n->d[n->cur_dnode] = new_NODE();
    n->d[n->cur_dnode]->u = n;
}

void ins_NODE( _NODE* n )
{
    _NODE* nn = new_NODE();
    nn->cur_dnode=0;
    nn->u = n;
    nn->d[0] = n->d[n->cur_dnode];
   
    n->d[n->cur_dnode] = nn;
}

int trans_str2NODE( _NODE* n, char* str )
{
    int len = strlen(str);
//printf("strlen=%d\n",len);
   
    if( len<=0 ){
    }
    else {
        char c = str[0];
        switch( c ){
        case '[':
            add_NODE( n );
            n->d[n->cur_dnode]->c = c;
            trans_str2NODE( n->d[n->cur_dnode], (str+1) );
            break;
        case ']':
            trans_str2NODE( n->u, (str+1) );
            break;
        case '(':
            add_NODE( n );
            n->d[n->cur_dnode]->c = c;
            trans_str2NODE( n->d[n->cur_dnode], (str+1) );
            break;
        case ')':
            trans_str2NODE( n->u, (str+1) );
            break;
        case '?':
            ins_NODE( n );
            n->d[n->cur_dnode]->c = c;
            trans_str2NODE( n, (str+1) );
            break;
        default:
            add_NODE( n );
            n->d[n->cur_dnode]->c = c;
            trans_str2NODE( n, (str+1) );
            break;
        }
    }
}

void print_NODE( _NODE* n, int depth )
{
    int i;
   
    char space[0xFF]; for( i = 0; i < depth; i++ ) { space[i] = '\t'; } space[depth] = '\0';
    printf("%sNODE[0x%x] char=%c int=%d\n", space, (int)(n->u), n->c, (int)(n->c) );
   
    for(i=0; i<=n->cur_dnode; i++ ) {
        print_NODE( n->d[i], depth+1 );
    }
}
void print_TREE( _NODE* r )
{
    print_NODE( r, 0 );
}

char dst[0xFFFF];
int  cur_dst;

int search_at_NODE( _NODE* n, char* str, int* index )
{
    int len = strlen(str);
    int i;
    int ret=0;
   
    if(len <= *index){
        return(0);
    }
    else {
        switch( n->c ) {
        case 0:
            ret = 1;
            for(i=0; i<=n->cur_dnode; i++ ) {
                ret &= search_at_NODE( n->d[i], str, index );
            }
            return( ret );
            break;
           
        case '[':
//printf("[\n");
            ret=0;
            for(i=0; i<=n->cur_dnode; i++ ) {
                ret |= search_at_NODE( n->d[i], str, index );
                if(ret!=0){break;}
            }
            return( ret );
            break;
       
        case '(':
//printf("(\n");
            ret = 1;
            int old_index = *index;
            for(i=0; i<=n->cur_dnode; i++ ) {
                if( *index >= len ) { ret=0; break; }
                ret &= search_at_NODE( n->d[i], str, index );
            }
           
            if(ret==0){ *index = old_index; }
            return( ret );
            break;
       
        case '?':
//printf("?\n");
//            ret = search_at_NODE( n->d[0], str, index );
//            return(ret);
            ret = 1;
            int ret_buf;
            for(i=0; i<2; i++ ) {
                int old_index = *index;
                ret_buf = search_at_NODE( n->d[0], str, index );
                if(ret_buf==0){ *index = old_index; return(ret); }
                ret=ret_buf;
            }
            return(ret);
            break;
       
        default:
printf("%c=%c ",n->c, str[*index]);
            if( n->c == str[*index] ) {

                switch( n->u->c ) {
                case '[':    dst[cur_dst] = n->c;     cur_dst++;    break;
                case '(':    dst[cur_dst] = n->c;    cur_dst++;    break;
                case '?':    dst[cur_dst] = n->c;    cur_dst++;    break;
                case 0  :    dst[cur_dst] = n->c;    cur_dst++;    break;
                }

                (*index)++;
                return(1);
            }
            else {
                return(0);
            }
            break;
        }
    }
}

void search_at_TREE( _NODE* r, char* str )
{
    int ret;
    int index = 0;
    int len = strlen(str);
    while(len>index){
printf("\n");
        int i;
        for(i=0;i<0xFFFF;i++) {dst[i]=0;} cur_dst=0;

//        printf("ret=%d : [%s]\n", search_at_NODE( r, str, &index ), dst );
        ret = search_at_NODE( r, str, &index );
        if(ret==1){;}else{ index++; }

        if(ret==1){printf("match [%s]", &dst[0] );}
    }
}

int main()
{
printf("\n");
printf("search.cpp testVersion0.0.1\n");
printf("\n");
printf("\n");
 
    _NODE* r = new_NODE();
//    char str[0xFFFF] = "[(AB)C]DE";
    char str[0xFFFF] = "[(123)4]?5";
//    char text[0xFFFF] = "_ABD_ABDE_CD_CDE_ABCDE_";
    char text[0xFFFF] = "__1235__45__12345__1231235__445__5__";

printf("TREE view\n\n");
    trans_str2NODE( r, str );
    print_TREE( r );

printf("SEARCH\n\n");
    printf("TEXT = %s : SEARCH = %s\n", text, str );
    search_at_TREE( r, text );

   
    putchar('\n');
    return(0);
}



linux カーネル 2.6.32 がリリースされたそうなので...
さっそくソースをダウンロードしてコンパイルしてみた。


なんか意外と簡単なのね…
カーネルコンパイルって、もっとツマヅキまくりで難しいのかと思ってたわ。
class _TREE および class _NODE によって順序木構造を書けば可能かもしれない
文字列検索の際の記述方法の一つとして正規表現がある。
正規表現を実現するにはどういうアルゴリズムが必要だろうか? と、興味の矛先が向いたので考えてます。

正式な正規表現とは違うけど、簡易的なルールを決めて、それを実現する方法をとりあえず考えてみようと思う。

簡易ルール
  • . は任意の一文字をあらわす。
  • ? は、その手前の1文字の0回or1回の繰り返しをあらわす。(例: xA? なら、 x か xA の意味)
  • [ ] によって囲まれた各文字のいずれか1文字に一致することをあらわす。(例: [ABC]X なら、 AX か BX か CX の意味)
  • ( ) によって囲まれた文字列は、1文字として解釈する。(例: x(ABC)? は、x か xABC の意味)
というルールによって、任意の文字列から(文字配列)から一致を検索するには、どういうアルゴリズムで可能だろうか?

とりあえず、詳細は抜きに、大まかな枠組みとしては、まずパーサーが必要になるのはとうぜんとして、
そのパーサーによって分割された命令群をどう実行するか?並べるか?を考えたら、おそらく木構造が適してるのではないだろうか…?と。

たとえば以下のような検索文字列があったとする。

[(AB)C]?DE

ルールを当てはめて解釈すると、これが意味する文字列は
  • DE
  • ABDE
  • CDE
のいずれかになるけど、これをはたして、どうやってコンピューターに理解させるか?そして実行させるか。

まず、 [(AB)C]?DE の最初の [ をルートから、最初のノードに登録する。(注:順序のある木です)
つぎに、このノード『 [ 』の、最初のノードに ( を登録する。
つぎに、『 ( 』のノードの、最初のノードに A、次のノードに B を登録する。
つぎに、 ) が現れたので、『 ( 』のノードの親ノードまで戻る。 親ノードは『 [ 』
つぎに、『 [ 』のノードの2番目に C を登録する。
つぎに、 ] が現れたので、『 [ 』のノードの親ノードまで戻る。 親ノードはルート。
つぎに、ルートの2番目に D、3番目に E を登録する。
以上。

これによって、以下のような木構造のグラフが完成する。

        
      
  [  D E 
  |     
  ( C    
       
A   B    
         

さて、グラフは作れたものの、これをどうやってコンピューターに解釈させるか?という問題。
各ノードに関数を持たせて、各ノードは自分の関数を実行する責任だけを考えるようにしてみてはどうか?と思った。

つまり、例えば 『 [ 』のノードは、自分の子ノード群から上がってくる『一致した』という信号のみを解釈する。そして、その結果を OR演算によって親ノード(今回の例ではルート)に返す。これのみ。

同様に、『 ( 』のノードは、自分の子ノード群から上がってくる『一致した』という信号を受け取ることだけを考えて動作すれば良い。そして、その結果をAND演算によって親ノード(今回の例では『 [ 』)に返す。これのみ。

特殊記号では無い、単純な1文字(ABCDE)の場合は、リーフである。(ノードを持たない)
実際に文字列に対して比較関数を実施して、なんらかの一致・非一致を試験する能力があるのはリーフのみである。
ノードには、その能力は無い。(ノードはあくまで、子ノードの演算結果を論理演算する装置に過ぎない)

これらの方法を実現するには、各ノード(そしてリーフ)を再帰によって連鎖的に処理していく方法で組めば、ロジックを簡単に組めそうな気がするのだが、はて? どうだろうか。
まだ実際には書いてない、試してない。



あ、ツリーに?を含めるの忘れてた…
そのうち書き直します。もぅ寝ます。
_LIST (0.1.0) 他
とりあえずバグをいろいろ直して、コード整理してみて、それで気に入らなかったら捨てようと思ったんだけど、
意外と読みやすいコードな気もしてきたので、やっぱ捨てないでしばらくこのまま進んでみようかと思う。まぁどうせ遊びだし。はは…w

if 文での比較用に、_LIST 型に比較関数を用意した。
すると派生クラスである CHAR_LISTにも、わりと簡単に同様の機能をもった比較関数を敬称によって実装できるので、
「あぁ、便利だな…」と思った。C++って、ときどき便利だから嫌いになりきれなくてこまる…

あと、今までコード書くのに GNOME のメモ帳(GEDIT)を使ってたんだけど、メソッド名を自動で補完入力してくれる機能が欲しくなったので(C++だと、それが無いときついw おもに記憶力的に。)
統合開発環境の kDevelop と Anjuta ってのを Synaptic でインストールしてみた。(あ、久しぶりにLinuxブログっぽい話だっw)
で、AnjutaってのはGnome系、KDevelop ってのはKDE系のソフトなんだけど、どっちもGnomeで動くみたい。よかったよかった。

で、やっぱ機能的にAnjutaの方は色々弱くて、正直あんまり使えないというか、GEDITで書いても大差ないかなぁ〜…って程度。
一方、KDevelopってのは、もぅ、めっちゃ素晴らしい!!って感じ。コード書いてる時の感覚は VisualStudioで書いてるときに近い。(主に自動補完入力が)
これ、ぜったいインストールした方がいいですよ!! まじでおすすめ。 っていうか、もぅGEDITには戻れませんわ…

ただ、KDE系のソフトなんで、やっぱり若干重たい。全体的に動作がもっさりしてる。でも機能はすばらしい。
なんかペイント系のソフトでも Karte でしたっけ? すごくクオリティーの高いペイントソフトがあったりと、KDE系(Qt系っていうの?)の方が、なんか全体的にソフトの質が一段上なのが多いですよね…

…乗り換えようかなぁ、KDEに…って、ちょっと思ってしまう。
ただ、重いんだよなぁ〜…
前に一度、試しにKDEの4.x系に変えてみたんだけど、どうにも重くて重くて、なんか486でWin95を使ってたころのような、尋常じゃない重さだったので「あぁ、こりゃアカン…見た目かっこいいけど」って思って、速攻でGNOMEに戻した経緯がありまして…
GNOMEは軽いよねぇ…軽いだけとか言ってませんよ!言ってませんよ!んがんぐ

_SEED.h (0.1.0)
#pragma once

class _SEED {
protected:
    _SEED*    next;
    _SEED*    back;

public:
    _SEED();
    virtual ~_SEED();

    virtual int        read_SEED ( _SEED* dst ) { return(0); }        // 派生したクラスの、ぶら下げたデータへの読み書きを、これら関数内で行う
    virtual int        write_SEED( _SEED* src ) { return(0); }        // ...
    virtual int        comparison_SEED( _SEED* seed ) { return(0); }

    virtual void     add_next( _SEED* seed );
    virtual void     add_back( _SEED* seed );
    virtual _SEED*    del_next( void );
    virtual _SEED*    del_back( void );

    virtual _SEED*    get_next( void );
    virtual _SEED*    get_back( void );
};
_SEED.cpp (0.1.0)
#include "_SEED.h"

_SEED::_SEED()
{
    next = 0;
    back = 0;
}

_SEED::~_SEED()
{
}

void _SEED::add_next( _SEED* seed )
{
    if( seed == 0 ) {
        this->next = 0;
    }
    else {
        _SEED* next = this->next;

        if( next != 0 ){
            next = this->next;
            next->back = seed;
        }

        seed->next = next;
        seed->back = this;

        this->next = seed;
    }
}

void _SEED::add_back( _SEED* seed )
{
    if( seed == 0 ) {
        this->back = 0;
    }
    else {
        _SEED* back = this->back;

        if( back != 0 ){
            back = this->back;
            back->next = seed;
        }
   
        seed->next = this;
        seed->back = back;

        this->back = seed;
    }
}

_SEED* _SEED::del_next( void )
{
    _SEED* del = 0;

    if( this->next == 0 ) {
    }
    else {
        del = this->next;
        if( del->next == 0 ) {
            this->next = 0;
        }
        else {
            _SEED* new_next    = del->next;
           
            this->next = new_next;
            new_next->back = this;           
        }
    }

    return( del );
}

_SEED* _SEED::del_back( void )
{
    _SEED* del = 0;

    if( this->back == 0 ) {
    }
    else {
        del = this->back;
        if( del->back == 0 ) {
            this->back = 0;
        }
        else {
            _SEED* new_back    = del->back;
           
            this->back = new_back;
            new_back->next = this;           
        }
    }

    return( del );
}

_SEED* _SEED::get_next( void )
{
    return( next );
}

_SEED* _SEED::get_back( void )
{
    return( back );
}

_LIST.h (0.1.0)
#pragma once

#include "_SEED.h"

// 派生させる場合に必要な設定について
// 新しい派生クラス x_LIST と、そのメンバ変数 x_SEED について、以下の設定が必須になります。
//
// ・x_SEED に、任意のメンバ変数を追加する。(任意)
//
// ・x_SEED に、任意のメンバ変数を追加した場合(ふつう追加するはず)、以下の2つの関数を再定義しなければならない
//   void read( _SEED* dst ) {;//ここに、データの、『 this から dst へ』の『書き写し(ポインタのコピーではない!)』 に関する命令を書く }
//   void write( _SEED* src ) {;// ...『src から this へ』の... }
//   なお、引数の _SEED* dst および src は、どちらも『実体が存在するポインタ』が前提です。(_SEED& dst および _SEED& src だと考えてください)
//
// ・x_LIST の new_SEED() 関数の再定義
//   これは _SEED 用の new オペレーターに相当する関数です。( operator new による再定義はしてません。理由はよくわかんないからですw )
//   virtual _SEED* new_SEED( void ) { x_SEED* seed = new x_SEED; return( (_SEED*)seed ); }
//
// 以上
//
// 派生クラスでの、write 及び read の再定義に関する注意
// read および write で、リストの自動処理(たとえば自動伸長など)を期待するのなら、
// 最終的な_LISTへの read および write には必ず read_SEED() および write_SEED() で _SEED 型のポインタを渡すことによって行うこと
// 以上
class _LIST {
private:
      virtual _SEED*    seek( int index );
    virtual _SEED*    seek_top( void ) { return( seed_top ); }
    virtual _SEED*    seek_end( void ) { _SEED* end_seed = seek(list_len-1); return( end_seed ); }

protected:
    _SEED*    seed_top;
    int        list_len;

    virtual void    size_add( int add_len );
    virtual void    size_dec( int dec_len );

    virtual _SEED* new_SEED( void ){ _SEED* new_seed = new _SEED;     return( (_SEED*)new_seed ); }        // new の代わりにこれを使う

public:
    _LIST();
    virtual ~_LIST();

    virtual void    size_set        ( int len );

    virtual int     read_LIST        ( int index, int width, _LIST* dst );
    virtual int     write_LIST        ( int index, int width, _LIST* src );
    virtual int     read_SEED        ( int index, _SEED* dst );
    virtual int     write_SEED        ( int index, _SEED* src );
    virtual int        comparison_SEED    ( int index, _SEED* seed );

    virtual int        _list_len        (void) {return(list_len);}

//    virtual int cut( int index, _SEED* dst );
//    virtual int cut( int index, int width, _LIST* dst );
//    virtual int paste( int index, _SEED* src );
//    virtual int paste( int index, _LIST* src );
   
    virtual void     print_all_address(void);
};
LIST.cpp (0.1.0)
#include <stdio.h>
#include "_LIST.h"

_LIST::_LIST()
{
    seed_top = new_SEED();
    list_len = 1;
}

_LIST::~_LIST()
{
  for(int i = list_len -1; i >= 0; i-- ) {
        _SEED* del_seed = seek(i);
       
        if( del_seed !=0 ) { delete del_seed; }
    }
}

_SEED* _LIST::seek( int index )
{
    if( index > list_len - 1 ) { index = list_len - 1; }

    _SEED* cur_seed = seed_top;

    for( int i=1; i <= index; i++ ) {
        if(cur_seed==0) {break;}                            // 次が無ければ0を返す

        cur_seed = cur_seed->get_next();
    }

    return( cur_seed );
}

void _LIST::size_add( int add_len )
{
    _SEED* cur_seed = seek( list_len - 1 );
    _SEED* new_seed;

    for(int i=0; i < add_len; i++ ) {
        new_seed = new_SEED();
        cur_seed->add_next( new_seed );
        cur_seed = new_seed;
    }

    list_len += add_len;
}

void _LIST::size_dec( int dec_len )
{
    _SEED* cur_seed = seek( list_len - 1 );
    _SEED* del_seed;
   
    for(int i = 0; i < dec_len; i++ ) {
        cur_seed = cur_seed->get_back();
        del_seed = cur_seed->del_next();
        delete del_seed;
    }

    list_len -= dec_len;
}

void _LIST::size_set( int len )
{
    if( len <= 0 ) { len = 1; }

    int dif = len - list_len;
    if( dif > 0 ) {
        size_add(dif);
    }
    else if( dif < 0 ) {
        dif = -dif;
        size_dec(dif);
    }
    else {
    }   
}

int _LIST::read_SEED( int index, _SEED* dst )
{
    if( index < 0 )             { index = 0; }                            // 範囲アンダーなら最初
    if( index > list_len - 1 )    { index = list_len - 1; }                // 範囲オーバーなら最後

    _SEED* src = seek( index );
    return( dst->write_SEED( src ) );                                    // あくまでnext,back変数以外のデータのリードライトのみ
}

int _LIST::write_SEED( int index, _SEED* src )
{
    if( index < 0 )             { index = 0; }                            // 範囲アンダーなら最初
    if( index > list_len - 1 )    { size_set( index+1 ); }                // 範囲オーバーならリストを伸ばす (+1は_LIST長という意味)

    _SEED* dst = seek( index );
    return( dst->write_SEED( src ) );
}

int _LIST::comparison_SEED( int index, _SEED* seed )
{
    if( index < 0 )             { index = 0; }                            // 範囲アンダーなら最初
    if( index > list_len - 1 )    { index = list_len - 1; }                // 範囲オーバーなら最後

    _SEED* base = seek( index );
    return( base->comparison_SEED( seed ) );
}

int _LIST::read_LIST( int index, int width, _LIST* dst )
{
    if( index < 0 )                 { index = 0; }                            // 範囲アンダーなら最初
    if( index > list_len - 1 )        { index = list_len - 1; }                // 範囲オーバーなら最後
    if( index + width > list_len )    { width = list_len - index; }            // 最大でも src の len 幅まで
    if( width <= 0 )                { width = 1; }                            // 幅が0以下なら1
   
    dst->size_set(width);                                                    // dstの幅を index to width 区間と同じ幅に

    _SEED* buf = new_SEED();
    for(int si=index, di=0 ; si < index + width; si++, di++ ) {
        this->read_SEED( si, buf );   
        dst->write_SEED( di, buf );
    }
    delete buf;
}

int _LIST::write_LIST( int index, int width, _LIST* src )
{
    if( index < 0 )                     { index = 0; }                            // 範囲アンダーなら最初
    if( width > src->_list_len() )        { width = src->_list_len(); }            // 最大でも src の len 幅まで
    if( width <= 0 )                    { width = 1; }
    if( index + width > list_len - 1 )    { this->size_set( index + width ); }    // 範囲オーバーならリストを伸ばす

    _SEED* buf = new_SEED();
    for(int si=0, di=index ; di < index + width; si++, di++ ) {
        src->read_SEED( si, buf );   
        this->write_SEED( di, buf );
    }
    delete buf;
}

void _LIST::print_all_address(void)
{
    _SEED* cur_seed = seed_top;

    printf("list_len=%d\n", list_len);

    for(int i=0; i < list_len; i++ ) {
        printf("%d:%d\n",i,(int)cur_seed);
        cur_seed = cur_seed->get_next();
    }   
}
















CHAR_SEED.h (0.1.0)
#pragma once

#include "_SEED.h"
#include "CHAR.h"

class CHAR_SEED : public _SEED {
protected:
    CHAR* ch;

public:
    CHAR_SEED() { ch = new CHAR; }
    virtual ~CHAR_SEED() { delete ch; }

    virtual int read_SEED ( _SEED* seed ) { return( ((CHAR_SEED*)seed)->write_CHAR( ch ) ); }
    virtual int write_SEED( _SEED* seed ) { return( ((CHAR_SEED*)seed)->read_CHAR ( ch ) ); }
    virtual int comparison_SEED( _SEED* seed );

    virtual int read_char ( unsigned char* dst ) { return( ch->read_char ( dst ) ); }
    virtual int write_char( unsigned char* src ) { return( ch->write_char( src ) ); }

    virtual int read_CHAR ( CHAR* dst ) { return( ch->read_CHAR ( dst ) ); }
    virtual int write_CHAR( CHAR* src ) { return( ch->write_CHAR( src ) ); }
   
    virtual int comparison_char( unsigned char* src )    { return( ch->comparison_char( src ) ); }
    virtual int comparison_CHAR( CHAR* src )            { return( ch->comparison_CHAR( src ) ); }

    virtual int _mode(void){ return( ch->_mode() ); }
    virtual int _step(void){ return( ch->_step() ); }
};
CHAR_SEED.cpp (0.1.0)
#include "CHAR_SEED.h"

int CHAR_SEED::comparison_SEED( _SEED* seed )
{
    CHAR seed_ch;
    ((CHAR_SEED*)seed)->read_CHAR( &seed_ch );
    return( comparison_CHAR( &seed_ch ) );
}

CHAR_LIST.h (0.1.0)
#pragma once

#include "_LIST.h"
#include "CHAR_SEED.h"

class CHAR_LIST : public _LIST {
protected:
    virtual _SEED* new_SEED( void ){ CHAR_SEED* new_seed = new CHAR_SEED; return( (_SEED*)new_seed ); } // new の代わりにこれを使う
   
public:
    CHAR_LIST() { delete seed_top; seed_top = new_SEED(); }    // コンストラクタ直後は_SEED型なので、一旦そのメモリを開放してから。
    virtual ~CHAR_LIST(){ ; }

    virtual int  read_char ( int index, unsigned char* dst );
    virtual int  write_char( int index, unsigned char* src );

    virtual int  read_CHAR ( int index, CHAR* dst );
    virtual int  write_CHAR( int index, CHAR* src );
   
    virtual int  read_CHAR_LIST ( int index, int width, CHAR_LIST* dst );
    virtual int  write_CHAR_LIST( int index, int width, CHAR_LIST* src );
   
    virtual int  read_str ( unsigned char* dst, int len );
    virtual int  write_str( unsigned char* src, int len );
   
    virtual int comparison_char( int index, unsigned char* src );
    virtual int comparison_CHAR( int index, CHAR* src );
    virtual int comparison_CHAR_LIST( CHAR_LIST* src );

    virtual int _mode( int index );
    virtual int _step( int index );
};
CHAR_LIST.cpp (0.1.0)
#include "CHAR_LIST.h"
 
int CHAR_LIST::read_char( int index, unsigned char* dst )
{
    CHAR_SEED* buf = new CHAR_SEED;
    read_SEED( index, (_SEED*)buf );
    int ret = buf->read_char( dst );
    delete buf;
    return( ret );
}
 
int CHAR_LIST::write_char( int index, unsigned char* src )
{
    CHAR_SEED* buf = new CHAR_SEED;
    int ret = buf->write_char( src );
    write_SEED( index, (_SEED*)buf );
    delete buf;
    return( ret );
}
 
int CHAR_LIST::read_CHAR( int index, CHAR* dst )
{
    CHAR_SEED* buf = new CHAR_SEED;
    read_SEED( index, (_SEED*)buf );
    int ret = buf->read_CHAR( dst );
    delete buf;
    return( ret );
}
 
int CHAR_LIST::write_CHAR( int index, CHAR* src )
{
    CHAR_SEED* buf = new CHAR_SEED;
    int ret = buf->write_CHAR( src );
    write_SEED( index, (_SEED*)buf );
    delete buf;
    return( ret );
}
 
int CHAR_LIST::read_CHAR_LIST( int index, int width, CHAR_LIST* dst )
{
    return( read_LIST( index, width, (_LIST*)dst ) );
}
 
int CHAR_LIST::write_CHAR_LIST( int index, int width, CHAR_LIST* src )
{
    return( write_LIST( index, width, (_LIST*)src ) );
}
 
int CHAR_LIST::read_str( unsigned char* dst, int len )
{
    int step = 0;
    int total_step = 0;
    int count = 0;
     
    for ( int i=0; i < len; i++ ) {
        step = read_char( count, &dst[total_step] );
        total_step += step;
        count++;
         
        if( count > len - 1 ) { break; }
    }
     
    return( total_step );
}
 
int CHAR_LIST::write_str( unsigned char* src, int len )
{
    int step = 0;
    int total_step = 0;
    int count = 0;
     
    for ( int i=0; i < len; i++ ) {
        step = write_char( count, &src[total_step] );
        total_step += step;
        count++;
         
        if( count > len - 1 ) { break; }
    }
     
    return( total_step );
}
 
int CHAR_LIST::comparison_char( int index, unsigned char* src )
{
    CHAR src_ch;
    src_ch.write_char( src );
 
    int ret = comparison_CHAR( index, &src_ch );
    return( ret );
}
 
int CHAR_LIST::comparison_CHAR( int index, CHAR* src )
{
    CHAR_SEED src_seed;
    src_seed.write_CHAR( src );
     
    CHAR_SEED base_seed;
    read_SEED( index, (_SEED*)&base_seed );
     
    int ret = base_seed.comparison_SEED( (_SEED*)&src_seed );
    return( ret );
}
 
// this に対する cl のマッチを調べる。
// 最初にマッチした位置の先頭インデックスを返す。 マッチした位置が無かった場合は -1 を返す。
int CHAR_LIST::comparison_CHAR_LIST( CHAR_LIST* src )
{
    int cur_src_index = 0;
    int max_src_index = src->_list_len();
 
    int cur_base_index = 0;
    int max_base_index = this->_list_len();
 
    int ret = -1;
 
    CHAR_SEED cur_src_seed;
     
    while( cur_base_index < max_base_index ) {
        src->read_SEED( cur_src_index, (_SEED*)&cur_src_seed );
 
        if( comparison_SEED( cur_base_index, (_SEED*)&cur_src_seed ) != 0 ) {
            cur_src_index++;
 
            if( cur_src_index >= max_src_index ) {
                cur_src_index = 0;
                 
                ret = cur_base_index - (max_src_index - 1);                        // 最初に一致したインデックスをリターンして終了
                return( ret );
            }
        }
        else {
            cur_src_index = 0;
        }
         
        cur_base_index++;
    }
     
    return( ret );
}
 
int CHAR_LIST::_mode( int index )
{
    CHAR_SEED buf;
    read_SEED( index, (_SEED*)(&buf) );
    return( buf._mode() );
}
 
int CHAR_LIST::_step( int index )
{
    CHAR_SEED buf;
    read_SEED( index, (_SEED*)(&buf) );
    return( buf._step() );
}

CHAR.h (0.1.0)
#pragma once

#include "CURSOR_CONTROL.h"

class CHAR {
protected:
    unsigned char* c;
    int mode;                            // 現在CHARに格納されてる文字の、使用バイト数 (ASCII=1, MultiByte=2,3,4)
    int step;                            // 現在CHARに格納されてる文字の、表示ブロック数 (ASCII=1, MultiByte=2)

    virtual void calc_step(void);
    virtual void calc_mode(void);

public:
    CHAR(){ c = new unsigned char[4]; c[0]=' '; write_char(c); }
    virtual ~CHAR(){ delete[] c; }

    // char[4] を読み込み UTF-8 に変換して格納する。
    // リターンは使用してるバイト数。判別不能の時は0を返す。
    virtual int write_char( unsigned char* src );
    virtual int write_CHAR( CHAR* src ) { return( write_char( src->c ) ); }

    // char[4] に UTF-8 の先頭バイトから順に格納する。
    // ただし、使用されるバイト数は、モードの必要分”だけ”であり、
    // それ以降のバイトには一切触れない(値を変えない・アクセスすらしない)
    // 戻り値には、使用しているバイト数が返される。0の場合はほぼエラーを意味する。
    virtual int read_char( unsigned char* dst );
    virtual int read_CHAR( CHAR* dst ) { return( read_char( dst->c ) ); }

    // 文字の比較を行う。同じ場合は1、違う場合は0
    // なお、比較するバイト数は先頭から mode 数分だけ。以降のバイトは無視して比較する。
    virtual int comparison_char( unsigned char* src );
    virtual int comparison_CHAR( CHAR* src );

    // 指定したカーソル位置に一文字表示する
    // 戻り値は、文字の表示に使用したブロック数。ASCII(半角文字)の場合は1ブロック、非ASCII(全角文字)の場合は2ブロック
    // カーソル位置は、表示後も変わらない。(自動では進まない)
    virtual int print( CURSOR_CONTROL* cc );

    virtual int _mode(void) { return( mode ); }
    virtual int _step(void) { return( step ); }
};
CHAR.cpp (0.1.0)
#include <stdio.h>

#include "CHAR.h"
#include "CURSOR_CONTROL.h"

void CHAR::calc_step(void)
{
    switch(mode){
    case 0: step = 0; break;
    case 1: step = 1; break;    // ASCII 半角文字なら
    case 2: step = 2; break;    // 非ASCIIは全て全角文字として扱う。(半角カナなどは考慮しない)
    case 3: step = 2; break;
    case 4: step = 2; break;
    default: step = 0; break;
    }   
}

void CHAR::calc_mode( void )
{
      unsigned char c0 = c[0];

    mode = 0;

    // 先頭バイトがEOFならEOF
    if( (char)c0 == EOF ) {
        mode = 1;       
    }
    // 先頭bitが1ならマルチバイト文字、0ならASCII文字
    else if( ( c0 & 0x80 ) == 0 ) {
        mode = 1;
    }
    else {
        // 第2bitが0なら先頭以外の文字、1なら先頭文字
        if ( ( c0 & 0x40 ) == 0 ) {
        }
        else {
            // 第3bitが0なら2バイト文字、1なら3バイト以上の文字
            if ( ( c0 & 0x20 ) == 0 )  {
                mode = 2;
            }
            else {
                // ...かつ、第4bitが0なら3バイト文字、1なら4バイト文字
                if ( ( c0 & 0x10 ) == 0 )  {
                    mode = 3;
                }
                else {
                    mode = 4;
                }
            }
        }
    }

    calc_step();
}

// char[4] を読み込み UTF-8 に変換して格納する。
// リターンは使用してるバイト数。判別不能の時は0を返す。
int CHAR::write_char( unsigned char* src )
{
    c[0] = src[0];    //c[1] = src[1];    c[2] = src[2];    c[3] = src[3];
    calc_mode();

//    switch( mode ){
//    case 1:    c[0] = src[0];    c[1] = 0;        c[2] = 0;        c[3] = 0;        break;
//    case 2:    c[0] = src[0];    c[1] = src[1];    c[2] = 0;        c[3] = 0;        break;
//    case 3:    c[0] = src[0];    c[1] = src[1];    c[2] = src[2];    c[3] = 0;        break;
//    case 4:    c[0] = src[0];    c[1] = src[1];    c[2] = src[2];    c[3] = src[3];    break;
//    default: break;
//    }
    switch( mode ){
    case 1:    c[0] = src[0];    break;
    case 2:    c[0] = src[0];    c[1] = src[1];    break;
    case 3:    c[0] = src[0];    c[1] = src[1];    c[2] = src[2];    break;
    case 4:    c[0] = src[0];    c[1] = src[1];    c[2] = src[2];    c[3] = src[3];    break;
    default: break;
    }
   
    return( mode );
}

// char[4] に UTF-8 の先頭バイトから順に格納する。
// ただし、使用されるバイト数は、モードの必要分”だけ”であり、
// それ以降のバイトには一切触れない(値を変えない・アクセスすらしない)
// 戻り値には、使用しているバイト数が返される。0の場合はほぼエラーを意味する。
int CHAR::read_char( unsigned char* dst )
{
    calc_mode();
   
//    switch(mode){
//    case 1:    dst[0] = c[0];    dst[1] = 0;        dst[2] = 0;        dst[3] = 0;        break;
//    case 2:    dst[0] = c[0];    dst[1] = c[1];    dst[2] = 0;        dst[3] = 0;        break;
//    case 3:    dst[0] = c[0];    dst[1] = c[1];    dst[2] = c[2];    dst[3] = 0;        break;
//    case 4:    dst[0] = c[0];    dst[1] = c[1];    dst[2] = c[2];    dst[3] = c[3];    break;
//    default: break;
//    }
    switch(mode){
    case 1:    dst[0] = c[0];    break;
    case 2:    dst[0] = c[0];    dst[1] = c[1];    break;
    case 3:    dst[0] = c[0];    dst[1] = c[1];    dst[2] = c[2];    break;
    case 4:    dst[0] = c[0];    dst[1] = c[1];    dst[2] = c[2];    dst[3] = c[3];    break;
    default: break;
    }
   
    return( mode );
}

// 文字の比較を行う。同じ場合は1、違う場合は0
// なお、比較するバイト数は先頭から mode 数分だけ。以降のバイトは無視して比較する。
int CHAR::comparison_char( unsigned char* src )
{
    calc_mode();
    int ret=0;

    switch(mode){
    case 1: if(c[0]==src[0])                                                 ret=1; break;
    case 2: if(c[0]==src[0] && c[1]==src[1])                                 ret=1; break;
    case 3: if(c[0]==src[0] && c[1]==src[1]&& c[2]==src[2])                 ret=1; break;
    case 4: if(c[0]==src[0] && c[1]==src[1]&& c[2]==src[2]&& c[3]==src[3])    ret=1; break;
    }

    return( ret );
}

int CHAR::comparison_CHAR( CHAR* src )
{
    unsigned char buf[4];
    src->read_char( buf );
    return( comparison_char( buf ) );
}

// 指定したカーソル位置に一文字表示する
// 戻り値は、文字の表示に使用したブロック数。ASCII(半角文字)の場合は1ブロック、非ASCII(全角文字)の場合は2ブロック
// カーソル位置は、表示後も変わらない。(自動では進まない)
int CHAR::print( CURSOR_CONTROL* cc )
{
    unsigned char c[4];
    read_char( c );

    cc->__setpos( cc->pos_x, cc->pos_y);    // カーソル位置をセット
    for( int i=0; i < mode; i++ ) {
        putchar( c[i] );
    }
    cc->__setpos( cc->pos_x, cc->pos_y );    // putchar() の実行で変わったであろうカーソル位置を、元にもどす(自動での移動はさせない)

    return( step );   
}





_LIST (0.0.9) 他
_LISTtest.cpp (動作テスト用)

CHAR をメンバーにもつ CHAR_SEED 及び CHAR_LIST
CHAR_LIST をメンバーにもつ LINE_SEED 及び LINE_LIST
これらクラスを適当に書いてみたところ、あっさり動いた。
たったこれっぽっちのコードで。

しかしながら、「わかりづらい」という問題。
どうもオブジェクト指向の多態性を利用して設計すると、処理が細かく分散して、
どうにも「アテ」を付けられないコードになるような気がする…(読みにくいコード)

C(的な使い方)に抑えて書いたコードのような、読みやすさ、見通しのよさ、一つ一つのモジュールの局所性(いろんなとこ読まなくても、一ヶ所読めば読める的な)ってのは、
多態性を積極的に利用すると、どうも犠牲になっちゃうような気がする…
…たしかに、「作った直後で、イメージが頭にある、理解してる状態」なら、多態性のコードでも
割と動作をイメージできてるものなんだけど、
いざ、これを1年後に読み返して、はたして読めるか? と自分に問えば、はっきり言って
かなりシンドイと思う…

余談だけど、先日のフォトショップのプラグインのコードなんかは、まるっきり行き当たりばったりのスパゲッティーコードですけど、
一見、読みづらそうだけど、いざ読んでみると、上から順番に「書いたときの感覚」で読み直していけば、実は意外とすんなり頭に入ってくる。
でも、多態性で「小賢く」しくみを作ってしまったようなコードだと、この「一年後でもすんなり読める」ってのは期待できない。 かならず「???」ってなるはず。
どうも、多態性で型が状況に応じて変化するってのが、読みづらさの原因だと思う。
どうにも読みながら「これはコードには○○って書いてあるけど、実際の動作時には●●として動いてるはずなので〜… え〜と…」的なw これをやりながら 読む必要があるから、だから多態性のコードは読みづらいし、最初の一読だけで理解なんて無理。なんども全体を反復的に読み返さないと、コードの意味をつか めない読みづらさ。

漠然とした印象だけど、どうも、あんまり多態性なんかはコードに入れ込まない方が、理解しやすいコードになると思う。個人的に。
理解しやすいってことは、あとあと改造しやすいってことだし。やっぱりC++は単なるベターCとして素朴な書き方する方がいいのかもしれない…(0.0.8)あたりのコード程度の使い方が一番マシな気がする。個人的に。

さて、(0.0.9)のCHAR_LISTはどうするべか…
やっぱ捨てた方がいいんだろうな… 読めねぇもん、一年後に、これ…orz



_SEED.h (0.0.9)
#pragma once

class _SEED {
protected:
    _SEED*    next;
    _SEED*    back;

public:
    _SEED();
    virtual ~_SEED();

    virtual void    read( _SEED* dst ) {;}        // 派生したクラスの、ぶら下げたデータへの読み書きを、これら関数内で行う
    virtual void    write( _SEED* src ) {;}        // ...

    virtual void     add_next( _SEED* seed );
    virtual void     add_back( _SEED* seed );
    virtual _SEED*    del_next( void );
    virtual _SEED*    del_back( void );

    virtual _SEED*    get_next( void );
    virtual _SEED* get_back( void );
};
_SEED.cpp (0.0.9)
#include <stdio.h>
#include "_SEED.h"

_SEED::_SEED()
{
    next = 0;
    back = 0;
}

_SEED::~_SEED()
{
}

void _SEED::add_next( _SEED* seed )
{
    if( seed == 0 ) {
        this->next = 0;
    }
    else {
        _SEED* next = this->next;

        if( next != 0 ){
            next = this->next;
            next->back = seed;
        }

        seed->next = next;
        seed->back = this;

        this->next = seed;
    }
}

void _SEED::add_back( _SEED* seed )
{
    if( seed == 0 ) {
        this->back = 0;
    }
    else {
        _SEED* back = this->back;

        if( back != 0 ){
            back = this->back;
            back->next = seed;
        }
   
        seed->next = this;
        seed->back = back;

        this->back = seed;
    }
}

_SEED* _SEED::del_next( void )
{
    _SEED* del = 0;

    if( this->next == 0 ) {
    }
    else {
        del = this->next;
        if( del->next == 0 ) {
            this->next = 0;
        }
        else {
            _SEED* new_next    = del->next;
           
            this->next = new_next;
            new_next->back = this;           
        }
    }

    return( del );
}

_SEED* _SEED::del_back( void )
{
    _SEED* del = 0;

    if( this->back == 0 ) {
    }
    else {
        del = this->back;
        if( del->back == 0 ) {
            this->back = 0;
        }
        else {
            _SEED* new_back    = del->back;
           
            this->back = new_back;
            new_back->next = this;           
        }
    }

    return( del );
}

_SEED* _SEED::get_next( void )
{
    return( next );
}

_SEED* _SEED::get_back( void )
{
    return( back );
}

_LIST.h (0.0.9)
#pragma once

#include "_SEED.h"

// 派生させる場合に必要な設定について
// 新しい派生クラス x_LIST と、そのメンバ変数 x_SEED について、以下の設定が必須になります。
//
// ・x_SEED に、任意のメンバ変数を追加する。(任意)
//
// ・x_SEED に、任意のメンバ変数を追加した場合(ふつう追加するはず)、以下の2つの関数を再定義しなければならない
//   void read( _SEED* dst ) {;//ここに、データの、『 this から dst へ』の『書き写し(ポインタのコピーではない!)』 に関する命令を書く }
//   void write( _SEED* src ) {;// ...『src から this へ』の... }
//   なお、引数の _SEED* dst および src は、どちらも『実体が存在するポインタ』が前提です。(_SEED& dst および _SEED& src だと考えてください)
//
// ・x_LIST の new_SEED() 関数の再定義
//   これは _SEED 用の new オペレーターに相当する関数です。( operator new による再定義はしてません。理由はよくわかんないからですw )
//   virtual _SEED* new_SEED( void ) { x_SEED* seed = new x_SEED; return( (_SEED*)seed ); }
//
// 以上
class _LIST {
protected:
    _SEED*    seed_top;
    int        list_len;

    virtual void    size_add( int add_len );
    virtual void    size_dec( int dec_len );

    virtual _SEED* new_SEED( void ){ _SEED* seed = new _SEED;     return( (_SEED*)seed ); }        // new の代わりにこれを使う

public:
    _LIST();
    virtual ~_LIST();

    virtual _SEED*    seek( int index );
    virtual _SEED*    seek_top( void ) { return( seed_top ); }
    virtual _SEED*    seek_end( void ) { _SEED* end_seed = seek(list_len-1); return( end_seed ); }

    virtual void    size_set( int len );

    virtual int     read_LIST    ( int index, int width, _LIST* dst );
    virtual int     write_LIST    ( int index, int width, _LIST* src );
    virtual int     read_SEED    ( int index, _SEED* dst );
    virtual int     write_SEED    ( int index, _SEED* src );

    virtual int    _list_len(void) {return(list_len);}

//    virtual int cut( int index, _SEED* dst );
//    virtual int cut( int index, int width, _LIST* dst );
//    virtual int paste( int index, _SEED* src );
//    virtual int paste( int index, _LIST* src );
   
    virtual void     print_all_address(void);
};
_LIST.cpp (0.0.9)
#include <stdio.h>
#include "_LIST.h"

_LIST::_LIST()
{
    seed_top = new_SEED();
    list_len = 1;
}

_LIST::~_LIST()
{
    for(int i = list_len -1; i >= 0; i-- ) {
        _SEED* del_seed = seek(i);
       
        if( del_seed !=0 ) { delete del_seed; }
    }
}

_SEED* _LIST::seek( int index )
{
    if( index > list_len - 1 ) { index = list_len-1; }

    _SEED* cur_seed = seed_top;

    for( int i=1; i <= index; i++ ) {
        if(cur_seed==0) {break;}                            // 次が無ければ0を返す

        cur_seed = cur_seed->get_next();
    }

    return( cur_seed );
}

void _LIST::size_add( int add_len )
{
    _SEED* cur_seed = seek( list_len - 1 );
    _SEED* new_seed;

    for(int i=0; i < add_len; i++ ) {
        new_seed = new_SEED();
        cur_seed->add_next( new_seed );
        cur_seed = new_seed;
    }

    list_len += add_len;
}

void _LIST::size_dec( int dec_len )
{
    _SEED* cur_seed = seek( list_len - 1 );
    _SEED* del_seed;
   
    for(int i = 0; i < dec_len; i++ ) {
        cur_seed = cur_seed->get_back();
        del_seed = cur_seed->del_next();
        delete del_seed;
    }

    list_len -= dec_len;
}

void _LIST::size_set( int len )
{
    if( len <= 0 ) { len = 1; }

    int dif = len - list_len;
    if( dif > 0 ) {
        size_add(dif);
    }
    else if( dif < 0 ) {
        dif = -dif;
        size_dec(dif);
    }
    else {
    }   
}

int _LIST::read_SEED( int index, _SEED* dst )
{
    if( index < 0 )             { index = 0; }                            // 範囲アンダーなら最初
    if( index > list_len - 1 )    { index = list_len - 1; }                // 範囲オーバーなら最後

    _SEED* buf = seek( index );
    dst->write( buf );                                                    // あくまでnext,back変数以外のデータのリードライトのみ
}

int _LIST::write_SEED( int index, _SEED* src )
{
    if( index < 0 )             { index = 0; }                            // 範囲アンダーなら最初
    if( index > list_len - 1 )    { size_set( index ); }                    // 範囲オーバーならリストを伸ばす

    _SEED* dst = seek( index );
    dst->write( src );
}

int _LIST::read_LIST( int index, int width, _LIST* dst )
{
    if( index < 0 )                 { index = 0; }                            // 範囲アンダーなら最初
    if( index > list_len - 1 )        { index = list_len - 1; }                // 範囲オーバーなら最後
    if( index + width > list_len )    { width = list_len; }                    // 最大でも src の len 幅まで
    if( width <= 0 )                { width = 1; }                            // 幅が0以下なら1
   
    dst->size_set(width);                                                // dstの幅をwidthと同じに

    _SEED* buf = new_SEED();
    for(int si=index, di=0 ; si < index + width; si++, di++ ) {
        this->read_SEED( si, buf );   
        dst->write_SEED( di, buf );
    }
    delete buf;       
}

int _LIST::write_LIST( int index, int width, _LIST* src )
{
    if( index < 0 )                     { index = 0; }                            // 範囲アンダーなら最初
    if( width > src->_list_len() )        { width = src->_list_len(); }            // 最大でも src の len 幅まで
    if( width <= 0 )                    { width = 1; }
    if( index + width > list_len - 1 )    { this->size_set( index + width ); }    // 範囲オーバーならリストを伸ばす

    _SEED* buf = new_SEED();
    for(int si=0, di=index ; di < index + width; si++, di++ ) {
        src->read_SEED( si, buf );   
        this->write_SEED( di, buf );
    }
    delete buf;       
}

/*
int _LIST::cut( int index, _SEED* dst )
{
    if( index > list_len - 1 )     { printf("err _SEED.cut() index\n"); return(-1); }

    _
   
}

int _LIST::paste( int index, _SEED* src )
{
}

int _LIST::cut( int index, int width, _LIST* dst )
{
    if( width <= 0 )             { printf("err _LIST.cut() width\n"); return(-1); }
    if( index > list_len - 1 )     { printf("err _LIST.cut() index\n"); return(-1); }

    int s_index = index;
    int e_index = index + width;
    if( e_index > list_len - 1 ) { e_index = list_len - 1; }

    int dst_size = e_index - s_index; if( dst_size <= 0 ) { printf("err _LIST.cut() dst_size\n"); return(-1);}
    dst->size_set( dst_size );

    for( int si=s_index, di=0; si < e_index; si++, di++ ) {
        _SEED* src_seed = this->seek(si);
        dst->add_

        dst_seed->write( src_seed );
printf("dst_seed=%d\n",(int)dst_seed);
    }

    return(0);
}

int _LIST::paste( int index, _LIST* src )
{
}
*/

void _LIST::print_all_address(void)
{
    _SEED* cur_seed = seed_top;

    printf("list_len=%d\n", list_len);

    for(int i=0; i < list_len; i++ ) {
        printf("%d:%d\n",i,(int)cur_seed);
        cur_seed = cur_seed->get_next();
    }   
}

_LISTtest.cpp (動作テスト用)

CHAR をメンバーにもつ CHAR_SEED 及び CHAR_LIST
CHAR_LIST をメンバーにもつ LINE_SEED 及び LINE_LIST
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "_SEED.h"
#include "_LIST.h"

#include "CHAR.h"

class CHAR_SEED : public _SEED {
protected:
    CHAR*    ch;

public:
    CHAR_SEED(){ ch = new CHAR;}
    virtual ~CHAR_SEED(){ delete ch; }

    virtual void read( _SEED* dst )     { CHAR_SEED* seed = (CHAR_SEED*)dst;     seed->ch->writeCHAR( ch ); }
    virtual void write( _SEED* src )    { CHAR_SEED* seed = (CHAR_SEED*)src;     ch->writeCHAR( seed->ch ); }

    virtual int  write( CHAR* src )             { return( ch->writeCHAR(src) );}
    virtual int  write( unsigned char* src )    { return( ch->write(src) );}

    virtual int print( CURSOR_CONTROL* cc ){ return( ch->print(cc) ); }
};

class CHAR_LIST : public _LIST {
protected:
    virtual _SEED* new_SEED( void ) { CHAR_SEED* seed = new CHAR_SEED; return( (_SEED*)seed ); }

public:
    CHAR_LIST() { seed_top = (_SEED*) new CHAR_SEED; }
    virtual ~CHAR_LIST() {;}

    virtual int write_char( int index, unsigned char* str ) {
        CHAR_SEED* seed = (CHAR_SEED*)seek(index);
        return( seed->write(str) );
    }

    virtual int write_CHAR( int index, CHAR* src ) {
        CHAR_SEED* seed = (CHAR_SEED*)seek(index);
        return( seed->write( src ) );
    }

    virtual int write_str( unsigned char* str ) {
        int str_len = strlen((char*)str);
        int total_step = 0;
        int CHAR_count=0;
        for(int i=0; i<str_len; i++ ) {
            CHAR_count++;
            if( CHAR_count >  list_len - 1 ) { size_set(CHAR_count); }

            total_step += write_char(i, &(str[total_step]));
            if( total_step >= str_len ) { break; }
        }
        return(total_step);
    }

    virtual void print( CURSOR_CONTROL* cc ){
        for(int i = 0; i < list_len; i++ ) {
            CHAR_SEED* seed = (CHAR_SEED*)seek(i);
            int step = seed->print(cc);
            cc->pos_x += step;
        }
    }
};





class LINE_SEED : public _SEED {
protected:
    CHAR_LIST*    cl;

public:
    LINE_SEED(){ cl = new CHAR_LIST;}
    virtual ~LINE_SEED(){ delete cl; }

    virtual void     read( _SEED* dst )     { LINE_SEED* seed = (LINE_SEED*)dst;     seed->cl->write_LIST( 0, seed->cl->_list_len(), cl ); }
    virtual void     write( _SEED* src )    { LINE_SEED* seed = (LINE_SEED*)src;     cl->write_LIST( 0, seed->cl->_list_len(), seed->cl ); }

    virtual int    write_char( int index, unsigned char* str )     {cl->write_char(index, str);}
    virtual int    write_CHAR( int index, CHAR* str )                {cl->write_CHAR(index, str);}
    virtual int    write_str ( unsigned char* str )                {cl->write_str(str);}

    virtual int     print( CURSOR_CONTROL* cc )                        { cl->print(cc); }
};

class LINE_LIST : public _LIST {
protected:
    virtual _SEED* new_SEED( void ) { LINE_SEED* seed = new LINE_SEED; return( (_SEED*)seed ); }

public:
    LINE_LIST() { seed_top = (_SEED*) new LINE_SEED; }
    virtual ~LINE_LIST() {;}

    virtual int write_char( int h, int w, unsigned char* str ) {
        LINE_SEED* seed = (LINE_SEED*)seek(h);
        return( seed->write_char( w, str ) );
    }

    virtual int write_CHAR( int h, int w, CHAR* src ) {
        LINE_SEED* seed = (LINE_SEED*)seek(h);
        return( seed->write_CHAR( w, src ) );
    }

    virtual int write_str( int h, unsigned char* str ) {
        LINE_SEED* seed = (LINE_SEED*)seek(h);
        return( seed->write_str( str ) );
    }

    virtual void print( CURSOR_CONTROL* cc ){
        for(int i = 0; i < list_len; i++ ) {
            LINE_SEED* seed = (LINE_SEED*)seek(i);
            seed->print(cc);

            cc->pos_x = 0; cc->pos_y++;
        }
    }
};





int main()
{
    CURSOR_CONTROL cc;
    cc.clear_screen();
    cc.setpos(0,0);

    unsigned char uc1[] = "あいうえおかきくけこabcdefghij98765432101234567890";
    unsigned char uc2[] = "aioananfwieofrjno;aignaoid;fngaiorfmnare;ofijao;finoadfna";
    unsigned char uc3[] = "!”#$%&’()0=〜|";

    LINE_LIST* ll = new LINE_LIST;
    ll->size_set(10);
   
    ll->write_str(0,uc1);
    ll->write_str(1,uc2);
    ll->write_str(2,uc3);
   
    ll->print(&cc);
   
    LINE_LIST* ll2 = new LINE_LIST;

    ll->read_LIST( 1, 1, ll2 );
    cc.setpos( 0, cc.pos_y+2 );
    ll2->print(&cc);    

    ll->write_LIST( 8, 1, ll2 );
    cc.setpos( 0, cc.pos_y+2 );
    ll->print(&cc);    

    getchar();
    return(0);
}




コンパイルのコマンドライン
gcc -o il _LISTtest.cpp _LIST.cpp _SEED.cpp CHAR.cpp CURSOR_CONTROL.cpp -lstdc++ -lc



CHAR (0.0.8) 他
CHAR型を使って書き直すのをやってみて気づいたんだけど、
以下の感じで途中まで書いて、「さて、次はLINE_LISTを書き直せば一段落だな…」と思ったあたりで気づいたんですけど、
どうも考え方としては、
『文字を要素としたリスト構造』がCHAR_LIST型、
『行を要素としたリスト構造』がLINE_LIST型、
で、これらはどちらもリスト構造として、基本的なメカニズムがそっくりなことに気づいた。
…LINE_LISTを書き始めたぐらいでこれに気づいた(苦笑orz)

????_SEED 型に『なんらかのデータ』をぶら下げて、それを????_LIST型によって参照と追加削除を制御するっていう図式は、共通してるんですよね… CHAR_LIST型でも LINE_LIST型でも。

だから、この2つの型から、共通した操作『要素』を抽出して、それを一つの抽象化の形にできるような気がした。
これは難しくするためじゃない。 これはより簡単にするため。

まだ書いてなくて、構想だけだけど、おそらく『基本的なリスト構造』である ????_SEED と ????_LIST (まだ名前は考えてない)を、抽象的なリストクラスとして組んでみてはどうか?と思ってる。
当然、抽象的なので、データの実体は扱えない。 データの実体は ????_SEEDから派生したクラスにhas a関係で持たせる。
????_SEED をテンプレートを採るクラスとして作るやりかたはしない。
理由は単純に、書き方がよくわからないからです(苦笑
あと、テンプレートによる良い点と悪い点を、あまり考察したことが無いから、思わぬ副作用に悩まされかねないし、(いや、かならず悩まされるはず)で、つまり、めんどくさい…ってのもあります(汗

とりあえず、『リスト的な構造』たりえる、最低限の要素は何か? っていう考察による抽象化作業と、
あと、????_SEED と ????_LIST に「どんな名前をでっちあげるか(笑)」を考えて遊ぼうと思います…

CHAR.h (0.0.8)
#pragma once

#include "CURSOR_CONTROL.h"

class CHAR {
public:
//protected:
    unsigned char c[4];
    int mode;                            // 現在CHARに格納されてる文字の、使用バイト数 (ASCII=1, MultiByte=2,3,4)
    int step;                            // 現在CHARに格納されてる文字の、表示ブロック数 (ASCII=1, MultiByte=2)

    virtual void calc_step(void);

public:
    CHAR(){ unsigned char c[4]=" "; write(c); }
    virtual ~CHAR(){;}

    // char[4] を読み込み UTF-8 に変換して格納する。
    // リターンは使用してるバイト数。判別不能の時は0を返す。
    virtual int write        ( unsigned char* src );
    virtual int writeCHAR    ( CHAR* src ){ return( write( src->c ) ); }

    // char[4] に UTF-8 の先頭バイトから順に格納する。
    // ただし、使用されるバイト数は、モードの必要分”だけ”であり、
    // それ以降のバイトには一切触れない(値を変えない・アクセスすらしない)
    // 戻り値には、使用しているバイト数が返される。0の場合はほぼエラーを意味する。
    virtual int read        ( unsigned char* dst );
    virtual int readCHAR    ( CHAR* dst ){ return( read( dst->c ) ); }

    // 指定したカーソル位置に一文字表示する
    // 戻り値は、文字の表示に使用したブロック数。ASCII(半角文字)の場合は1ブロック、非ASCII(全角文字)の場合は2ブロック
    // カーソル位置は、表示後も変わらない。(自動では進まない)
    virtual int print( CURSOR_CONTROL* cc );

    virtual int _mode(void){ return( mode ); }
    virtual int _step(void){ return( step ); }
};


CHAR.cpp (0.0.8)
#include <stdio.h>
#include "CHAR.h"
#include "CURSOR_CONTROL.h"

void CHAR::calc_step(void)
{
    switch(mode){
    case 0: step = 0; break;
    case 1: step = 1; break;    // ASCII 半角文字なら
    case 2: step = 2; break;    // 非ASCIIは全て全角文字として扱う。(半角カナなどは考慮しない)
    case 3: step = 2; break;
    case 4: step = 2; break;
    default: step = 0; break;
    }   
}

// char[4] を読み込み UTF-8 に変換して格納する。
// リターンは使用してるバイト数。判別不能の時は0を返す。
int CHAR::write( unsigned char* src )
{
    CHAR* dst = this;

    dst->mode = 0;

    unsigned char c0 = src[0];
    unsigned char c1;
    unsigned char c2;
    unsigned char c3;

    // 先頭bitが1ならマルチバイト文字、0ならASCII文字
    if( ( c0 & 0x80 ) == 0 ) {
        dst->c[0] = c0;
        dst->c[1] = 0;
        dst->c[2] = 0;
        dst->c[3] = 0;
        dst->mode = 1;
    }
    else {
        // 第2bitが0なら先頭以外の文字、1なら先頭文字
        if ( ( c0 & 0x40 ) == 0 ) {
        }
        else {
            dst->c[0] = c0;

            // 第3bitが0なら2バイト文字、1なら3バイト以上の文字
            if ( ( c0 & 0x20 ) == 0 )  {
                dst->c[1] = src[1];
                dst->mode = 2;

                dst->c[2] = 0;
                dst->c[3] = 0;
            }
            else {
                // ...かつ、第4bitが0なら3バイト文字、1なら4バイト文字
                if ( ( c0 & 0x10 ) == 0 )  {
                    dst->c[1] = src[1];
                    dst->c[2] = src[2];
                    dst->mode = 3;

                    dst->c[3] = 0;
                }
                else {
                    dst->c[1] = src[1];
                    dst->c[2] = src[2];
                    dst->c[3] = src[3];
                    dst->mode = 4;
                }
            }
        }
    }

    calc_step();

    return( dst->mode );
}

// char[4] に UTF-8 の先頭バイトから順に格納する。
// ただし、使用されるバイト数は、モードの必要分”だけ”であり、
// それ以降のバイトには一切触れない(値を変えない・アクセスすらしない)
// 戻り値には、使用しているバイト数が返される。0の場合はほぼエラーを意味する。
int CHAR::read( unsigned char* dst )
{
    CHAR* src = this;

    switch(src->mode){
    case 1:
        dst[0] = src->c[0];
        return(1);
    case 2:
        dst[0] = src->c[0];
        dst[1] = src->c[1];
        return(2);
    case 3:
        dst[0] = src->c[0];
        dst[1] = src->c[1];
        dst[2] = src->c[2];
        return(3);
    case 4:
        dst[0] = src->c[0];
        dst[1] = src->c[1];
        dst[2] = src->c[2];
        dst[3] = src->c[3];
        return(4);
    default:
        return(0);
    }
}

// 指定したカーソル位置に一文字表示する
// 戻り値は、文字の表示に使用したブロック数。ASCII(半角文字)の場合は1ブロック、非ASCII(全角文字)の場合は2ブロック
// カーソル位置は、表示後も変わらない。(自動では進まない)
int CHAR::print( CURSOR_CONTROL* cc )
{
    unsigned char c[4];
    read( c );

    cc->__setpos( cc->pos_x, cc->pos_y);    // カーソル位置をセット
    for( int i=0; i < mode; i++ ) {
        putchar( c[i] );
    }
    cc->__setpos( cc->pos_x, cc->pos_y );    // putchar() の実行で変わったであろうカーソル位置を、元にもどす(自動での移動はさせない)

    return( step );   
}








CHAR_SEED.h (0.0.8)
#pragma once

#include "CHAR.h"
 
class CHAR_SEED {
protected:
    CHAR         c;
    CHAR_SEED*     next;
    CHAR_SEED*     back;

public:
    CHAR_SEED(){ next = 0; back = 0; }
    virtual ~CHAR_SEED(){ ; }

    virtual void        add_next( CHAR_SEED* cs );
    virtual void        add_back( CHAR_SEED* cs );

    virtual CHAR_SEED*    del_next( void );
    virtual CHAR_SEED*    del_back( void );

    virtual CHAR_SEED* get_next( void ) { return( next ); }
    virtual CHAR_SEED* get_back( void ) { return( back ); }

    virtual int         write        ( unsigned char* src )    { return( c.write( src ) ); }
    virtual int         writeCHAR    ( CHAR* src )            { return( c.writeCHAR( src ) ); }
    virtual int         read        ( unsigned char* dst )    { return( c.read( dst ) ); }
    virtual int         readCHAR    ( CHAR* dst )            { return( c.readCHAR( dst ) ); }

    virtual int        print( CURSOR_CONTROL* cc )        { return( c.print( cc ) ); }
};


CHAR_SEED.cpp (0.0.8)
#include "CHAR_SEED.h"

void CHAR_SEED::add_next( CHAR_SEED* cs )                // next に cs を挿入
{
    if( cs == 0 ) { this->next = 0; return; };            // cs がNullならnextに0(終端記号)をセットしてリターン

    if( this->next != 0 ) {
        this->next->back = cs;
    }

    cs->next            = this->next;
    cs->back            = this;

    this->next            = cs;
}

void CHAR_SEED::add_back( CHAR_SEED* cs )                // back に cs を挿入
{
    if( cs == 0 ) { this->back = 0; return; };            // cs がNullならbackに0(終端記号)をセットしてリターン

    if( this->back != 0 ) {
        this->back->next = cs;
    }

    cs->next            = this;
    cs->back            = this->back;

    this->back            = cs;
}

CHAR_SEED* CHAR_SEED::del_next( void )                    // next を1個除外(単にリストから除外されるだけ。メモリ開放は行われない)
{
    CHAR_SEED* del_cs = this->next;

    if( del_cs != 0 ) {
        if( del_cs->next != 0 ) {
            del_cs->next->back = this;
        }
       
        this->next = del_cs->next;
    }
    else {
        this->next = 0;
    }

    return( del_cs );                                    // 除外された cs のアドレスをリターン
}

CHAR_SEED* CHAR_SEED::del_back( void )                    // next を1個除外(単にリストから除外されるだけ。メモリ開放は行われない)
{
    CHAR_SEED* del_cs = this->back;

    if( del_cs != 0 ) {
        if( del_cs->back != 0 ) {
            del_cs->back->next = this;
        }
       
        this->back = del_cs->back;
    }
    else {
        this->back = 0;
    }

    return( del_cs );                                    // 除外された cs のアドレスをリターン
}



CHAR_LIST.h (0.0.8)
#pragma once

#include "CHAR_SEED.h"
#include "STRING.h"
 
class CHAR_LIST {
private:
    virtual void        size_add( int add_len );
    virtual void        size_dec( int dec_len );

protected:
    CHAR_SEED*            cs_top;
    int                 list_len;

    virtual CHAR_SEED*    seek( int index );
    virtual void         size_set( int set_len );

public:
    CHAR_LIST();
    virtual ~CHAR_LIST();

    virtual void         writeCHAR    ( int index, CHAR* ch );
    virtual void         writeSTRING    ( STRING* str );
    virtual void         readCHAR    ( int index, CHAR* ch );
    virtual void        readSTRING    ( STRING* str );

    virtual int        print        ( CURSOR_CONTROL* cc );

    virtual int        _list_len    (void){ return(list_len); }
};



CHAR_LIST.cpp (0.0.8)
#include <stdio.h>
#include <stdlib.h>
#include "CHAR_LIST.h"
 
CHAR_LIST::CHAR_LIST()
{
    unsigned char space[4] = " ";
 
    cs_top = new CHAR_SEED;
    cs_top->write( space );                                            // 初期値はスペース
    list_len = 1;                                                    // リスト長は1文字
}

CHAR_LIST::‾CHAR_LIST()
{
    CHAR_SEED* cs;
    cs = this->seek( list_len - 1 );                                // clの最後のcsのアドレス

    for( int i=list_len-1; i>=1; i-- ) {                            // cs が先頭になるまで繰り返す
        cs = cs->get_back();                                        // csをリストひとつ戻る
        delete cs->get_next();
    }
    delete cs;                                                        // 最後に先頭のcsを開放
}

CHAR_SEED* CHAR_LIST::seek( int index )                                // csのシーク
{
    CHAR_SEED* seek_cs = cs_top;
 
    if( index <  0        ) { index = 0; }                            // 範囲アンダーなら最小値
    if( index >= list_len ) { index = list_len -1; }                // 範囲オーバーなら最大値

    while( index > 0 ) {
        seek_cs = seek_cs->get_next();
        index--;
    }

    return( seek_cs );
}

void CHAR_LIST::size_add( int add_len )                                // 終端以降にcsをadd_len分だけ追加する
{
    CHAR_SEED* end_cs = seek(list_len-1);                            // 終端のcs
    CHAR_SEED* new_cs;

    for(int i=0; i<add_len; i++ ) {
        new_cs = new CHAR_SEED;                                        // 新しいcs一個分のメモリを確保       
        end_cs->add_next( new_cs );                                    // 終端に追加
        end_cs = end_cs->get_next();                                // 終点を次に進める
    }
    end_cs->add_next( (CHAR_SEED*)0 );                                // 最後にフタ

    list_len += add_len;
}

void CHAR_LIST::size_dec( int dec_len )
{
    int dif = list_len - dec_len;
    if( dif <= 0 ) { dec_len = list_len -1; }                        // difが0以下になってしまう場合は、difが1になる数をセットする

    CHAR_SEED* end_cs = seek(list_len-1);                            // 終端のcs
    CHAR_SEED* cur_cs = end_cs->get_back();                            // 終端の一個手前の位置
    CHAR_SEED* del_cs;

    for(int i=0; i<dec_len; i++ ) {
        del_cs = cur_cs->del_next();
        delete del_cs;

        cur_cs = cur_cs->get_back();
    }
    cur_cs->add_next( (CHAR_SEED*)0 );                                // 最後にフタ

    list_len -= dec_len;
}
 
void CHAR_LIST::size_set( int set_len )
{
    if( set_len <= 0 ) { set_len = 1; }                            // 0以下の長さを指定されたら1に

    int dif = set_len - list_len;

    if( dif > 0 ) {
        size_add( dif );
    }
    else if ( dif < 0 ) {
        dif = -dif;                                                    // 絶対値に(ーだったはずなので)
        size_dec( dif );
    }
    else {
        ;
    }
}
 
void CHAR_LIST::writeCHAR( int index, CHAR* ch )
{
    if ( index < 0 ) { index = 0; }                                 // index の範囲が0未満の場合、0にする。

    int dif = index - (list_len - 1);                                // index がリスト長を越えた場合、メモリー確保
    if( dif > 0 ) {
        size_set( index + 1 );
    }
 
    CHAR_SEED* cs = seek( index );
    cs->writeCHAR( ch );
}

void CHAR_LIST::writeSTRING( STRING* src )
{
    size_set( src->_len() );                                        // clをsrcの長さと同じにする
    CHAR buf;

    for( int i = 0; i < src->_len(); i++ ) {                        // srcの長さ分...
        src->readCHAR( i, &buf );                                    // srcから読み込み...
        writeCHAR( i, &buf );                                        // clに書き込む
    }
}
 
void CHAR_LIST::readCHAR( int index, CHAR* ch )
{
    if ( index <  0        ) { index = 0; }                         // index の範囲が0未満の場合、0にする。
    if ( index >= list_len ) { index = list_len - 1; }                // index の範囲が最大値を越えた場合、最大値に。

    CHAR_SEED* cs = seek( index );
    cs->readCHAR( ch );
}

void CHAR_LIST::readSTRING( STRING* dst )
{
    CHAR buf;
    dst->size_set( list_len );                                        // dstをclと同じ長さにする

    for( int i = 0; i < dst->_len(); i++ ) {
        readCHAR( i, &buf );                                        // clから読み込み...
        dst->writeCHAR( i, &buf );                                    // dstに書き込む
    }
}

int CHAR_LIST::print( CURSOR_CONTROL* cc )
{
    CURSOR_CONTROL cur_cc = *cc;

    int total_step = 0;
    int step;
    CHAR_SEED* cur_cs = cs_top;

    for( int i=0; i<list_len; i++ ){
        step = cur_cs->print(&cur_cc);
       
        cur_cs = cur_cs->get_next();
        cur_cc.pos_x += step;
        total_step += step;
    }

    cc->setpos(cc->pos_x, cc->pos_y);
    return( total_step );
}

 
 

STRING.h (0.0.8)
#pragma once

#include "CHAR.h"
#include "CURSOR_CONTROL.h"

class STRING {
protected:
    CHAR*    str;
    int        len;

    virtual void size_add( int add_len );
    virtual void size_dec( int dec_len );

public:
    STRING();
    virtual ~STRING();

    virtual void size_set( int set_len );

    virtual int write_char    ( int index,                 unsigned char* src );
    virtual int write_str    ( unsigned char* src );
    virtual int writeCHAR     ( int index,                 CHAR* src );
    virtual int writeSTRING( STRING* src );

    virtual int read_char    ( int index,                 unsigned char* dst );
    virtual int read_str    ( unsigned char* dst );
    virtual int readCHAR      ( int index,                 CHAR* dst );
    virtual int readSTRING    ( STRING* dst );

    virtual void print( CURSOR_CONTROL* cc );

    virtual int _len(void) { return(len); }
};



STRING.cpp (0.0.8)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "STRING.h"
#include "CHAR.h"
#include "CURSOR_CONTROL.h"

STRING::STRING()
{
    len    = 1;                                                        // lenには文字数が入る。データのバイト量ではないので注意。あくまで文字数。
    str    = new CHAR[len];
}

STRING::~STRING()
{
    delete[] str;
}

void STRING::size_add( int add_len )
{
    int new_len = len + add_len;
    CHAR* buf = new CHAR[new_len];

    for( int i=0; i<len; i++ ) {
        readCHAR( i, &(buf[i]) );                                    // バッファに退避
    }
   
    delete[] str;                                                    // 古いメモリを開放

    str = buf;                                                        // バッファのポインタを書き込む
    len = new_len;
}

void STRING::size_dec( int dec_len )
{
    int new_len = len - dec_len;

    CHAR* buf = new CHAR[len];
    for(int i = 0; i < len; i++ ) {
        buf[i] = str[i];                                            // バッファに退避
    }

    delete[] str;                                                    // メモリ開放...
    str = new CHAR[new_len];                                        // メモリ確保

    for( int i=0; i < new_len; i++ ) {
        str[i] = buf[i];                                            // 退避先から必要量だけ書きもどす
    }

    len = new_len;
}

void STRING::size_set( int set_len )
{
    if( set_len <= 0 ) { set_len = 1; }                                // 0以下なら、1をセット(最低でも1になる)
    int dif = set_len - len;

    if( dif > 0 ) {
        size_add( dif );   
    }
    else if( dif < 0 ) {
        dif = -dif;
        size_dec( dif );
    }
    else {
        ;
    }
}

int STRING::write_char( int index, unsigned char* src )
{
    if( index < 0 ) { index = 0; }                                    // index の範囲丸め

    if( len <= index ) {                                            // メモリが足りなかったら確保する
        int old_len = len;
        len = index + 1;

        CHAR* old_str = str;
        str = new CHAR[len];

        for(int i=0; i<old_len; i++ ) {                                // 古い内容のコピー
            str[i] = old_str[i];
        }

        for(int i=old_len; i<len; i++ ) {                            // 新規確保分はスペースで埋める
            unsigned char buf[4] = " ";
            str[i].write( buf );
        }

        delete[] old_str;                                            // 古いメモリを開放
    }

    return( str[index].write(src) );                                // srcをCHARに書き込み、使用したバイト数をリターンする   
}

int STRING::write_str( unsigned char* src )                        // 文字列srcの最後は必ず \0 であること
{
    int byte_len = strlen((char*)src);
    if( byte_len <= 0 ) { return(0); }                                // srcのbyte長が0以下なら0でリターン

    int dif = byte_len - len;                                        // 書き込み文字数に対する lenの不足文字数を得る(すべてASCIIと想定。十分量)
    if( dif > 0 ) {                                                    // 不足分があるなら、足りない分を確保する
        delete[] str;

        len = byte_len;
        str = new CHAR[len];
    }

    len = byte_len;

    int step=0;
    int s=0;
    for(int i=0; i<len; i++) {
        step += s;
        s = str[i].write( &(src[step]) );
        if( s==0 || src[step] == '\0' ){ len = i; return( step ); }
    }

    return( step );                                                    // srcをCHAR配列に書き込んだ際の、使用した総バイト数をリターンする
}

int STRING::writeCHAR( int index, CHAR* src )
{
    unsigned char buf[4];                                            // バッファーの確保
    for(int i=0; i<4; i++ ){ buf[i] = ' '; }                        // バッファーをスペース文字で初期化

    src->read( buf );
    return( write_char( index, buf ) );                                // bufをCHARに書き込み、使用したバイト数をリターンする   
}

int STRING::writeSTRING( STRING* src )
{
    if( src->len <= 0 ) { return(0); }                                // 文字数が0以下なら0でリターン

    unsigned char* buf = new unsigned char[src->len * 4];        // バッファーの確保
    for(int i=0; i<src->len * 4; i++ ){ buf[i] = ' '; }                // バッファーをスペース文字で初期化

    src->read_str( buf );                                            // src からバッファへ文字データを読み込み
    int step = write_str( buf );                                    // bufをCHAR配列に書き込み、使用した総バイト数をリターンするため

    delete[] buf;
    return(step);   
}

int STRING::read_char( int index, unsigned char* dst )
{
    if( index >= len ) { return(-1); }
    if( index < 0 ) { return(-1); }                                // 範囲外だったら読まずにリターン

    return( str[index].read( dst ) );                                // dstに一文字分を読み込み、使用バイト数をリターンする
}

int STRING::read_str( unsigned char* dst )
{
    if( len <= 0 ) { return(-1); }                                    // 文字数が0なら何もせずー1でリターン

    int step=0;   
    for(int i=0; i < len; i++ ) {
        step += str[i].read( &(dst[step]) );
    }

    dst[step]='\0';                                                    // 生成した文字列の最後に \0 を付加する
   
    return( step );
}

int STRING::readCHAR( int index, CHAR* dst )
{
    if( index >= len ) { return(-1); }
    if( index < 0 ) { return(-1); }                                // 範囲外だったら読まずにリターン

    unsigned char buf[4];
    str[index].read( buf );
    return( dst->write( buf ) );                                    // dstに一文字分を読み込み、使用バイト数をリターンする   
}

int STRING::readSTRING( STRING* dst )
{
    return( dst->writeSTRING( this ) );
}

void STRING::print( CURSOR_CONTROL* cc )
{
    CURSOR_CONTROL old = *cc;
    int step;

    for(int i=0; i<len; i++ ) {
        cc->setpos(cc->pos_x, cc->pos_y);
        step = str[i].print(cc);
       
        cc->pos_x += step;
    }

    *cc = old;
    cc->setpos(cc->pos_x, cc->pos_y);
}
















FILE_IO.h (0.0.8)
#pragma once
 
#include <stdio.h>
#include "CHAR.h"
 
class FILE_IO {
public:
    FILE* fp;
    int open_flag;

public:
    FILE_IO( char* file_name );
    virtual ~FILE_IO();

    virtual void    seek_set( long adrs );
    virtual void    seek_cur( long adrs );
    virtual void    seek_end( long adrs );
 
    virtual long    tell( void );

    // CHAR型へのファイルからの一文字読み込み、そしてファイルポインタを次の文字の先頭位置へ。
    // ファイルエラー、またはファイル終了の場合は EOF を返す。通常は現在のファイルシークのアドレスを返す。
    // (char[4] を読み込んで、状況に応じて読み込み、シーク調整を行ってる)
    virtual long read_char( CHAR* ch );

    // CHAR型からのファイルへの一文字書き込み。そしてファイルポインタを次の文字の先頭位置へ。
    // リターンは書き込んだバイト数を返す。UTF-8マルチバイトで帰ってくる可能性があるのは 1,2,3,4 のどれか。
    // リターンが 0 の場合は文字が書き込まれなかったという意味。とうぜん、ファイルポインタも進まない。
    virtual long write_char( CHAR* ch );
};
 
 

FILE_IO.cpp (0.0.8)
#include <stdio.h>
#include <string.h>
#include "FILE_IO.h"
#include "CHAR.h"
 
FILE_IO::FILE_IO( char* file_name )
{
    fp = fopen( file_name, "r+" );
    open_flag = 1;
}
 
FILE_IO::~FILE_IO()
{
    if( open_flag == 1 ){
        fclose( fp );
        open_flag=0;
    }
}
 
void FILE_IO::seek_set( long adrs )
{
    fseek( fp, adrs, SEEK_SET );
}

void FILE_IO::seek_cur( long adrs )
{
    fseek( fp, adrs, SEEK_CUR );
}

void FILE_IO::seek_end( long adrs )
{
    fseek( fp, adrs, SEEK_END );
}
 
long FILE_IO::tell( void )
{
    return( ftell(fp) );
}

// CHAR型へのファイルからの一文字読み込み、そしてファイルポインタを次の文字の先頭位置へ。
// ファイルエラー、またはファイル終了の場合は EOF を返す。通常は現在のファイルシークのアドレスを返す。
// (char[4] を読み込んで、状況に応じて読み込み、シーク調整を行ってる)
long FILE_IO::read_char( CHAR* ch )
{
    long a = tell();                                        // 読み込み開始位置の保存

    unsigned char c[4];
    c[0] =
    c[1] =
    c[2] =
    c[3] = 0;

    // 一文字ずつ c[] に読み込む、この際、EOF の文字の次以降は 0 になっているはず。
    int i;
    for ( i = 0; i < 4; i++ ) {
        c[i] = (unsigned char)fgetc(fp);
        if( c[i] == EOF ) { break; }
    }
   
    // 先頭バイトがEOFじゃなければ CHAR に書き込み、結果、判別されたマルチバイト文字の
    // バイト数に応じて、ファイルシークを調節する(次の文字の先頭バイトへ)
    if ( c[0] != EOF ) {
        switch( ch->write( c ) ) {
        case 0:        seek_set( a + 1 );    break;
        case 1:        seek_set( a + 1 );    break;
        case 2:        seek_set( a + 2 );    break;
        case 3:        seek_set( a + 3 );    break;
        case 4:        break;
        }
    }
    else {
        return( EOF );
    }

    return( tell() );
}

// CHAR型からのファイルへの一文字書き込み。そしてファイルポインタを次の文字の先頭位置へ。
// リターンは書き込んだバイト数を返す。UTF-8マルチバイトで帰ってくる可能性があるのは 1,2,3,4 のどれか。
// リターンが 0 の場合は文字が書き込まれなかったという意味。とうぜん、ファイルポインタも進まない。
long FILE_IO::write_char( CHAR* ch )
{
    unsigned char c[4];
    long len = ch->read( c );

    int i;
    for( i = 0; i < len; i++ ) {
        fputc( c[i], fp );
    }

    return( len );
}
 







CURSOR_CONTROL.h (0.0.8)
#pragma once

class CURSOR_CONTROL {
public:
    int pos_x;    // カーソルの現在位置
    int pos_y;
     
    int scr_w;    // スクリーンの幅・高さ
    int scr_h;

public:
    CURSOR_CONTROL();
    virtual ‾CURSOR_CONTROL();
 
    // 単純にカーソル位置を移動するのみ。内部処理的にプリント位置を調整する目的の時はこちら
    virtual void __setpos( int x, int y );
 
    // cc にカーソル位置情報を保存しつつ移動する。通常のカーソル移動はこちら
    virtual void setpos( int x, int y );

    // カーソルを1マス移動する(画面の外周外に出た場合は、外周位置に留まる)
    virtual void move_right( void );
    virtual void move_left ( void );
    virtual void move_up   ( void );
    virtual void move_down ( void );

    // キー入力を得る
    virtual char get_key(void);

    // 画面をクリアーする
    virtual void clear_screen( void );     
};


CURSOR_CONTROL.cpp (0.0.8)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "CURSOR_CONTROL.h"

 
#include <unistd.h>
#include <termios.h>
#include <sys/time.h>

static int flg_init_termios = 0;
static struct termios save_term;
static struct termios temp_term;

CURSOR_CONTROL::CURSOR_CONTROL()
{
    const int def_screen_w = 132;
    const int def_screen_h = 43;

    pos_x = 0;
    pos_y = 0;
    scr_w = def_screen_w;
    scr_h = def_screen_h;

    if( flg_init_termios == 0 ) {
          tcgetattr(fileno(stdin), &save_term);
          temp_term = save_term;
          temp_term.c_iflag &= IGNCR;
          temp_term.c_lflag &= ~ICANON;
          temp_term.c_lflag &= ~ECHO;
          temp_term.c_lflag &= ~ISIG;
          temp_term.c_cc[VMIN]=1;
          temp_term.c_cc[VTIME]=0;
          tcsetattr(fileno(stdin), TCSANOW, &temp_term);
    }
    flg_init_termios += 1;                                // ユニークカウンタ(これでシステム全体での起動数を把握しておく)
}

CURSOR_CONTROL::~CURSOR_CONTROL()
{
    flg_init_termios -= 1;                                // ユニークカウンタを一つ減らす
    if( flg_init_termios == 0 ) {
        tcsetattr(fileno(stdin), TCSANOW, &save_term );        // すべては、これを複数回起動してしまうのを防止するため。(ユニークカウンタ
    }
}
 
void CURSOR_CONTROL::setpos( int x, int y )
{
    pos_x = x;
    pos_y = y;
 
    if(pos_x >= scr_w){pos_x = scr_w-1;}
    if(pos_y >= scr_h){pos_y = scr_h-1;}

    if(pos_x < 0){pos_x = 0;}
    if(pos_y < 0){pos_y = 0;}
 
    __setpos( pos_x, pos_y );
}

void CURSOR_CONTROL::clear_screen( void )
{
    printf("%c[2J",0x1B );
}

char CURSOR_CONTROL::get_key(void)
{
    return( getchar() );
}

// カーソルを1マス移動する(画面の外周外に出た場合は、外周位置に留まる)
void CURSOR_CONTROL::move_right( void )
{
    pos_x++;
    if ( pos_x >= scr_w ) pos_x = scr_w - 1;

    setpos( pos_x, pos_y );   
}

void CURSOR_CONTROL::move_left( void )
{
    pos_x--;
    if ( pos_x < 0 ) pos_x = 0;

    setpos( pos_x, pos_y );   
}

void CURSOR_CONTROL::move_up( void )
{
    pos_y++;
    if ( pos_y >= scr_h ) pos_y = scr_h - 1;

    setpos( pos_x, pos_y );   
}

void CURSOR_CONTROL::move_down( void )
{
    pos_y--;
    if ( pos_y < 0 ) pos_y = 0;

    setpos( pos_x, pos_y );   
}

void CURSOR_CONTROL::__setpos( int x, int y )
{
    x+=1;
    y+=1;   

    printf("%c[%d;%dH",0x1b, y, x );
}



CHAR_SEEDmain.cpp (簡単なコンパイルテスト用)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CHAR_LIST.h"

int main()
{
    CURSOR_CONTROL cc;
    cc.setpos(10,5);
    cc.clear_screen();

    CHAR_LIST cl;

    STRING str;
    CHAR ch;
    unsigned char uc[]="あいうえおかきくけこ1234567890ABCDEFG";
    unsigned char buf[1000];
    ch.write( &(uc[30]) );

    str.write_str( uc );
    STRING s2;
    str.readSTRING( &s2 );
    s2.size_set(10);
    s2.print(&cc);

    getchar();

    return(0);
}
コンパイルのコマンドライン (linux / gcc)
gcc -o cs CHAR_SEEDmain.cpp CHAR_LIST.cpp CHAR_SEED.cpp CHAR.cpp STRING.cpp CURSOR_CONTROL.cpp -lstdc++

LINE_LIST.h (0.0.6) 書き直しかけ
#pragma once
 
#include "CHAR_LIST.h"
 
typedef struct tagLINE_SEED {
    CHAR_LIST cl;
    struct tagLINE_SEED* next;
    struct tagLINE_SEED* back;
} LINE_SEED;
 
typedef struct tagLINE_LIST{
    LINE_SEED* ls_top;
    int list_len;
} LINE_LIST;
 
extern void initLINE_LIST( LINE_LIST* ll, int len );
 
// メモリー確保領域を伸ばす
// 最後尾に len 分だけメモリーを追加する
// 確保した領域のCHAR_LISTは1文字分だけ確保されてスペースで初期化される
extern void stretchLINE_LIST( LINE_LIST* ll, int len );
 
// LISTを配列としてイメージした場合の、配列の添え字を意味する。 0番からはじまる。
//
// 配列のLIST長よりも添え字が大きかった場合( next = 0 の状態)の場合、最後の要素を返す。
// また、インデックスがマイナスの場合は、最初の要素を返す。
extern LINE_SEED* seekLINE_LIST( LINE_LIST* ll, int index );
 
// LINE_LIST の連結
// center が真中のLINE_LIST の最前部をあらわす。 center_len で幅を指定する、これが center の最後部となる。
// center の前後に back の最後尾と next 最前部とが、それぞれ連結する。
//
// 0 ポインタは、それぞれ最後部、最前部をあらわす。next が 0 なら最後部、back が 0 なら最前部である。
extern void linkLINE_LIST( LINE_LIST* center, int center_len, LINE_LIST* back, LINE_LIST* next );
 
// dst の dst_index 番目の手前の位置に、src の src_index 番目から len 分を挿入する。
// くわしくは __insertLINE_LIST() の説明を参照のこと。
// len は 1 以上の大きさを指定しなければならない。1行挿入なら len = 1 である。
// index が dst の長さを超えた場合は、最後からindex までの不足分のメモリ領域が確保されて、さらにその後ろのsrcがリンクされる。
extern void insertLINE_LIST( LINE_LIST* dst, int dst_index, LINE_LIST* src, int src_index, int len );
 
 
// row行、colum位置に文字列を len文字分書き込む。
// 行や列が足りなかった場合は、自動的にメモリー領域が新たに確保される
// row, colum にはマイナスを指定できない。マイナスの場合は何もせずに終了する。
extern void write_strLINE_LIST( LINE_LIST* top, int row, int colum, char* str, int len );
 
// row行、colum位置から文字列を読み込む。
// 行が足りなかった場合、最後の行が読み込まれる。列が足りなかった場合、列の最後までが読み込まれる。
// row, colum にはマイナスを指定できない。マイナスの場合は何もせずに終了する。
extern void read_strLINE_LIST( LINE_LIST* top, int row, int colum, char* str, int len );
 
// row行、colum位置に1文字を書き込む。
// くわしくは write_strLINE_LIST を参照
extern void write_LINE_LIST( LINE_LIST* top, int row, int colum, char c );
 
// row行、colum位置から1文字読み込む。
// くわしくは read_strLINE_LIST を参照
extern char read_LINE_LIST( LINE_LIST* top, int row, int colum );
 
 
LINE_LIST.cpp (0.0.6) 書き直しかけ
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LINE_LIST.h"
#include "CHAR_LIST.h"
 
extern void _insertLINE_LIST( LINE_LIST* ll, int index, int len );
extern void __insertLINE_LIST( LINE_LIST* dst, int index, LINE_LIST* src );
 
void initLINE_LIST( LINE_LIST* ll, int len )
{
    if (len < 1 ) { printf("err initLINE_LIST() len¥n"); exit(1); }
 
    ll->ls_top = (LINE_SEED*)malloc( sizeof(LINE_SEED) );    // まず先頭1つ分を設定して作るってしまって...
    ll->ls_top->back = 0;
    ll->ls_top->next = 0;
    initCHAR_LIST( &(ll->ls_top->cl), 0x01 );
    ll->list_len = 1;
 
    stretchLINE_LIST( ll, len - 1 );    // ...それをストレッチすることで領域を確保する。
}
 
// メモリー確保領域を伸ばす
// 最後尾に len 分だけメモリーを追加する
// 確保した領域のCHAR_LISTは1文字分だけ確保されてスペースで初期化される
void stretchLINE_LIST( LINE_LIST* ll, int len )
{
    LINE_SEED* cur = seekLINE_LIST( ll, ll->list_len - 1 );
    LINE_SEED* next;
     
    int i;
 
    for ( i = 0; i < len; i++ ) {
        cur->next = (LINE_SEED*)malloc(sizeof(LINE_SEED) * len);
        initCHAR_LIST( &(cur->next->cl), 0x01 );
 
        next = cur->next;
        next->back = cur;
        cur = next;
 
        ll->list_len++;
    }
 
    cur->next = 0;
}
 
// LISTを配列としてイメージした場合の、配列の添え字を意味する。 0番からはじまる。
//
// 配列のLIST長よりも添え字が大きかった場合( next = 0 の状態)の場合、最後の要素を返す。
// また、インデックスがマイナスの場合は、最初の要素を返す。
LINE_SEED* seekLINE_LIST( LINE_LIST* ll, int index )
{
    int i;
    LINE_SEED* cur = ll->ls_top;
 
    if (index < 0 ) { return( cur ); }
 
    for(i=0;i<index;i++){
        if( cur->next != 0 ) {
            cur = cur->next;
        }
        else {
            i = index;
        }
    }
 
    return( cur );
}
 
// insertLINE_LIST 用の準備
// LINE_LIST の index 番目から len 分だけ、LINE_SEED のメモリー領域を新規に確保して index の手前の位置に挿入する
// たとえば index が 0 で len が 10 ならば、新しい領域が0〜9に作られ、今までの古い領域が10以降に押しやられる。
// len は 1 以上の大きさを指定しなければならない。1行挿入なら len = 1 である。
// *アルゴリズムが変わったので、今は insetrLINE_LIST() の内部処理では使われてない。
void _insertLINE_LIST( LINE_LIST* ll, int index, int len )
{
    if (len < 1 ) { printf("err : _insertLINE_LIST() len¥n"); exit(1); }
 
    LINE_LIST nll;
    initLINE_LIST( &nll, len );
 
    LINE_SEED* fast = seekLINE_LIST( &nll, 0 );
    LINE_SEED* end  = seekLINE_LIST( &nll, nll.list_len - 1 );
    LINE_SEED* next = seekLINE_LIST( ll, index );
    LINE_SEED* back = next->back;
 
    if ( index == 0 ) {
        fast->back = 0;
 
        end->next  = next;
        next->back = end;
 
        ll->ls_top = fast;
    }
    else {
        fast->back = back;
        back->next = fast;
 
        end->next  = next;
        next->back = end;
    }
 
    ll->list_len += len;
}
 
// insertLINE_LIST 用の準備
// dst の index 番目の手前の位置に、src の0番目から list_len - 1 最目(つまり最後尾の要素)まですべてを挿入する。
// つまり dst のリンクを定義しなおすだけである。
// src の正体は insettLINK_LIST() 内で新たにメモリ確保されたバッファーである。これをdstのリンク先を修正することで挿入する。
// src の list_len (srcの長さ)が 1 以上の大きさでない場合は、なにもせずに終了する。
// index が dst の長さを超えた場合は、最後からindex までの不足分のメモリ領域が確保されて、さらにその後ろのsrcがリンクされる。
void __insertLINE_LIST( LINE_LIST* dst, int index, LINE_LIST* src )
{
    if( src->list_len < 1 ) { return; }
 
    LINE_SEED* fast = seekLINE_LIST( src, 0 );
    LINE_SEED* end  = seekLINE_LIST( src, src->list_len - 1 );
    LINE_SEED* next;
    LINE_SEED* back;
 
    if ( index == 0 ) {
        next = seekLINE_LIST( dst, index );
        back = 0;
 
        dst->ls_top = fast;
 
        fast->back = back;
        end->next  = next;
        next->back = end;
    }
    else if ( index >= dst->list_len ) {
        int dif = index - dst->list_len;
//printf("dif=%d¥n",dif);
        stretchLINE_LIST( dst, dif );
//printf("dst->list_len=%d¥n",dst->list_len);
 
        next = 0;
        back = seekLINE_LIST( dst, index );
 
        fast->back = back;
        back->next = fast;
        end->next  = next;
    }
    else {
        next = seekLINE_LIST( dst, index );
        back = next->back;
 
        fast->back = back;
        back->next = fast;
        end->next  = next;
        next->back = end;
    }
 
    dst->list_len += src->list_len;
}
 
// dst の dst_index 番目の手前の位置に、src の src_index 番目から len 分を挿入する。
// くわしくは __insertLINE_LIST() の説明を参照のこと。
// len は 1 以上の大きさを指定しなければならない。1行挿入なら len = 1 である。
// index が dst の長さを超えた場合は、最後からindex までの不足分のメモリ領域が確保されて、さらにその後ろのsrcがリンクされる。
void insertLINE_LIST( LINE_LIST* dst, int dst_index, LINE_LIST* src, int src_index, int len )
{
    // 引数が不正な場合は何もしないで即リターンする
    if( dst_index<0 || src_index<0 ) {return;}
 
    LINE_SEED* src_ls;
 
    char* buf = (char*)malloc(0xFFFF);
    LINE_LIST llb; initLINE_LIST(&llb, len);
    LINE_SEED* llb_ls;
 
    int j;
 
    for( j = 0; j < len; j++ ) {
        src_ls = seekLINE_LIST( src, src_index + j );
        llb_ls = seekLINE_LIST( &llb, j );
         
        read_strCHAR_LIST(  &(src_ls->cl), 0, buf, src_ls->cl.list_len );
        write_strCHAR_LIST( &(llb_ls->cl), 0, buf, src_ls->cl.list_len ); // src_ls なのはタイプミスではない
    }
 
    __insertLINE_LIST( dst, dst_index, &llb );
    free((void*)buf);
}
 
// row行、colum位置に文字列を len文字分書き込む。
// 行や列が足りなかった場合は、自動的にメモリー領域が新たに確保される
// row, colum にはマイナスを指定できない。マイナスの場合は何もせずに終了する。
void write_strLINE_LIST( LINE_LIST* top, int row, int colum, char* str, int len )
{
    // 領域がマイナス指定の場合は何もせず終了
    if( row < 0 || colum < 0 ) { return; }
 
    // 文字列長が1以下なら何もせず終了
    if ( len < 1 ) { return; }
 
    // len が str長よりも大きい場合は、str長に修正して実行する
    if ( len > (int)strlen(str) ) { len = (int)strlen(str); }
 
    // もし行が足りなかった場合は新たに行を確保する
    int dif = row - ( top->list_len - 1 );
    if ( dif > 0 ) {
        stretchLINE_LIST(top,dif);
    }
 
    LINE_SEED* lsp = seekLINE_LIST( top, row );
    write_strCHAR_LIST( &(lsp->cl), colum, str, len ); // colum が大きかった場合はこの関数内で新たに列が確保される
}
 
// row行、colum位置から文字列を読み込む。
// 行が足りなかった場合、最後の行が読み込まれる。列が足りなかった場合、列の最後までが読み込まれる。
// row, colum にはマイナスを指定できない。マイナスの場合は何もせずに終了する。
void read_strLINE_LIST( LINE_LIST* top, int row, int colum, char* str, int len )
{
    // 領域がマイナス指定の場合は何もせず終了
    if( row < 0 || colum < 0 ) { return; }
 
    // 文字列長が1以下なら何もせず終了
    if ( len < 1 ) { return; }
 
    // len が str長よりも大きい場合は、str長に修正して実行する
    if ( len > (int)strlen(str) ) { len = (int)strlen(str); }
 
    // もしrowが最大行をオーバーした場合は、最大行に修正して実行する
    int dif = row - ( top->list_len - 1 );
    if ( dif > 0 ) {
        row -= dif;
    }
 
    LINE_SEED* ls = seekLINE_LIST( top, row );
    read_strCHAR_LIST( &(ls->cl), colum, str, len ); // colum が大きかった場合はこの関数内で、列の最後までが読み込まれる
}
 
// row行、colum位置に1文字を書き込む。
// くわしくは write_strLINE_LIST を参照
void write_LINE_LIST( LINE_LIST* top, int row, int colum, char c )
{
    char str[2];
    str[0] = c;
    str[1] = '¥0';
 
    write_strLINE_LIST( top, row, colum, str, 1 );
}
 
// row行、colum位置から1文字読み込む。
// くわしくは read_strLINE_LIST を参照
char read_LINE_LIST( LINE_LIST* top, int row, int colum )
{
    char str[2];
    str[0] = '¥0';
    str[1] = '¥0';
 
    read_strLINE_LIST( top, row, colum, str, 1 );
    return( str[0] );
}







ETC_MATH (0.0.7)
math.cのソースは読んだことないんで憶測ですが、おそらくアレのサイン、コサインはテイラーてんかいでやってんだろうな…と。そんな気がする。
あれだと精度もそれなりに出るし良いんだけど、いかんせん、除算と乗算を何回も繰り返す計算になるので、たぶんテーブルにしちゃった方が速いだろうな…とおもった。

…まぁ、常套手段ですがw

昔はメモリー資源が貴重だったんで、0〜π/2までのテーブルを用意して、それをブロック毎に分岐して読み方を変えることで使いまわすような組み方が普通だったんだけど、
今の時代はメモリーが余りまくりなので(メモリーがギガとかマジありえねぇ〜〜w)、贅沢に無駄に、無駄というか、素直に作っても大丈夫な気がする。(変に小賢い工夫とかせずに)

昔は浮動小数点数演算が遅かったので、固定小数点数を使って高速化をするのが普通でしたけど、最近は浮動小数点数型も整数型も、さして処理速度に昔ほどの大きな差はなくなってるので、無理して固定小数なんか使わなくても、素直に浮動小数で作ればいいだろうな…と考えた。

ちなみに、PC98なんかでゲーム作るときは、0〜π/2の範囲を256に分割したテーブルを用意して、その三角関数は256を1として扱う固定小数点数型を返したりしてた。そういうのが普通だった。
固定小数点数は足し算と引き算は普通にやっていいんだけど、掛け算の場合は計算後に>>してやる必要があって、その右シフト量がちょうど1を表す数、たとえば8ビット(256)なワケさ。
PSだともう少し少数の精度を増やして、4096を1として扱うのがハード的な仕様として?決められてた。GTEっていう行列演算専用のユニットであつかう行列はshort型(16びっと)の3x3の正方行列で、これの単位が4096=1だったわけで、小数部12ビット、整数部4ビット(いや3+符号だったか?わすれた)の固定小数点型だったりしました。

で、もぅ現代のパソコンはアホみたいにメモリーがあり余ってるし、浮動小数点数でも計算そこそこ速いんで、テーブルは0〜π/2じゃなくて、0〜2πをフルに用意しちゃって、テーブル分割数は0x40000 (!?バカかよっw)、つまり1/4ブロック毎に64k分割してます。しかもそのテーブルには固定小数点数じゃなくて浮動小数点数型の数値が格納されてる。という仕様。
…たぶんPC98時代だったら、まずまともには動かないレベルw(メモリー的にも処理速度的にも)

でも、まぁとりあえず試しに組んでみて、速度比較のためにn<20までのテイラータイプのsin関数を書いて、これと処理速度の比較をしてみたのですが、
テイラー展開型の sin だと、 sin(π/4)を1000万回計算するのに、指折り数えて6秒程度、
テーブル型の sin だと、同様の計算が一瞬でした。なので指折り数えられなかったので、10倍の1億回計算させましたが、それでも1秒程度でした。
つまり、ざっと見積もっても50倍くらいは速い。

ただ、もちろん、速度重視の単純なテーブル型だと、線形の補間なんてのはしないで、単純に小数切り捨てで近くの箱を選択するだけなので、精度的には劣る。千分の1くらいまでは平気なんだけど、1万分の1くらいの精度になるともぅ無理。 ここを(速度を保ったまま)上げようと思ったら、単純にテーブルをもっと膨大にすればいいんだろうけど、現時点でも64*4*4で、テーブルだけでも1メガ越えてるし、(しかも sin, cos で共用せずに、それぞれ専用に用意してる(アホ過ぎるっw))、さすがに千分の1の精度が出れば、まぁ、当面ホビーには充分だろうし…ははw

ETC_MATH.h (0.0.7)
#ifndef _ETC_MATH_H_
#define _ETC_MATH_H_
 
// a^inv
extern int pow(int a, int inv );
 
// 基数による桁数
extern int _dig(int a, int cardinal );
 
// 数値型から文字列型
extern void itos( char* dst, int src );

extern double factoriol( long a );            // 階乗
extern double pow_f( double a, long inv );    // 累乗
extern double exp_taylor( double a );            // expornent
extern double sin_taylor( double a );            // sin(テイラー展開

// テーブルによる三角関数
extern double sin_t( double a );
extern double cos_t( double a );
extern double tan_t( double a );



 
#endif // _ETC_MATH_H_
 

ETC_MATH.cpp (0.0.7)
#include <stdio.h>
#include <stdlib.h>
#include "ETC_MATH.h"
#include "ETC_MATH_TABLE.h"
 
// a^inv
int pow(int a, int inv )
{
    int r=a;
 
    if(inv==0) r=1;
    if(inv==1) r=a;
 
    int i;
    for(i=2;i<=inv;i++){r*=a;}
 
    return(r);
}
 
// 基数による桁数
int _dig(int a, int cardinal )
{
    if( cardinal ==0 ){printf("err: dig() cardinal¥n");exit(1);}
 
    int count=0;
 
    while(a>0){
        count++;
        a/=cardinal;
        if( a <= 0 ) { break; }
    }
 
    return(count);
}
 
// 数値型から文字列型
void itos( char* dst, int src )
{
    if(src > 0){
        int p;
        int unit;
        int sub=0;
        int dig=_dig(src,10);
        int i;
        for(i=0;i<dig;i++){
            p=pow(10,i+1);
            sub+=((src%p)-sub);
            unit=sub / pow(10, i);
 
            switch(unit){
                case 0:dst[dig-1-i]='0';break;
                case 1:dst[dig-1-i]='1';break;
                case 2:dst[dig-1-i]='2';break;
                case 3:dst[dig-1-i]='3';break;
                case 4:dst[dig-1-i]='4';break;
                case 5:dst[dig-1-i]='5';break;
                case 6:dst[dig-1-i]='6';break;
                case 7:dst[dig-1-i]='7';break;
                case 8:dst[dig-1-i]='8';break;
                case 9:dst[dig-1-i]='9';break;
                default:printf("err: itos() dst[%d]¥n",dig-1-i ); exit(1); break;
            }
        }
        dst[dig]='¥0';
    }
    else {
        dst[0]='0';
        dst[1]='¥0';
    }
}

double factoriol( long a )
{
    double v = 1;

    for(long i = 1; i <= a; i++ ) {
        v *= (double)i;
    }

    return( v );
}

double pow_f( double a, long inv )
{
    double r=a;

    if(inv==0){r=1;}
    if(inv==1){r=a;}
   
    for(long i=2; i <= inv; i++ ){ r *= a; }
 
    return(r);
   
}

double exp_taylor( double a )
{
    double v=0;

    for(long i = 0; i < 10; i++ ) {
        v += ( 1.0 / factoriol(i) ) * pow_f(a,i);
    }   
   
    return( v );
}

double sin_taylor( double a )
{
    double v=0;
    double fugou=1.0;

    for(long i=1; i<20; i+=2 ) {
        v += fugou * ( ( 1.0 / factoriol(i) ) * pow_f(a, i) );
        fugou=-fugou;
    }

    return( v );
}



static double ETC_MATH_t_table_rd( ( (double)ETC_MATH_TABLE_SIZE / 2 ) / 3.14159265358979 );
double sin_t( double a )
{
    unsigned long l = (unsigned long)( a * ETC_MATH_t_table_rd );
    l %= ETC_MATH_TABLE_SIZE;
    return( ETC_MATHsin_table[l]);
}

double cos_t( double a )
{
    unsigned long l = (unsigned long)( a * ETC_MATH_t_table_rd );
    l %= ETC_MATH_TABLE_SIZE;
    return( ETC_MATHcos_table[l]);
}

double tan_t( double a )
{
    unsigned long l = (unsigned long)( a * ETC_MATH_t_table_rd );
    l %= ETC_MATH_TABLE_SIZE;
    return( ETC_MATHtan_table[l]);
}

ETC_MATH_make_TABLE.cpp (0.0.7)

(これをコンパイルして実行すると ETC_MATH_TABLE.h が生成されます)
(それを ETC_MATH.cpp に #include して使います)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>



#define TABLE_SIZE 0x40000



int main()
{
///*
    {
        FILE* fp = fopen( "ETC_MATH_TABLE.h","w+" );
        double rd=3.14159265358979 / (TABLE_SIZE / 2);
        long i;

        fprintf(fp,"#ifndef _ETC_MATH_TABLE_H_\n" );
        fprintf(fp,"#define _ETC_MATH_TABLE_H_\n\n" );

        fprintf(fp,"#define ETC_MATH_TABLE_SIZE %d\n\n", TABLE_SIZE );


        fprintf(fp,"static double ETC_MATHsin_table[ETC_MATH_TABLE_SIZE] = {\n" );
        for(i=0; i < TABLE_SIZE; i++) {
            fprintf( fp, "%f,\t ",sin(rd*i) );
            if((i%8)==0){
                fprintf(fp,"\n");
            }
        }   
        fprintf(fp,"\n};\n\n" );

        fprintf(fp,"static double ETC_MATHcos_table[ETC_MATH_TABLE_SIZE] = {\n" );
        for(i=0; i < TABLE_SIZE; i++) {
            fprintf( fp, "%f,\t ",cos(rd*i) );
            if((i%8)==0){
                fprintf(fp,"\n");
            }
        }   
        fprintf(fp,"\n};\n\n" );

        fprintf(fp,"static double ETC_MATHtan_table[ETC_MATH_TABLE_SIZE] = {\n" );
        for(i=0; i < TABLE_SIZE; i++) {
            fprintf( fp, "%f,\t ",tan(rd*i) );
            if((i%8)==0){
                fprintf(fp,"\n");
            }
        }   
        fprintf(fp,"\n};\n\n" );


        fprintf(fp,"#endif // _ETC_MATH_TABLE_H_\n" );

        fclose(fp);
    }
//*/

    return(0);
}







INT (0.0.7)
整数を格納するための int 型という標準型があるんだけど、これだと最大でも 32bit までしか格納できないので( gcc の場合)、それよりも大きい数を代入すると桁溢れを起こしてしまう。

通常型の int には、具体的には±20億程度の数まで格納できる。
これは、桁数に直すと 10 ケタ。
16進数での桁数に直すと 8 ケタ。

これをもっと、膨大な数でも、『ケタ溢れを心配しないで使える型』ってのがあれば、便利なんじゃないだろうか?
と思った。
「そういう型は無いのかなぁ〜?」と思ってC言語入門とか読んでみても、どうやら無いみたいなので、自分で作ることにしました。

INT 型では、±2億ケタ程度の数まで扱えます。(あくまで設計上)
初期状態では 32 ビット長です。 これが、演算によってケタ溢れを起こすと、自動的にビット数を増やします。
増やすビット数は8ビット単位です。たとえば32ビットで +0x FF FF FF FF だったとして、これに1を加えると
、自動的サイズが変更されてに 0x 01 FF FF FF FF となります。

INT同士での四則演算ができます。演算結果が桁溢れした場合も、自動的にサイズが増やされます。

INTに対してのビット演算が可能です。

INTに対してのシフト演算が可能です。シフト演算の場合は、自動的なサイズ拡張は『行いません』。
桁溢れした値は捨てられます。
(引数には、シフトするバイト数を渡します。正のlong型です。(←つまり+20億bit まで))

シフト演算の前には、使用するバイト数を明示的に指定した方がいいです。
そのために size_set() を用意してあります。これでINTのバイト長を直接指定できます。
相対的にバイト長を指定したい時のために size_add() もしくは size_dec も用意してあります。
(引数にはいずれも正のlong型を渡します。)



データ構造:
符号無char型の位置を記録するための配列に、
個々に定義したcharを、それぞれ個々にぶら下げる形です。
(注:charが連続した配列である保証はありません)

012len-1
... ...(←CHAR*型の配列)
  (←ポインタを登録)
... ...(←CHAR型の実データ)



加算:
INT型のAに対して、INT型のBを加算する場合。

Aの方が短い
76543210 


 
A

B



長い方(B)の長さに合わせて、短い方(A)を伸ばす
 76543210 
 

A
 B



描くバイトを 2バイトと解釈してA+Bとして加算する
0 
A
+ 
B



各バイトを2バイトに拡張した単位で加算した結果の、LSB側1バイトが、そのインデックスでの加算結果となる。
HSB1バイト側は、次のインデックスのバイトに加算される。
これを n-1 まで単純に繰り返すだけです。
 n-13210    
     A0   
     +    
     B0   
     =    
    A'0   
    +     
     A1   
    +     
     B1   
    =     
    A'1   
   +      
     A2   
   +      
     B2   
   =      
    A'2   
  +       
     A3   
  +       
     B3   
  =       
    A'3   
 +        
     An-1   
 +        
     Bn-1   
 =        
    A'n-1   
          



減算:
加算と同じパターンです。
(ただし、Bを2の補数した数を加算します)

補数について:



乗算:



除算:





INT.h (0.0.7)
#pragma once

class INT {
//protected:
public:
    unsigned char**    byte;
    long                len;
    long                fugou;

    virtual unsigned char        _byte(long index)                            { if((index<len) && (index>=0)) return(*(byte[index])); else return(0); }
    virtual void                _set_b(long index, unsigned char c)        { if((index<len) && (index>=0)) (*byte[index])=c; else return; }
    virtual long                _len(void)                                     { return(len); }
    virtual long                _b_len(void);
    virtual long                 _fugou(void)                                 { return(fugou); }
    virtual void                _set_fugou( long f )                        { if( f == +1 ) fugou = +1; else if( f == -1 ) fugou = -1; };

    virtual void                _add( INT* a );        // 内部処理用
    virtual void                _sub( INT* a );        // 内部処理用
    virtual void                _mul( INT* a );        // 内部処理用
    virtual void                _deq( INT* a );        // 内部処理用
public:
    INT(void);
    virtual ~INT(void);
    virtual void gc(void);                    // 余分な確保分のメモリー領域を開放して、len を正しい値に設定する。

    virtual void set( long l );                // long 型の値をセットできる。
    virtual void copy( INT* a );                // a の内容を自分に書き込む(ようするにコピーです)

    virtual void size_set( long size );        // 格納できる桁数をセットする(バイト単位)
    virtual void size_add( long size );        // 格納できる桁数を今より増やす(バイト単位)
    virtual void size_dec( long size );        // 格納できる桁数を今より減らす(バイト単位)

    virtual int  comparison( INT* a );            // 比較を行い、=なら0、自分の方が大きい(>)なら+1、aの方が大きい(<)なら-1を返す
    virtual int  comparison_abs( INT* a );        // 絶対値で比較。あとは comparison() と同じ

    virtual void r_shift( long s );            // 右シフト演算
    virtual void l_shift( long s );            // 左シフト演算
   
    virtual void b_and( INT* a );                // バイナリーAND &
    virtual void b_or ( INT* a );                // バイナリーOR  |
    virtual void b_xor( INT* a );                // バイナリーXOR ^
    virtual void b_not( void );                // バイナリーNOT ~
    virtual void b_0( void );                    // バイナリーAll0(すべてのビットを0にする)
    virtual void b_1( void );                    // バイナリーAll1(すべてのビットを1にする)
    virtual void b_comprement( void );        // バイナリー補数に変換

    virtual void add( INT* a );
    virtual void sub( INT* a );
    virtual void mul( INT* a );
    virtual void deq( INT* a );

    virtual void print(void);
    virtual void print0x( void );
};




INT.cpp (0.0.7)
#include <stdio.h>
#include "INT.h"

INT::INT(void)
{
    fugou     = +1;
    len     = 4;
    byte     = new (unsigned char*[len]);
    for( long i = 0; i < len; i++ ) {
        byte[i] = new (unsigned char);
        *byte[i] = 0;
    }
}

INT::~INT(void)
{
    for(int i = 0; i < len; i++ ) {
        delete byte[i];
    }
    delete[] byte;
}

// 余分な確保分のメモリー領域を開放して、len を正しい値に設定する。
void INT::gc(void)
{
    long old_len = len;
    long new_len = 1;                                                // 最低でも1byteの長さは残すため。( デフォルトで =1 にしてある理由)

    for(long i = len-1; i >= 1; i-- ) {                           
        if( *(byte[i]) == 0x00 ){
        }
        else {
            new_len = i+1;                                               
            break;
        }
    }

    for(long i = old_len-1; i >= new_len; i-- ) {                    // len の位置以上の、使わない余分なメモリを開放する
        delete (byte[i]);
    }

    len = new_len;

// ポインタの配列そのものは開放しない。(伸びたら、伸びっぱなし)
// 毎回いちいちこれまで再定義して縮めてると、char をぶら下げ直す処理時間がバカにならない気がするので。これだと気になって気分的に使い辛くなるから。伸ばしっぱなし。触れない。

//    unsigned char** list = new (unsigned char*[len]);            // charをぶら下げるための、新しい長さの、ポインタの配列を新たに確保。(スワップ用)
//    for(int i = 0; i < len; i++ ) {                                    // 新しいポインタの配列に、古いcharをぶら下げなおす。
//        list[i] = byte[i];                                            // ポインタのコピー(アドレスのコピー)
//    }

//    delete[] byte;                                                    // 古いリストの開放
   
//    byte = new (unsigned char*[len]);                                // charをぶら下げるための、新しい長さの、ポインタの配列を新たに確保。
//    for(int i = 0; i < len; i++ ) {                                    // 新しいポインタの配列に、古いcharをぶら下げなおす。
//        byte[i] = list[i];                                            // ポインタのコピー(アドレスのコピー)
//    }
//    delete[] list;
}

// a の内容を自分に書き込む(ようするにコピーです)
void INT::copy( INT* a )
{
    size_set( a->_len() );                            // this の byte長を、a のbyte長にあわせる

    for(long i=0; i < len; i++ ) {                    // a のbyte内容を、thisのbyteに全部書き写す
        *(byte[i]) = a->_byte(i);                   
    }

    fugou = a->_fugou();                            // 符号も書き写す
}

// 格納できる桁数を今より増やす(バイト単位)
void INT::size_add( long size )
{
    if( size <= 0 ) {return;}                        // size が0以下なら処理しないでリターン

    unsigned char** buf = new (unsigned char*[len + size]);
    for(long i = 0; i < len; i++ ) {
        buf[i] = byte[i];                            // ポインタの書き写し(あくまでポインタ。実体ではない)
    }
   
    delete[] byte;                                    // とりあえず開放
    byte = new (unsigned char*[len + size]);        // そして再確保(領域拡張)

    for(long i = 0; i < len; i++ ) {
        byte[i] = buf[i];                            // ポインタの書き写し(あくまでポインタ。実体ではない)
    }
    for(long i = len; i < len + size; i++ ) {
        byte[i]     = new (unsigned char);        // あらたな伸ばした分の領域を確保
        *(byte[i])     = 0;                            // 0で内容を初期化
    }

    len += size;                                    // 新しいサイズをメモ
    delete[] buf;                                    // バッファーを開放して終了
}

// 格納できる桁数を今より減らす(バイト単位)
void INT::size_dec( long size )
{
    if( size <= 0 ) {return;}                        // size が0以上なら処理しないでリターン
   
    if( ( len - size ) <= 0 ) {
        size = len - 1;                                // もしsizeが大きすぎてlenが0以下になってしまう場合、size は len - size = 1 の数に設定。(最低でも1byteの長さを保つ)
    }

    for(long i = len - size; i < len; i++ ) {
        delete byte[i];                                // len-size(新サイズ)以降のbyteを全て開放
    }

    unsigned char** buf = new (unsigned char*[len - size]);
    for(long i = 0; i < len-size; i++ ) {
        buf[i] = byte[i];                            // ポインタの書き写し(あくまでポインタ。実体ではない)
    }
   
    delete[] byte;                                    // とりあえず開放
    byte = new (unsigned char*[len - size]);        // そして再確保(領域拡張)

    for(long i = 0; i < len-size; i++ ) {
        byte[i] = buf[i];                            // ポインタの書き写し(あくまでポインタ。実体ではない)
    }

    len -= size;                                    // 新しいサイズをメモ
    delete[] buf;                                    // バッファーを開放して終了
}

// 格納できる桁数を設定する(バイト単位)
void INT::size_set( long size )
{
    if( size <= 0 ) {return;}                        // size が0以下なら処理しないでリターン
   
    long dif = size - len;                            // 新サイズに対する、旧サイズの不足分

    if( dif > 0 ) {                                    // サイズが足りなければ増やす
        size_add( dif );
    }
    else if( dif < 0 ) {                            // サイズが多ければ減らす
        dif=-dif;
        size_dec( dif );
    }
    else {                                            // サイズが同じなら何もしない
        ;
    }
}

// bit長を返す(もっともHSB側のbitの番目までの長さを返す。たとえばLSBのみが1なら長さは1。1バイトすべてが1なら長さは8)
long INT::_b_len(void)
{
    for(long i=len-1; i>=0; i-- ) {
        unsigned char c = *(byte[i]);
        if( c != 0 ) {
            if( c & ((unsigned char)(0x01<<7)) ) {
                return( (i*8) + 8 );
            }
            else if ( c & ((unsigned char)(0x01<<6)) ) {
                return( (i*8) + 7 );
            }
            else if ( c & ((unsigned char)(0x01<<5)) ) {
                return( (i*8) + 6 );
            }
            else if ( c & ((unsigned char)(0x01<<4)) ) {
                return( (i*8) + 5 );
            }
            else if ( c & ((unsigned char)(0x01<<3)) ) {
                return( (i*8) + 4 );
            }
            else if ( c & ((unsigned char)(0x01<<2)) ) {
                return( (i*8) + 3 );
            }
            else if ( c & ((unsigned char)(0x01<<1)) ) {
                return( (i*8) + 2 );
            }
            else if ( c & ((unsigned char)(0x01<<0)) ) {
                return( (i*8) + 1 );
            }
        }
    }
}

void INT::r_shift( long s )
{
    if( s <= 0 ) {return;}                            // シフト量が0、もしくはマイナスの場合は処理しないでリターン
   
    long                 sm = s % 8;                    // ビット単位でのスモールなシフト量
    long                 sb = s / 8;                    // バイト単位でのビッグなシフト量

    for(long i = sb; i < len; i++ ) {                // とりあえず sb 単位での移動を終わらしちゃおう。
        *(byte[i-sb]) = *(byte[i]);                    // 内容を直接書き写しちゃう。ようするに普通のコピー。
    }

    long edge = len - sb;
    if ( edge < 0 ){ edge=0; }
    for(long i=edge; i < len; i++) {   
        *(byte[i]) = 0;                                // シフトで空になった分は 0 で埋めます。
    }

    (*(byte[0])) >>= sm;
    for(long i=1; i < len; i++) {                    // 次に残りの sm 単位での移動を終わらせちゃおう。
        unsigned short buf;
        buf = (unsigned short)(*(byte[i]));
        buf <<= 8;
        *(byte[i-1]) |= (unsigned char)( ( (buf >> sm) >> 0 ) & 0x00FF );    // 一個手前の値にORで加える   
        *(byte[i-0])  = (unsigned char)( ( (buf >> sm) >> 8 ) & 0x00FF );    // こちらは単純に代入
    }
}

void INT::l_shift( long s )
{
    if( s <= 0 ) {return;}                            // シフト量が0、もしくはマイナスの場合は処理しないでリターン
   
    long                 sm = s % 8;                    // ビット単位でのスモールなシフト量。
    long                 sb = s / 8;                    // バイト単位でのビッグなシフト量。

    for(long i = len-1; i >= sb; i-- ) {            // とりあえず sb 単位での移動を終わらしちゃおう。逆順だから、すこしややこしい。
        *(byte[i]) = *(byte[i-sb]);                    // 内容を直接書き写しちゃう。ようするに普通のコピー。
    }

    long edge = sb-1;
    if ( edge > (len-1) ){ edge=(len-1); }
    for(long i=edge; i >= 0; i--) {
        *(byte[i]) = 0;                                // シフトで空になった分は 0 で埋めます。逆順だから、すこしややこしい。
    }

    (*(byte[len-1])) <<= sm;
    for(long i=len-1-1; i >= 0; i--) {                // 次に残りの sm 単位での移動を終わらせちゃおう。逆順だから、すこしややこしい。
        unsigned short     buf;
        buf = (unsigned short)(*(byte[i]));
        *(byte[i+1]) |= (unsigned char)( ( (buf << sm) >> 8 ) & 0x00FF );    // 一個次の値にORで加える   
        *(byte[i+0])  = (unsigned char)( ( (buf << sm) >> 0 ) & 0x00FF );    // こちらは単純に代入
    }
}

// バイナリーAND &
void INT::b_and( INT* a )
{
    long s_len;   
    s_len = ( len <= a->_len() ) ? len : a->_len();            // 2つのうち、短い方のbyte長

    for(long i = 0; i < s_len; i++ ) {                        // 短い方の長さにあわせて処理
        *(byte[i]) = (*(byte[i])) & a->_byte(i);            // 仮に、自分同士で計算してる場合でも、バッファーを介さなくても問題ない
    }

    for(long i = s_len; i < len; i++ ) {                    // 残りはすべて0をセット(短い方の、足りないbyte分は、すべて0と解釈して計算する)
        *(byte[i]) = 0;
    }
}

// バイナリーOR  |
void INT::b_or ( INT* a )
{
    long s_len;   
    s_len = ( len <= a->_len() ) ? len : a->_len();            // 2つのうち、短い方のbyte長

    for(long i = 0; i < s_len; i++ ) {                        // 短い方の長さにあわせて処理
        *(byte[i]) = (*(byte[i])) | a->_byte(i);            // 仮に、自分同士で計算してる場合でも、バッファーを介さなくても問題ない
    }
                                                            // 残りはすべて不変(短い方の、足りないbyte分は、すべて0と解釈して計算する)
}

// バイナリーXOR ^
void INT::b_xor( INT* a )
{
    long s_len;   
    s_len = ( len <= a->_len() ) ? len : a->_len();            // 2つのうち、短い方のbyte長

    for(long i = 0; i < s_len; i++ ) {                        // 短い方の長さにあわせて処理
        *(byte[i]) = (*(byte[i])) ^ a->_byte(i);            // 仮に、自分同士で計算してる場合でも、バッファーを介さなくても問題ない
    }
                                                            // 残りはすべて不変(短い方の、足りないbyte分は、すべて0と解釈して計算する)
}

// バイナリーNOT !
void INT::b_not( void )
{
    for(long i = 0; i < len; i++ ) {
        *(byte[i]) = ~(*(byte[i]));                            // 仮に、自分同士で計算してる場合でも、バッファーを介さなくても問題ない
    }
}

// バイナリーAll0
// (すべてのビットを0にする)
void INT::b_0( void )
{
    for(long i = 0; i < len; i++ ) {
        *(byte[i]) = 0;
    }
}

// バイナリーAll1
// (すべてのビットを1にする)
void INT::b_1( void )
{
    for(long i = 0; i < len; i++ ) {
        *(byte[i]) = (unsigned char)(0xFF);
    }
}

// バイナリー補数に変換
void INT::b_comprement(void)
{
    INT one;                                                // 内容が 0x01 の INT型のインスタンスを作成するため
    long one_l = 1;
    one.set( one_l );

    INT buf;
    buf.copy( this );                                        // this のコピーを作り...
    buf.b_not();                                            // ビットを反転し
    long old_len = buf._len();                                // この時点でのlenサイズをメモ
    buf._add( &one );                                        // 符号無視で1を加算。(両者は符号も同じなので、符号解釈ありでも結果は同じだが、一応、本来の意味で)

    if( buf._len() > old_len ) {                            // もしlenが増えてたら
        buf.size_dec( buf._len() - old_len );                // 増えた分、縮める。(buf._len() - old_len は 1byteのはず。buf.set_dec(1)でも同じだが、一応、本来の意味で)
    }

    copy( &buf );                                            // buf を this にコピー
}

// 符号を考慮した加算
void INT::add( INT* a )
{
//    a->gc();                                                // 保険
//    gc();

    if ( fugou > 0 ) {
        if ( a->_fugou() > 0 ) {                            // どちらもプラスなら、通常の加算
            _add( a );
        }
        else if ( a->_fugou() < 0 ) {                        // this がプラス、a がマイナスのケース
            int comp = comparison_abs( a );                    // 絶対値で比較

            if ( comp > 0 ) {                                // this の方が大きければ
//printf("t - a\n");
//this->print0x();
//a->print0x();
                _sub( a );                                    // this - a として計算
            }
            else if ( comp < 0 ) {                            // a の方が大きければ
//printf("a - t\n");
                INT buf;
                buf.copy( a );
                buf._sub( this );                            // a - this として計算し
                copy( &buf );                                // 加算結果を this に入れ
                fugou = -1;                                    // this の符号を -1 にする
            }
            else {                                            // 絶対値での比較結果が同じだった場合
                set(0);                                        // this は 0
            }
        }
    }
    else if ( fugou < 0 ) {                                    // this の符号がマイナスの場合
        if ( a->_fugou() < 0 ) {                            // どちらもマイナスなら、通常の加算
            _add( a );
        }
        else if ( a->_fugou() > 0 ) {                        // this はマイナス、aはプラスのケース
            int comp = comparison_abs( a );                    // 絶対値で比較

            if ( comp > 0 ) {                                // this の方が大きければ
//printf("bbbb");
                _sub( a );                                    // this - a として計算
            }
            else if ( comp < 0 ) {                            // a の方が大きければ
//printf("aaaa");
                INT buf;
                buf.copy( a );
                buf._sub( this );                            // a - this として計算し
                copy( &buf );                                // 加算結果を this に入れ
                fugou = +1;                                    // this の符号を +1 にする
            }
            else {                                            // 絶対値での比較結果が同じだった場合
//printf("cccc");
                set(0);                                        // this は 0
            }
        }
    }

//    gc();                                                    // もし余ってるメモリがあるなら開放
}

// 符号を考慮しない加算(内部処理用)
void INT::_add( INT* a )
{
    long s_len;                                                // 2つのうち、短い方のbyte長
    long b_len;                                                // 2つのうち、短い方のbyte長
    if( len >= a->_len() ) {
        s_len = a->_len();
        b_len = len;
    }
    else {
        s_len = len;
        b_len = a->_len();
    }

    a->size_set( b_len );                                    // 長い方のサイズにあわせてメモリ確保
    size_set( b_len );                                        // 同

    unsigned short co = 0;                                    // キャリーオーバーのメモ用
    for(long i = 0; i < b_len; i++ ) {                        // 長い方の長さにあわせて処理
        unsigned short buf1, buf2, buf3;
        buf1         = (unsigned short)(*(byte[i]));
        buf2        = (unsigned short)(a->_byte(i));
       
        buf3         = (buf1 + co) + buf2;

        _set_b( i, (unsigned char)( buf3 & 0x00FF ) );
        co            = (buf3 >> 8) & 0x00FF;                    // 今回分のキャリーオーバー量をメモ
    }

    if( co != 0 ) {                                            // もし、キャリーオーバーの値があれば、それを格納するために1バイト伸ばして記録。
        size_add(1);
        _set_b( len - 1, (unsigned char)( co & 0x00FF) );
    }
}

void INT::sub( INT* a )
{
//    a->gc();                                                // 保険
//    gc();

    if ( fugou > 0 ) {
        if ( a->_fugou() > 0 ) {                            // どちらもプラスなら、通常の減算
            int comp = comparison_abs( a );                    // 絶対値で比較

            if ( comp > 0 ) {                                // this の方が大きければ...
                _sub( a );                                    // 通常の減算
                                                            // this の符号は変化しない           
            }
            else if ( comp < 0 ) {                            // a の方が大きければ...
                INT buf;
                buf.copy( a );
                buf._sub( this );
                copy( &buf );                                // a - this での減算
                fugou = -1;                                    // this の符号を -1 にする
            }
            else {                                            // 絶対値での比較結果が同じだった場合
                set(0);                                        // this は 0
            }
        }
        else if ( a->_fugou() < 0 ) {                        // this がプラス、a がマイナスのケース
            _add( a );                                        // 加算を行い...
                                                            // this の符号は変化しない
        }
    }
    else if ( fugou < 0 ) {                                    // this の符号がマイナスの場合
        if ( a->_fugou() < 0 ) {                            // どちらもマイナスなら...
            int comp = comparison_abs( a );                    // 絶対値で比較

            if ( comp > 0 ) {                                // this の方が大きければ...
                _sub( a );                                    // 通常の減算
                                                            // this の符号は変化しない           
            }
            else if ( comp < 0 ) {                            // a の方が大きければ...
                INT buf;
                buf.copy( a );
                buf._sub( this );
                copy( &buf );                                // a - this での減算
                fugou = +1;                                    // this の符号を +1 にする
            }
            else {                                            // 絶対値での比較結果が同じだった場合
                set(0);                                        // this は 0
            }
        }
        else if ( a->_fugou() > 0 ) {                        // this がマイナス、a がプラスのケース
            _add( a );                                        // 加算を行い...
                                                            // this の符号は変化しない
        }
    }

//    gc();                                                    // もし余ってるメモリがあるなら開放
}

void INT::_sub( INT* a )
{
    INT a_c;                                                // a の補数用
    a_c.copy( a );
    a_c.size_set(len);                                        // a_c を this の len と同じbyte長に設定
    a_c.b_comprement();                                        // 実際に a の補数を得る

    long old_len = len;                                        // this の、この時点でのbyte長をメモ
    _add( &a_c );                                            // this に補数を加算する(減算)(符号は無視する)

    if( len > old_len ) { size_set(old_len); }                // もしold_lenより伸びてたら、lenの長さまでちぢめる
}

void INT::mul( INT* a )
{
    _mul(a);

    if( fugou > 0 ) {
        if( a->_fugou() > 0 ) {
            fugou = +1;
        }
        else if( a->_fugou() < 0 ) {
            fugou = -1;
        }
    }
    else if( fugou < 0 ) {
        if( a->_fugou() > 0 ) {
            fugou = -1;
        }
        else if( a->_fugou() < 0 ) {
            fugou = +1;
        }
    }
}

void INT::_mul( INT* a )
{
    a->gc();                                                        // 必要最小限のbyte長のlenを得る
    gc();

    long old_fugou_a         = a->_fugou();                            // 符号を一時的に保存
    long old_fugou_this     = fugou;

    a->_set_fugou(+1);                                                // 符号を一時的に+に設定
    fugou=+1;

    long b_len;                                                        // 2つのうち、長い方のbyte長
    b_len = ( len >= a->_len() ) ? len : a->_len();

    INT b;
    b.copy( this );                                                    // 参照用バッファに、自分自身の値をコピー

    set( 0 );                                                        // 自分自身の内容を0にリセット

    INT sft;   
    sft.copy( a );                                                    // シフトには a をつかう。
    sft.size_set( b_len * 2 );                                        // b_len の2倍のサイズを確保。

    long sft_count = 0;                                                // ループ中での、次のシフト量のカウント用

    for(long byte_i = 0;  byte_i < b_len; byte_i++ ) {                // 長い方のバイト長回数分だけ繰り返す
        for(long bit_i = 0; bit_i < 8; bit_i++ ) {                    // 1バイト中のビット数(8ビット)回数分だけ繰り返す
            unsigned char bit_msk = (0x01 << bit_i);
            if( ( b._byte( byte_i ) & bit_msk ) != 0 ) {            // 現在の byte_i の bit_i 番目のビットが1なら
                sft.l_shift( sft_count );                            // sht の内容を、シフトカウント分だけ左シフトする               
                add( &sft );                                        // その sht を自分自身に加算

                sft_count = 0;                                        // カウンタリセット
                                                                    // 直後ですぐ1になる。これを0で回してしまうと、仮にその回でシフトの必要が発生しても、シフト0に
                                                                    // なってしまう。(シフトされないバグになる)
                                                                    // シフト0が使われるのは最初の先頭一回目のみ。あとはシフトは必ず1以上。微妙に組み間違えやすいので注意。
            }
            sft_count++;                                            // カウンターを1回進める。
        }
    }   

    a->_set_fugou(old_fugou_a);                                        // 一時的に変更した符号を、元に戻す
    fugou = old_fugou_this;

    a->gc();                                                        // 無駄なbyte長を捨てる
    gc();
}

void INT::deq( INT* a )
{
    _deq( a );

    if( fugou > 0 ) {
        if( a->_fugou() > 0 ) {
            fugou = +1;
        }
        else if( a->_fugou() < 0 ) {
            fugou = -1;
        }
    }
    else if( fugou < 0 ) {
        if( a->_fugou() > 0 ) {
            fugou = -1;
        }
        else if( a->_fugou() < 0 ) {
            fugou = +1;
        }
    }
}

void INT::_deq( INT* a )
{
    a->gc();                                                        // 必要最小限のbyte長のlenを得る
    gc();

    long old_fugou_a         = a->_fugou();                            // 符号を一時的に保存
    long old_fugou_this     = fugou;

    a->_set_fugou(+1);                                                // 符号を一時的に+に設定
    fugou=+1;


    long a_bitlen     = a->_b_len();
    long this_bitlen    = _b_len();
    long dif_bitlen = this_bitlen - a_bitlen;

    if( dif_bitlen < 0 ){ set(0); return; }


    INT ans;                                                        // 減算回数のカウント用(これが除算結果)
    ans.size_set( len );                                            // this と同じbyte長に

    INT buf;                                                        // 雑用
    buf.size_set( len );                                            // this と同じbyte長に
   
    INT sft;
    sft.copy( a );                                                    // これをシフトしながら減算に使う
    sft.size_set( len );                                            // this と同じbyte長に

    sft.l_shift( dif_bitlen );                                        // bit長の差分だけ左シフト
    for(long i=0; i <= dif_bitlen; i++ ){
        if( comparison_abs( &sft ) >= 0 ){
            sub( &sft );
           
            buf.b_0();
            buf.set(0x01);
            buf.l_shift( (dif_bitlen)-i );
            ans.b_or(&buf);   
        }
        sft.r_shift(1);
    }

    copy(&ans);

       
    a->_set_fugou(old_fugou_a);                                        // 一時的に変更した符号を、元に戻す
    fugou = old_fugou_this;

    a->gc();                                                        // 無駄なbyte長を捨てる
    gc();
}

// 比較を行い、=なら0、自分の方が大きい(>)なら+1、aの方が大きい(<)なら-1を返す
int INT::comparison( INT* a )
{
    int comp =  comparison_abs( a );                                // とりあえず絶対値で符号無視による比較

    if( fugou > 0 ) {                                                // this の符号がプラス
        if ( a->_fugou() > 0 ) {                                    // this も a もどちらもプラスのケース
            return( comp );                                            // 通常の比較
        }
        else if( a->_fugou() < 0 ) {                                // this がプラス、a がマイナスのケース
            return( +1 );                                            // this が大きいと判定
        }
    }
    else if( fugou < 0 ) {                                            // this の符号がマイナス
        if( a->_fugou() < 0 ) {                                        // this も a もどちらもマイナスのケース
            return( -comp );                                        // 通常の比較の逆(*マイナス)       
        }
        else if ( a-> _fugou() > 0 ) {                                // this がマイナス、a がプラスのケース
            return( -1 );                                            // a が大きいと判定       
        }
    }
}

// 絶対値で比較。あとは comparison() と同じ
int INT::comparison_abs( INT* a )
{
    int        ret_large_s;
    int        ret_large_b;
    int        ret_equal = 0;

    INT*    s_int;                                                    // 2つのうち、短い方のINTへのアドレス
    INT*    b_int;                                                    // 2つのうち、長い方のINTへのアドレス

    if ( len >= a->_len() ) {
        s_int = a;
        b_int = this;
        ret_large_s = -1;                                            // s_int が大きかった場合に、-1を返す。(aが大きいの意味なので)
        ret_large_b = +1;                                            // b_int が大きかった場合に、+1を返す。(thisが大きいの意味なので)
    }
    else {
        s_int = this;
        b_int = a;
        ret_large_s = +1;                                            // s_int が大きかった場合に、+1を返す。(thisが大きいの意味なので)
        ret_large_b = -1;                                            // b_int が大きかった場合に、-1を返す。(aが大きいの意味なので)
    }


    for(int i=b_int->_len(); i > s_int->_len(); i-- ) {                // 最後(一番大きい桁側)から読んでいき、s_int の最後に行き着くまでに 非0 の値があれば、こちらが大きい
        if ( b_int->_byte(i) != 0 ) {
            return ret_large_b;                                        // b_int の方が大きいと解釈してリターン
        }
    }

    for(int i=s_int->_len(); i >= 0; i-- ) {                        // s_int の最後(一番大きい桁側)から読んでいき、0に行き着くまで、どちらが大きいかを比較する
        unsigned char cs,cb;
        cs = s_int->_byte(i);
        cb = b_int->_byte(i);

        if( cb > cs ){
            return ret_large_b;                                        // b_int の方が大きいと解釈してリターン
        }
        else if ( cs > cb ) {
            return ret_large_s;                                        // s_int の方が大きいと解釈してリターン
        }
    }

    return ret_equal;                                                // b_int と s_int に違いが無かったので、同じ値だと解釈してリターン
}

void INT::set( long l )
{
    size_set(4);                                                    // thisを4byteの長さに   

    if( l < 0 ) { l = -l; fugou = -1; } else { fugou = +1; }        // 符号

    *byte[0] = (unsigned char)( ( l & 0x000000FF ) >> 0  );
    *byte[1] = (unsigned char)( ( l & 0x0000FF00 ) >> 8  );
    *byte[2] = (unsigned char)( ( l & 0x00FF0000 ) >> 16 );
    *byte[3] = (unsigned char)( ( l & 0xFF000000 ) >> 24 );
}

void INT::print( void )
{
    long l;
    l =
         ( ((unsigned long)(*byte[0]))  << 0  ) |
         ( ((unsigned long)(*byte[1]))  << 8  ) |
         ( ((unsigned long)(*byte[2]))  << 16 ) |
         ( ((unsigned long)(*byte[3]))  << 24 );

    if( fugou<0 ){ l=-l; }

    printf( "%ld", l );
}

void INT::print0x( void )
{
    if ( fugou < 0 ) putchar('-');

    printf("0x");

    for(long i = len-1; i >= 0; i-- ) {
        printf( "%02X", *byte[i] );

        if( ( i % 4 ) == 0 ) {
            putchar(' ');
        }
        if( ( i % 32 ) == 0 ) {
            putchar('\n');
            putchar(' ');
            putchar(' ');
        }
    }
}












ふぁむいり
たのしかた
20091123_02x.jpg

わるのり
20091123_3x.jpg

また描いてるよコイツ…w
20091123_5.jpg

泣いた
20091123_6x.jpg

うろおぼえコスモス
20091123_07x.jpg


チャー
20091120_01x.png

SCREEN メモ (0.0.1)
スクリーンへの描画関係を担当。
まだ全然プロトタイプ。
大まかなアルゴリズムの確認で行き当たりばったりで組んだので、全体的に絡みがひどい、見通しの悪い、わかりずらい仕組みになってる。
もっと単純・簡単な景色へと書き直さないとしないと、難しくて使えない…使いたくない(orz

具体的には今後、STRING型をCHAR型で書き直して、そのSTRING型でLINE_LIST型を書き直して、そのLINE_LIST型でSCREEN型を書き直したらどうかなぁ…と考えてます。

SCREEN.h (0.0.1)
/*
    SCREEN
    SCREENにはスクリーンへの文字バッファの描画を担当する。
    ユーザーはSCREENの文字バッファに文字列を登録して、SCREENに描画を実行させる。
    文字バッファには文字情報が格納されてるが、ここはあくまで描画バッファなので、ここからデータを『取り出す』ような使い方はしてはいけない。
    あくまでSCREENの仕事は与えられたバッファをスクリーンに描画するのみである。
    ここを文字情報の格納場所として考えたような使い方は『しないように!!』。(これは各モジュール間の依存関係を極力なくすため作戦です)
 
    SCREENの構造の説明
 
    sl はポインタの配列である。ここにはデータの大本となる str 配列へのポインタが格納される。
    sl の配列サイズは screen_h である。これは改行に依存せずに、純粋に行数で考えた場合を扱うために用意してある。
 
    _bufは screen_w * screen_h の長さの配列である。
 
    rb はポインタの配列である。これは_bufを2次元配列として扱い易くするために、_bufの各行の先頭にあたるアドレスを保存する。
    これを用いて _buf にアクセスすれば計算量が減るし、扱いも簡単である。
 
    rl はROW_LINK型の配列である。サイズはscreen_h
    ROW_LINKの内容は to_line_link に rb の添え字番号、line_separete_index には行の分割番目を記録する。
     
    これらを用いての、一連の使用法の例を説明する。
    まず SCREEN に表示させたい文字列 str を用意する。この str の文字列長は、いくら長くてもよい。
 
    次に str を sl にリンクする。
    これは、SCREEN の仮想行(文字列がscreen_wを超えた場合の改行を考慮しない、純粋な行数)で考えた場合の、表示させたい行数である。
    たとえば、元のテキストの10行目を仮想行の1行目に表示させたいなら sl[0] である。3行目なら sl[2] という要領である。
    sl には「文字列を screen_w の幅に収めて、あまった分は改行して…」という概念が無い。純粋な『行』という概念で考えてよい。
 
    つぎに、slの指し示す内容を、 _buf に実際に書き込む。
    直接 _buf を操作すると煩雑になるので、_buf にリンクされた rb を用いる。
    rb に行を書き込む操作は、常に他の行への影響の可能性があるので、常に全体での一連の操作が必要になる。
    つまり、たとえば rb の10行目だけを書き換えることはできない。10行目だけで十分な場合でも rb[0] から screen_h 分の更新が必要である。
    まず最初に、rb[0] に sl[0] の内容を書き込むことから始まる。
    具体的には sl[0] の指し示す str の(長さ / screen_w)が x > 0 ならば複数行という意味であり、書き込みループ回数を表し、
    この rb[0] の( 書き込みループ回数 * screen_w )が、そのループ回での書き込みに用いる str の先頭アドレスであり、
    これらを用いて rb[0],rb[1],rb[2],,, と書き込んでいく。その際に用いたslのindexが、各行のto_line_linkであり、indexが link_separete_index である。
    この一連の処理によって sl[0] を _buf の(指定行〜必要行分)だけ書き込んだことになる。
     
    たとえば例として sl[0] にリンクされた str の文字列長が 200 文字、screen_w が 80 ならば、rb の内容は、
    rb[0] = sl[0] + 0-1   〜 sl[0] + 80-1
    rb[1] = sl[0] + 80-1  〜 sl[0] + 160-1
    rb[2] = sl[0] + 160-1 〜 sl[0] + 200-160-1
    となり、
    rl[0〜2].to_line_link = 0
    rl[0〜2].line_separate_index = 80, 80, 40
    となる。
 
    この要領で、rb[screen_h-1]まで処理を繰り返すことにより、_bufへの登録が完了する。
    以上。
 
    ROW_LINK について:
    なぜこれが用意されてるかというと、スクリーン位置と、文字列の仮想行上での位置の対応を、簡単に計算するためである。
    つまり、スクリーンカーソル位置を仮想行上での位置に簡単に変換するためである。また、その逆も。
 
*/
 
#ifndef _SCREEN_H_
#define _SCREEN_H_
 
#include <stdio.h>
#include "CURSOR_CONTROL.h"
 
#define DEF_SCREEN_W 132
#define DEF_SCREEN_H 43
 
typedef struct tagROW_LINK {
    int to_line_link;
    int line_separete_index;
} ROW_LINK;
 
typedef struct tagSCREEN {
    int screen_w;
    int screen_h;
     
    ROW_LINK* rl;    // 各行が、実際の行数の何行目に対応しているかのリンクを指す構造体の、配列
    char* _buf;        // w * h の長さの1次元配列
    char** rb;        // _bufの各行の先頭アドレスを指す、ポインタの配列。(いちいち h * screen_w + w しなくても簡単にアクセスできるように)
    char** sl;        // 大本の文字列strへのリンク
} SCREEN;
 
extern void initSCREEN( SCREEN* scr );
extern void resizeSCREEN( SCREEN* scr, int w, int h );
 
// 大本の行 sl の index に登録する。
// あくまでリンクにすぎない(実際の文字データのコピーは行われない。実際の_buf へのコピーは refresh_bufSCREEN()で行われる。)
// index が範囲外の場合は何もせずにリターンする。
extern void reg_strSCREEN( SCREEN* scr, int index, char* str );
 
// sl にリンクされた文字列の内容で _buf を更新する。
extern void refresh_bufSCREEN( SCREEN* scr );

// _bufの内容を画面に出力する
extern void printSCREEN( SCREEN* scr, CURSOR_CONTROL* cc );
 
#endif // _SCREEN_H_

SCREEN.c (0.0.1)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SCREEN.h"
#include "CURSOR_CONTROL.h"
 
extern void __link_buf2rbSCREEN( SCREEN* scr );
extern void __initSCREEN( SCREEN* scr );
 
// buf と rb を結びつける
void __link_buf2rbSCREEN( SCREEN* scr )
{
    int j;
    for ( j=0; j<scr->screen_h; j++ ) {
        scr->rb[j] = &scr->_buf[scr->screen_w * j];
    }
}

// 文字列バッファを初期値 ' ' で埋める
void __initSCREEN( SCREEN* scr )
{
    int i;
    for(i=0;i<scr->screen_h*scr->screen_w;i++){
        scr->_buf[i]=' ';
    }
}
 
void initSCREEN( SCREEN* scr )
{
    scr->screen_w = DEF_SCREEN_W;
    scr->screen_h = DEF_SCREEN_H;
 
    scr->_buf    = (char*)malloc( sizeof(char) * scr->screen_w * scr->screen_h );
    scr->rl        = (ROW_LINK*)malloc( sizeof(ROW_LINK) * scr->screen_h );
    scr->rb        = (char**)malloc( sizeof(char*) * scr->screen_h );
    scr->sl        = (char**)malloc( sizeof(char*) * scr->screen_h );

    __initSCREEN( scr );
    __link_buf2rbSCREEN( scr );
}
 
void resizeSCREEN( SCREEN* scr, int w, int h )
{
    scr->screen_w = w;
    scr->screen_h = h;
 
    scr->_buf    = (char*)realloc( scr->_buf, sizeof(char) * scr->screen_w * scr->screen_h );
    scr->rl        = (ROW_LINK*)realloc( scr->rl, sizeof(ROW_LINK) * scr->screen_h );      
    scr->rb        = (char**)realloc( scr->rb, sizeof(char*) * scr->screen_h ); 
    scr->sl        = (char**)realloc( scr->sl, sizeof(char*) * scr->screen_h );
 
    __initSCREEN( scr );
    __link_buf2rbSCREEN( scr );
}
 
// 大本の行 sl の index に登録する。
// あくまでリンクにすぎない(実際の文字データのコピーは行われない。実際の_buf へのコピーは refresh_bufSCREEN()で行われる。)
// index が範囲外の場合は何もせずにリターンする。
//
// 注!!:引数で渡すstrは、文字の最後に必ず ¥0 が付加されてること!!
void reg_strSCREEN( SCREEN* scr, int index, char* str )
{
    if( index >= scr->screen_h || index < 0 ) { return; }
 
    scr->sl[index] = str;
}
 
// sl にリンクされた文字列の内容で _buf を更新する。
void refresh_bufSCREEN( SCREEN* scr )
{
    int j,jj;
 
    int cur_sh;
    char* src = scr->sl[0];
    char* cur_src_line_top;
    int   cur_src_line_len;
 
    char* dst = scr->rb[0];
    char* cur_dst_line_top;
 
    cur_sh=0; // 現在のスクリーンの書き込み行 
 
    for(j=0;j<scr->screen_h;j++){    // 書き込み元の、最大書き込み可能行数の高さ分(スクリーンの高さと同じ)
        src = scr->sl[j];    // 書き込み元アドレスを sl から、現在の書き込み行番目を得る
//printf("sl=%s",src);
        cur_src_line_len = ((int)strlen(src))/scr->screen_w; // 現在の書き込み行の、スクリーン書き込み用の仮想行数。
//printf("cur_src_line_len=%d ",cur_src_line_len);
 
        for(jj=0; jj<=cur_src_line_len; jj++){    // 仮想行数分だけ繰り返す(cur_src_line_lenは1行の時は0なので < ではなく <= で結んでる)
            if (cur_sh >= scr->screen_h ) {
//printf("¥n単行複数行化ありcur_sh=%d¥n ",cur_sh );
                return;    // スクリーン書き込み行が、スクリーン高さに達したらリターンして終了
            } 
//printf("cur_sh=%d ",cur_sh);
            cur_src_line_top = &(src[scr->screen_w * jj]);    // 書き込み元の先頭アドレスを、仮想行の先頭に設定する(仮想行xスクリーン幅)
//printf("cur_src_line_top=%d ",(int)cur_src_line_top);
            cur_dst_line_top = scr->rb[cur_sh];        // 書き込み先の先頭アドレス。こちらは文字位置ではなく、行そのものの移動。この違いに注意。
//printf("scr->rb[cur_sh]=%d¥n ",(int)scr->rb[cur_sh]);
             
            if(jj <= cur_src_line_len){ // 仮想的に分割した行の最後でなければ
                int len = scr->screen_w;
                strncpy( cur_dst_line_top, cur_src_line_top, len ); //(int)strlen(cur_src_line_top) ); // 実際に文字列をコピー
                cur_dst_line_top[len]='¥0';
//printf( "%s¥n",cur_dst_line_top);
//printf(" screen_w = %d ; strlen = %d ",scr->screen_w, strlen(cur_dst_line_top) ); 
//printf("%d strcpy=%s¥n ",(int)cur_dst_line_top, cur_dst_line_top );
            }
            else { //最後ならば
                int len = (int)strlen(cur_src_line_top);
                strncpy( cur_dst_line_top, cur_src_line_top, len );
                cur_dst_line_top[len]='¥0';
//printf( "%s¥n",cur_dst_line_top);
            }
 
            cur_sh++; // 現在のスクリーンの書き込み位置を次に進める
 
        }
    }
//printf("¥ncur_sh=%d¥n ",cur_sh );
}

// _bufの内容を画面に出力する
void printSCREEN( SCREEN* scr, CURSOR_CONTROL* cc )
{
  //    clear_screen();

    int row,colum;
    for( row=0; row<scr->screen_h; row++ ) {
        for( colum=0; colum<scr->screen_w; colum++ ) {
           
            __setposCURSOR_CONTROL( colum, row );

            char c = scr->rb[row][colum];
            if(c=='¥0' || c=='¥n') {
                break;
            }
            else {
                putchar(c);
            }
        }
    }

    __setposCURSOR_CONTROL( cc->pos_x, cc->pos_y );
}





ETC_MATH メモ (0.0.6)
その他、雑多な関数。

int pow( int a, int inv )
ainv 、ただしinvは正のみ

int _dig( int a, int cardinal )
a の桁数を求める。 cardeinal には 10 と書けばいい。
aもcardinalも正のみ。

void itos( char* dst, int src )
整数型 src から 文字列型 dst への変換。
src は正の数字のみ。
dst の長さは不定。十分に長いサイズのバッファを与えること。

ETC_MATH.h (0.0.6)
#ifndef _ETC_MATH_H_
#define _ETC_MATH_H_
 
// a^inv
extern int pow(int a, int inv );
 
// 基数による桁数
extern int _dig(int a, int cardinal );
 
// 数値型から文字列型
extern void itos( char* dst, int src );
 
#endif // _ETC_MATH_H_
 

ETC_MATH.c (0.0.6)
#include <stdio.h>
#include <stdlib.h>
#include "ETC_MATH.h"
 
// a^inv
int pow(int a, int inv )
{
    int r=a;
 
    if(inv==0) r=1;
    if(inv==1) r=a;
 
    int i;
    for(i=2;i<=inv;i++){r*=a;}
 
    return(r);
}
 
// 基数による桁数
int _dig(int a, int cardinal )
{
    if( cardinal ==0 ){printf("err: dig() cardinal¥n");exit(1);}
 
    int count=0;
 
    while(a>0){
        count++;
        a/=cardinal;
        if( a <= 0 ) { break; }
    }
 
    return(count);
}
 
// 数値型から文字列型
void itos( char* dst, int src )
{
    if(src > 0){
        int p;
        int unit;
        int sub=0;
        int dig=_dig(src,10);
        int i;
        for(i=0;i<dig;i++){
            p=pow(10,i+1);
            sub+=((src%p)-sub);
            unit=sub / pow(10, i);
 
            switch(unit){
                case 0:dst[dig-1-i]='0';break;
                case 1:dst[dig-1-i]='1';break;
                case 2:dst[dig-1-i]='2';break;
                case 3:dst[dig-1-i]='3';break;
                case 4:dst[dig-1-i]='4';break;
                case 5:dst[dig-1-i]='5';break;
                case 6:dst[dig-1-i]='6';break;
                case 7:dst[dig-1-i]='7';break;
                case 8:dst[dig-1-i]='8';break;
                case 9:dst[dig-1-i]='9';break;
                default:printf("err: itos() dst[%d]¥n",dig-1-i ); exit(1); break;
            }
        }
        dst[dig]='¥0';
    }
    else {
        dst[0]='0';
        dst[1]='¥0';
    }
}
 






CURSOR_CONTROL(0.0.6) メモ
windows の getch() に相当する、get_key() を用意しようと思った。
つまり、いちいちエンターを押さなくても、キーを押した瞬間に読み取ってくれるような関数。

windowsとlinuxでは、初期設定の手続きが違うからマクロで書きわけてます。
visual c++ だと、コンパイル時に普通は標準だと自動的に #define WIN32 が付加されるので、それを頼りに #ifdef WIN32 (←WIN32 が定義されてたら?という分岐)で処理を分岐させてます。

linuxだと、プログラムの終了時に、設定の復帰処理を行わないといけないので、main() の最後に必ず endCURSOR_CONTROL(void) を書くように。 windowsでコンパイルした場合、単純にこの関数は空になります。

初期設定は、得に意識して行う必要はありません。 CURSOR_CONTROL型の変数を初期化する関数 initCURSOR_CONTROL() を実行すると、(呼び出しがプログラム中の最初の一回目なら)自動的に初期化が行われます。
CURSOR_CONTROL 型の変数はいくらでも作れますが、initCURSOR_CONTROL() を実行した際に、初期設定を行うのは、プログラム中全体での最初の1個目の初期化時だけです。

    
CURSOR_CONTROL型

初期化
initCURSOR_CONTROL()で初期化 
  
すでに以前に、
他のCURSOR_CONTROL型の
初期化を行ったことがある? 
 
  ↓ まだない。初 ( flg_init_termios == 0 ) 
  termios の初期設定を行う
flg_init_termios フラグを1に
 


void setposCURSOR_CONTROL( CURSOR_CONTROL* cc, int pos_x, int ppos_y )
void __setposCURSOR_CONTROL(  int pos_x, int ppos_y )

どちらもカーソルの位置をセットする関数。
この位置に、カーソルが移動する。(文字の描画位置)
__が付いた方は、現在位置を cc に保存する必要が無い場合などに使う。
通常版( setposCURSOR() )だと、実行毎に cc に現在位置が保存される。(あと細かな範囲補正と)

setposCURSOR_CONTROL()__setposCURSOR_CONTROL()
指定位置へとカーソルを移動する

screenのサイズと比較し、指定位置がscreen範囲を飛び出してる場合は補正する。
その後、内部的に __setposCURSOR_CONTROL()を呼び出す。
指定位置へとカーソルを移動する





CURSOR_CONTROL.h (0.0.6)
#ifndef _CURSOR_CONTROL_H_
#define _CURSOR_CONTROL_H_

#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <termios.h>
#include <sys/time.h>
#endif // WIN32

#ifdef WIN32
#else
extern struct termios save_term;
extern struct termios temp_term;
#endif // WIN32
 
typedef struct tagCOUSOR_CONTROL {
    int pos_x;    // カーソルの現在位置
    int pos_y;
     
    int scr_w;    // スクリーンの幅・高さ
    int scr_h;
} CURSOR_CONTROL;
 
extern void initCURSOR_CONTROL( CURSOR_CONTROL* cc );        // CURSOR_CONTROLのシステムの初期化も兼ねる。最初に必ず一回以上実行すること
extern void endCURSOR_CONTROL( void );                    // CURSOR_CONTROLのシステムの終了処理。mainの最後で必ず一回実効すること。
 
// 単純にカーソル位置を移動するのみ。内部処理的にプリント位置を調整する目的の時はこちら
extern void __setposCURSOR_CONTROL( int x, int y );
 
// cc にカーソル位置情報を保存しつつ移動する。通常のカーソル移動はこちら
extern void setposCURSOR_CONTROL( CURSOR_CONTROL* cc, int x, int y );

// カーソルを1マス移動する(画面の外周外に出た場合は、外周位置に留まる)
extern void move_rightCURSOR_CONTROL( CURSOR_CONTROL* cc );
extern void move_leftCURSOR_CONTROL( CURSOR_CONTROL* cc );
extern void move_upCURSOR_CONTROL( CURSOR_CONTROL* cc );
extern void move_downCURSOR_CONTROL( CURSOR_CONTROL* cc );

// キー入力を得る
extern char get_key(void);

// 画面をクリアーする
extern void clear_screen(void);
 
#endif // _CURSOR_CONTROL_H_

CURSOR_CONTROL.c (0.0.6)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SCREEN.h"
#include "ETC_MATH.h"
#include "CURSOR_CONTROL.h"
 
#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <termios.h>
#include <sys/time.h>
#endif // WIN32
 
#ifdef WIN32
HANDLE hConsole;
static int flg_init_hConsole = 0;
#else
struct termios save_term;
struct termios temp_term;
static int flg_init_termios = 0;
#endif // WIN32

 
void initCURSOR_CONTROL( CURSOR_CONTROL* cc )
{     
    cc->pos_x = 0;
    cc->pos_y = 0;
    cc->scr_w = DEF_SCREEN_W;
    cc->scr_h = DEF_SCREEN_H;

#ifdef WIN32
    if( flg_init_hConsore == 0 ) {
        hConsole = GetStdHandle( STD_OUTPUT_HANDLE );
        flg_init_hConsore = 1;
    }
#else
    if( flg_init_termios == 0 ) {
          tcgetattr(fileno(stdin), &save_term);
          temp_term = save_term;
          temp_term.c_iflag &= IGNCR;
          temp_term.c_lflag &= ~ICANON;
          temp_term.c_lflag &= ~ECHO;
          temp_term.c_lflag &= ~ISIG;
          temp_term.c_cc[VMIN]=1;
          temp_term.c_cc[VTIME]=0;
          tcsetattr(fileno(stdin), TCSANOW, &temp_term);
        flg_init_termios = 1;
    }
#endif //WIN32
}

void endCURSOR_CONTROL(void)
{
#ifdef WIN32
    if( flg_init_hConsore == 1 ) {
        flg_init_hConsore = 0;
    }
#else
    if( flg_init_termios == 1 ) {
        tcsetattr(fileno(stdin), TCSANOW, &save_term );
        flg_init_termios = 0;
    }
#endif //WIN32
}
 
void setposCURSOR_CONTROL( CURSOR_CONTROL* cc, int x, int y )
{
    cc->pos_x = (x<0)?0:x;
    cc->pos_y = (y<0)?0:y;
 
    if(cc->pos_x >= cc->scr_w){cc->pos_x = cc->scr_w-1;}
    if(cc->pos_y >= cc->scr_h){cc->pos_y = cc->scr_h-1;}
 
    __setposCURSOR_CONTROL( cc->pos_x, cc->pos_y );
}

void clear_screen(void)
{
#ifdef WIN32
#else
  printf("%c[2J",0x1B );
#endif // WIN32
}

char get_key(void)
{
#ifdef WIN32
    return( (char)getch() );
#else
    return( getchar() );
#endif // WIN32
}





// カーソルを1マス移動する(画面の外周外に出た場合は、外周位置に留まる)
void move_rightCURSOR_CONTROL( CURSOR_CONTROL* cc )
{
    cc->pos_x++;
    if ( cc->pos_x >= cc->scr_w ) cc->pos_x = cc->scr_w - 1;

    setposCURSOR_CONTROL( cc, cc->pos_x, cc->pos_y );   
}

void move_leftCURSOR_CONTROL( CURSOR_CONTROL* cc )
{
    cc->pos_x--;
    if ( cc->pos_x < 0 ) cc->pos_x = 0;

    setposCURSOR_CONTROL( cc, cc->pos_x, cc->pos_y );   
}

void move_upCURSOR_CONTROL( CURSOR_CONTROL* cc )
{
    cc->pos_y++;
    if ( cc->pos_y >= cc->scr_h ) cc->pos_y = cc->scr_h - 1;

    setposCURSOR_CONTROL( cc, cc->pos_x, cc->pos_y );   
}

void move_downCURSOR_CONTROL( CURSOR_CONTROL* cc )
{
    cc->pos_y--;
    if ( cc->pos_y < 0 ) cc->pos_y = 0;

    setposCURSOR_CONTROL( cc, cc->pos_x, cc->pos_y );   
}





#ifdef WIN32
void __setposCURSOR_CONTROL( int x, int y )
{
    COORD Pos;
    Pos.X = x;
    Pos.Y = y;
 
    SetConsoleCursorPosition(hConsole, Pos); 
}
#endif // WIN32
 
#ifndef WIN32
void __setposCURSOR_CONTROL( int x, int y )
{
    x+=1;
    y+=1;   
 
    char str_x[0x0F];
    char str_y[0x0F];
    itos( str_x, x );
    itos( str_y, y );
//printf("str_x=%s, str_y=%s\n",str_x, str_y );
    int str_x_len = (int)strlen(str_x);
    int str_y_len = (int)strlen(str_y);
 
    char command[0x1F];
 
    command[0]=0x1b;
    command[1]='[';
     
    int i;
    char* cp;
    cp = &command[2];
    for(i=0;i<str_y_len;i++){ *cp=str_y[i]; cp++; }
 
    command[2 + str_y_len] =';';
 
    cp = &command[2+str_y_len+1];
    for(i=0;i<str_x_len;i++){ *cp=str_x[i]; cp++; }
 
    command[2 + str_y_len + 1 + str_x_len + 0] ='H';
    command[2 + str_y_len + 1 + str_x_len + 1] ='\0';
 
//    puts(command);
    for(i=0; i<2 + str_y_len + 1 + str_x_len + 2; i++){
        putchar(command[i]);//putchar(' ');
    }
//
//    printf("%c[%d;%df",0x1b,x,y);
}
#endif // WIN32
 

CHAR(0.0.6) メモ
CHAR に、putchar に相当する関数を用意しようと思った。

int printCHAR( CHAR* ch, CURSOR_CONTROL* cc )
引数は CHAR と カーソルのコントローラー
このカーソル位置に、CHAR の文字を出力する。
ASCII の場合は半角、その他の場合は全角。
(半角カナは考慮してません。←そのうち追加します。)

戻り値は、画面の表示ブロックの消費量。ASCIIなら1、全角なら2。

CHAR.h (0.0.6)
#ifndef _CHAR_H_
#define _CHAR_H_

#include "CURSOR_CONTROL.h"

typedef struct tagCHAR {
    unsigned char c[4];
    int mode;
} CHAR;

// char[4] を読み込み UTF-8 に変換して格納する。
// リターンは使用してるバイト数。判別不能の時は0を返す。
extern int writeCHAR( CHAR* dst, unsigned char* src );

// char[4] に UTF-8 の先頭バイトから順に格納する。
// ただし、使用されるバイト数は、モードの必要分”だけ”であり、
// それ以降のバイトには一切触れない(値を変えない・アクセスすらしない)
// 戻り値には、使用しているバイト数が返される。0の場合はほぼエラーを意味する。
extern int readCHAR( CHAR* src, unsigned char* dst );

// 指定したカーソル位置に一文字表示する
// 戻り値は、文字の表示に使用したブロック数。ASCII(半角文字)の場合は1ブロック、非ASCII(全角文字)の場合は2ブロック
// カーソル位置は、表示後も変わらない。(自動では進まない)
extern int printCHAR( CHAR* ch, CURSOR_CONTROL* cc );

#endif // _CHAR_H_


CHAR.c (0.0.6)
#include <stdio.h>
#include "CHAR.h"
#include "CURSOR_CONTROL.h"

// char[4] を読み込み UTF-8 に変換して格納する。
// リターンは使用してるバイト数。判別不能の時は0を返す。
int writeCHAR( CHAR* dst, unsigned char* src )
{
    dst->mode = 0;

    unsigned char c0 = src[0];
    unsigned char c1;
    unsigned char c2;
    unsigned char c3;

    // 先頭bitが1ならマルチバイト文字、0ならASCII文字
    if( ( c0 & 0x80 ) == 0 ) {
        dst->c[0] = c0;
        dst->c[1] = 0;
        dst->c[2] = 0;
        dst->c[3] = 0;
        dst->mode = 1;
    }
    else {
        // 第2bitが0なら先頭以外の文字、1なら先頭文字
        if ( ( c0 & 0x40 ) == 0 ) {
        }
        else {
            dst->c[0] = c0;

            // 第3bitが0なら2バイト文字、1なら3バイト以上の文字
            if ( ( c0 & 0x20 ) == 0 )  {
                dst->c[1] = src[1];
                dst->mode = 2;

                dst->c[2] = 0;
                dst->c[3] = 0;
            }
            else {
                // ...かつ、第4bitが0なら3バイト文字、1なら4バイト文字
                if ( ( c0 & 0x10 ) == 0 )  {
                    dst->c[1] = src[1];
                    dst->c[2] = src[2];
                    dst->mode = 3;

                    dst->c[3] = 0;
                }
                else {
                    dst->c[1] = src[1];
                    dst->c[2] = src[2];
                    dst->c[3] = src[3];
                    dst->mode = 4;
                }
            }
        }
    }

    return( dst->mode );
}

// char[4] に UTF-8 の先頭バイトから順に格納する。
// ただし、使用されるバイト数は、モードの必要分”だけ”であり、
// それ以降のバイトには一切触れない(値を変えない・アクセスすらしない)
// 戻り値には、使用しているバイト数が返される。0の場合はほぼエラーを意味する。
int readCHAR( CHAR* src, unsigned char* dst )
{
    switch(src->mode){
    case 1:
        dst[0] = src->c[0];
        return(1);
    case 2:
        dst[0] = src->c[0];
        dst[1] = src->c[1];
        return(2);
    case 3:
        dst[0] = src->c[0];
        dst[1] = src->c[1];
        dst[2] = src->c[2];
        return(3);
    case 4:
        dst[0] = src->c[0];
        dst[1] = src->c[1];
        dst[2] = src->c[2];
        dst[3] = src->c[3];
        return(4);
    default:
        return(0);
    }
}

// 指定したカーソル位置に一文字表示する
// 戻り値は、文字の表示に使用したブロック数。ASCII(半角文字)の場合は1ブロック、非ASCII(全角文字)の場合は2ブロック
// カーソル位置は、表示後も変わらない。(自動では進まない)
int printCHAR( CHAR* ch, CURSOR_CONTROL* cc )
{
    unsigned char c[4];
    readCHAR( ch, c );
    int step;
    int i;


    __setposCURSOR_CONTROL( cc->pos_x, cc->pos_y);    // カーソル位置をセット
    for( i=0; i < ch->mode; i++ ) {
        putchar( c[i] );
    }
    __setposCURSOR_CONTROL( cc->pos_x, cc->pos_y );    // putchar() の実行で変わったであろうカーソル位置を、元にもどす(自動での移動はさせない)


    switch(ch->mode){
    case 0: step = 0; break;
    case 1: step = 1; break;    // ASCII 半角文字なら
    case 2: step = 2; break;    // 非ASCIIは全て全角文字として扱う。(半角カナなどは考慮しない)
    case 3: step = 2; break;
    case 4: step = 2; break;
    default: step = 0; break;
    }

    return( step );   
}






CHAR メモ
「そもそも char型とは何か?」
という、疑問。
本来の char の意味を考えたら、char を補完する新たな CHAR 型の必要性を感じた。そしてそれを基本型として組むべきではないのか?と。



もともと、C の char型とは、『キャラクタ型』という意味。 つまり、1つで1文字を表せる。そういう変数。

変数とは、中に数をメモしとくための箱。 そもそも、なぜ変数で文字を表せるのか?
実際のところ、char 自体に文字画像が入ってるワケじゃなくて、char に記録された数字は、あれは、単なる文字一覧表の中での、文字に対応した番号にすぎない。

ASCIIコード対応表
 01234567
0NULDLESP0@P`p
1SOHDC1!1AQaq
2STXDC2"2BRbr
3ETXDC3#3CScs
4EOTDC4$4DTdt
5ENQNAK%5EUeu
6ACKSYN&6FVfv
7BELETB'7GWgw
8BSCAN(8HXhx
9HTEM)9IYiy
10LFSUB*:JZjz
11VTESC+;K[k{
12FFFS,<L\l|
13CRGS-=M]m}
14SORS.>N^n~
15SIUS/?O_oDEL

この表の文字の数は、全部で合計は 16 * 8 で 128個。
つまり0〜127までの数字を表せる入れ物なら、十分。
HSB LSB
  


この箱の1つ1つが、それぞれ、0か1かのどちらかを記録できる。
この箱1つのことを1ビットと呼ぶ。
で、この箱を8個まとめたものが1バイト。
1メガバイトってのは、この棒が100万本使える状態。1ギガバイトってのは10億本使える状態。

この棒の、箱1つ1つは、0か1のどちらかしか記録できない。だから、箱1つに3とか5みたいな数字は記録できない。
数字は、この棒に2進数で記録する。
10進数だと、0、1、2、3、、、8、9 と来て、繰り上がって10になる。 で、11、12、13、、、と続いてく。
この10で繰り上がるってのが、2進数の場合2で繰り上がる。
つまり、0、1 と来たら、繰り上がって 10 となる。 で、11 で、また繰り上がって 100で、101、
また繰り上がって 110、で111、また繰り上がって 1000、で1001、また繰り上がって1010、で1011、でまた繰り上がって 1100、で1101、でまた繰り上がって1110、で1111。

わかりやすくイメージ描くと、こんな感じ
 1514131211109876543210
LSB1010101010101010
 1100110011001100
 1111000011110000
HSB1111111100000000
LSB ってのは、一番下の桁って意味。 たとえば十進数で例えると 1234 の 4。 一の位 がLSB。
HSBってのは、一番上の桁って意味。 たとえば十進数で例えると 1234 の1。 千の位がHSB。

上の例だと4つの箱、つまり4ビットによる数です。4ビットだと0〜15までの数字を表せる。

この0〜15までを、一の位として扱えるのが16進数。 これは0〜9、そしてA、B、C、D、E、Fと続く。
Aは10という意味、Bは11という意味、Cは12という意味、Dは13という意味、Eは14、Fは15。
プログラムで書くときは頭に接頭詞で0xって書く。 0x0F と書いたら、これは 00001111 であり、15である。

話を char に戻すと、
char ってのは要するに ASCII コードの対応表を保存するに十分なサイズ。っていう目的の数で、
だから 8bit という大きさに決められたんだと思う。 (8bitは0〜255までの数字をあらわせる)

だから昔は 『char 型 = 文字を表せる』 の図式が成立してたんだろうけど、それは ASCII コードしか使わない国の人たちだけの話。
一方、日本だとひらがな、カタカナ、そして漢字があるからこまる。なにせ漢字は種類が多い。 とてもじゃないが 0 〜 255の範囲になんて収まらない。
日本語を表すための表として shift-jis を用意したものの、char の1バイトでは足りなかったのである。
だから、w_char 型なんてのを使ったりしてた。このw_charってのは、ようするにchar[2]と同じで、2バイトのサイズである。
2バイトあれば、2の16乗個まで表せる。つまり大体64キロ。6万4千くらい。厳密には65536種類。
もちろん、LSB側の7bitはASCIIと互換で、同じコード変換表になっているので、その兼ね合いで、実際には64000種類も対応は書けないのだけど、それでも char よりは、全然多くの文字を『指し示せる』

最近だと UTF-8というエンコードをよくみかける。
これはユニコードというコード体系の一種で、いわく「地球上の全ての言語の文字を表す」っていう理念のもとに作りはじめられた対応表。
さすがに、すべての言語っていうと、使用するバイト数も多そうなもんだけど、当初は2バイトでこと足りると思ってたらしい。
…西洋人の感覚だと 「せいぜい2、3万種類くらいじゃね? 地球上の文字って」って感覚だったのだろう…
で、とうぜん「あれ?っていうか足りなくね?」となり、結局一文字を3バイトというルールに変更し、その後、結局4バイトになった。
一文字4バイトだと、ASCII文字でこと足りてたラテン文字文化圏の人たちはたまらない。1バイトで記録できるものを、わざわざ4バイト。
これではこまるので、UTF-8は、使用するバイト数が可変長になっている。文字の種類によって、使用するバイト数が変わる。
これが、妙なとっつきにくさの原因なのだろうけど、実際、その判別方法は全然簡単である。フラグを見てくだけ。
UTF-8でも、先頭1バイトの7bit分は、ASCIIコードとまったく同じである。ASCIIは0〜127の数字を文字の対応表に使用してた。つまりHSBの 1bit が余ってる状態。これをフラグにして判断していくだけ。

具体的にはこんな感じ。ぜんぜん簡単である。なにも難しいことなんて無い。

<UTF-8の読み方>
先頭バイトの
HSB側から1ビット目が
0なら1バイト文字(ASCII文字)、
1ならマルチバイト文字

0だった
1バイト文字
(ASCII文字)

↓ 1だった

  
先頭バイトの
HSB側から2ビット目が
1なら、先頭以外のバイト
0なら、このバイトが、マルチバイト文字の先頭バイト

1だった
なんだか
よくわかんねぇ
状態

↓ 0だった

  
先頭バイトの
HSB側から3ビット目が
0なら、このバイトと、次のバイトによる2バイト文字
1なら、3バイト以上の文字

0だった
2バイト文字

↓ 1だった

  
先頭バイトの
HSB側から4ビット目が
0なら、このバイトと、次のバイトと、次々のバイトの3バイト文字
1なら、このバイトから、次々々バイトまでの4バイト文字

0だった
3バイト文字

↓ 1だった

  

4バイト文字

  
   

で、本題のもどると、
基本型を char じゃなくて、このUTF-8型に決め打ちした CHAR 型にして作り直した方が良いような気がした。
…ので、CHAR 型を作ることにしました。

CHAR.h (0.0.5)
#ifndef _CHAR_H_
#define _CHAR_H_

typedef struct tagCHAR {
    unsigned char c[4];
    int mode;
} CHAR;

// char[4] を読み込み UTF-8 に変換して格納する。
// リターンは使用してるバイト数。判別不能の時は0を返す。
extern int writeCHAR( CHAR* dst, unsigned char* src );

// char[4] に UTF-8 の先頭バイトから順に格納する。
// ただし、使用されるバイト数は、モードの必要分”だけ”であり、
// それ以降のバイトには一切触れない(値を変えない・アクセスすらしない)
// 戻り値には、使用しているバイト数が返される。0の場合はほぼエラーを意味する。
extern int readCHAR( CHAR* src, unsigned char* dst );

#endif // _CHAR_H_

CHAR.cpp (0.0.5)
#include <stdio.h>
#include "CHAR.h"

// char[4] を読み込み UTF-8 に変換して格納する。
// リターンは使用してるバイト数。判別不能の時は0を返す。
int writeCHAR( CHAR* dst, unsigned char* src )
{
    dst->mode = 0;

    unsigned char c0 = src[0];
    unsigned char c1;
    unsigned char c2;
    unsigned char c3;

    // 先頭bitが1ならマルチバイト文字、0ならASCII文字
    if( ( c0 & 0x80 ) == 0 ) {
        dst->c[0] = c0;
        dst->c[1] = 0;
        dst->c[2] = 0;
        dst->c[3] = 0;
        dst->mode = 1;
    }
    else {
        // 第2bitが0なら先頭以外の文字、1なら先頭文字
        if ( ( c0 & 0x40 ) == 0 ) {
        }
        else {
            dst->c[0] = c0;

            // 第3bitが0なら2バイト文字、1なら3バイト以上の文字
            if ( ( c0 & 0x20 ) == 0 )  {
                dst->c[1] = src[1];
                dst->mode = 2;

                dst->c[2] = 0;
                dst->c[3] = 0;
            }
            else {
                // ...かつ、第4bitが0なら3バイト文字、1なら4バイト文字
                if ( ( c0 & 0x10 ) == 0 )  {
                    dst->c[1] = src[1];
                    dst->c[2] = src[2];
                    dst->mode = 3;

                    dst->c[3] = 0;
                }
                else {
                    dst->c[1] = src[1];
                    dst->c[2] = src[2];
                    dst->c[3] = src[3];
                    dst->mode = 4;
                }
            }
        }
    }

    return( dst->mode );
}

// char[4] に UTF-8 の先頭バイトから順に格納する。
// ただし、使用されるバイト数は、モードの必要分”だけ”であり、
// それ以降のバイトには一切触れない(値を変えない・アクセスすらしない)
// 戻り値には、使用しているバイト数が返される。0の場合はほぼエラーを意味する。
int readCHAR( CHAR* src, unsigned char* dst )
{
    switch(src->mode){
    case 1:
        dst[0] = src->c[0];
        return(1);
    case 2:
        dst[0] = src->c[0];
        dst[1] = src->c[1];
        return(2);
    case 3:
        dst[0] = src->c[0];
        dst[1] = src->c[1];
        dst[2] = src->c[2];
        return(3);
    case 4:
        dst[0] = src->c[0];
        dst[1] = src->c[1];
        dst[2] = src->c[2];
        dst[3] = src->c[3];
        return(4);
    default:
        return(0);
    }
}

STRING メモ
char* 型での文字列操作だと、なんとなく微妙な部分で「どっちだっけか?」ってなったりしてややこしいので、STRING型として操作をまとめてしまおうと思った。

STRING は文字列を一行格納するためのもの。
STRINGに対しての行える操作は
  • 1文字書き込む : write_charSTRING()
  • 1文字読み込む : read_charSTRING()
  • 1行書き込む : write_strSTRING()
  • 1行読み込む : read_strSTRING()
のみ。(あと、おまけで ・STRING を書き込む : write_stringSTRING がある)


write_char は STRING の x 文字目に1文字書き込むが、
この際の x が STRING長より長かった場合は、以下のような処理になる。
         
         
01234............x
STRING長 = 5



01234............x
string長 = x + 1
*には文字としてスペースが書き込まれる

このように不足分の領域が自動的に再確保され、
STRING の最大長が伸ばされる。(メモリの再確保が行われる)
その際、新たに確保した分のスキマはスペース(空白文字)で埋められる。

書き込んだ1文字以外の文字列は、全て保持される。(破壊されない)



write_string は、単純に char* 型による文字列を STRING にコピーするだけ。
その際に、書き込み位置は選べない。書き込み位置は常に先頭0番目から。
書き込み文字列は、char* と、その length で表現する。
STRING長よりも length が長い場合は、STRING長が伸ばされる(新たにメモリが確保される)

注:STRING.c には、文字列の最後に ¥0 をとくに書き込むような『気の使い方』は一切していないので、
直接読み取りをする場合は、そこを意識して注意するように。
具体的には strlen が望みどうりの値を返さないケースが起きたりする。

(なるべく read_ 系の関数を介して読み取る方がいい。その方が簡単だし安全)

これは実際、どう組むべきか迷ってます。
へたに生データでの ¥0 を保証しちゃうと、関数を介さないでアクセスするクセがついてしまうのが怖い。
¥0 が保証されないのであれば、面倒だし、関数を介するだろう…と。
もしも関数を介さずにアクセスした際に、len を無視して文字列を伸ばしたり縮めたりされると、read_、write_ともに、関数の動作に支障がでてくる。

とにかく、STRING の生データには直接触らないっていう方針で使ってれば問題無い。 
常に関数を介するように。
生データに直接書き込みするのは、なるべく避けるように。



read_char は、STRING の任意の位置から1文字読み込む。
戻り値として char
位置が 0 より小さい(マイナス)場合は0、位置がSTRING長以上の場合は STRING長 - 1 の位置から読み込む。

         
         
01234............x
STRING長 = 5



         
         
01234............x
STRING長 = 5



read_str は STRING から char* に文字列を読み込みます。
読み込みは常に先頭0文字目からです。
読み込む文字列長は STRING の len 依存です。
つまり、char* には十分なメモリ領域を確保しとく必要があります。
(汎用的に使うバッファ変数を用いて読み込むケースがほとんどでしょうから、いっそのこと1メガくらい確保しといても良いかもしれません。最近のPCはメモリが有り余ってますし。)

あと、この関数で読み込んだ文字列には、文字列の最後に必ず \0 が付加されます。(\0 保証)
つまり、この関数を介してで読み込んだ文字列なら、 strlen() が必ず動作します。(正常に動作します)

注意: char* のメモリが STRING長に満たない場合の動作は不定です。 とにかく char* には十分すぎるメモリを確保しといてください。

read_str ボツ案1:
必要に応じて read_str 関数内部で malloc して、ポインタをリターンする方法なら、メモリを動的に確保できるので、メモリ領域の問題は解決するのですが、その方法だと、結果的に read_str が一種の malloc として動作するのと同じ意味です。
これだと、malloc に関わる free の問題があらわれてしまいます。
常にシステムでほとんど最初から最後まで存在し続けることを望まれるメモリならば、とくに開放に神経質になる必要はそれほどありませんが、read_str の場合、おそらく、読み込んだ文字列の用途は一時バッファ的な使い方がほぼ大部分のケースだと予想されます。
この手のメモリーってのは、どんどん無駄に溜まるので、使用後の開放が必須ですが、手動の開放作業ってのは、往々にしてを忘れてしまうことが多い。
なぜなら、開放してもしなくても、これといってエラーが発生するワケでもないし、コンパイルも当然通る。
そこが怖い。(この手のエラーは、ものすごく見付けづらい、直しづらい)
だから、read_str を malloc の一種として実装する案はボツにしました。

read_str ボツ案2:
STRING のプログラムブロックに、大域変数として char* 型の string_buf を用意する。
これをヘッダファイルで外部に公開して使えるようにする。
read_str は。この string_buf へとリード結果を書き込む。
そして、ユーザーは string_buf を読めば、常に、直近に実行した read_str の結果を得ることができる。
この方法だと、read_str というユニークなバッファを用意することで、両方の問題を解決できる。
現在案の、『メモリーを余分に確保しとかなくてはならない』という問題。
また、ボツ案1の、ゴミメモリー領域を、うっかり発生させてしまいかねない、という問題。
どちらも解決できる。
string_buf は、read_str関数が。完全に把握してコントロールすることができるバッファ。
だから動的にメモリーを確保してやれば、読み込みの問題は解決する。 うっかり忘れのゴミメモリ問題も無い。
でもこれは、デメリットとして、大域変数の問題があるのでボツにした。
つまり、関数内で完結させたい処理であっても、それが不可能である。というコーディング上の不安定要素が入り込んでしまう恐れがあるからボツ。
つまり、関数Aで使った結果が、関数Bで読むときにも影響する。 忘れたままBで『期待値』を頼りに string_buf を読むと、まったくおかしな値が入ってた…というケースが必ず起こりうる。
これを防止するためには、read_str 関数と、その結果の string_buf に対して行う作業を、必ずペアにして、それらの処理の間に、さらに再帰的に read_str 関数を使うなどの処理を挟み込まない。
この、『read_str と string_buf は、ペアで直後に使用すること』という制約が、意外とキツい。なぜなら再帰、もしくは再帰的なループ系の処理が、のきなみ、ほぼ全てアウトだから。再帰を書くためには、それなりのトリックなり用意が必要になってくる。
こういう複雑性を持ち込むのは、本末転倒だと思う。(元々、プログラムを簡単にするために STRING を用意してるのだからw)
なので、この大域変数でバッファを用意する案もボツにしました。

結局、現在の、『無駄に大きめのバッファを用意して使ってね』 というパラダイムが一番マシな気がしたので、これを採用してます。
これが一番、『妙な作法的なもの』を意識せずに使えて、簡単だと思ったからです。
…もっと良い方法があれば、それに書き換えるつもりですが、ボツ案1が本当は理想なんですが、これを安全に実装するには、やはりガベージコレクションが保証されてる言語じゃないと不安です…
(Cでボツ案1を組むと、いわば手動ガベージコレクションを人間に要求することと同じ意味。 でも、人間は間違えるし、うっかり忘れもする。)



STRING.h (0.0.5)
#ifndef _STRING_H_
#define _STRING_H_

typedef struct tagSTRING {
    char*    c;
    int        len;
} STRING;

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "STRING.h"

// 初期化
// インスタンスの作成直後に必ず最初にこの関数を通して初期化する必要がある。
extern void initSTRING( STRING* str );

// char 型の文字列を len 文字分、STRINGに書き込む。この際、古いデータは破壊され、上書きによって置き換わる。(つまり感覚としては char -> STRINGへのコピーに近い)
// STRING のメモリーが足りない場合は自動的に確保される
extern void write_strSTRING( STRING* dst, char* src, int len );

// char 1文字を dst の index 番目に書き込む。
// STRING のメモリーが足りない場合は自動的に確保される。確保された分はスペースで初期化される。
extern void write_charSTRING( STRING* dst, int index, char c );

// src の文字列を dst に書き込む。
// STRING のメモリーが足りない場合は自動的に確保される
extern void write_stringSTRING( STRING* dst, STRING* src );

// char 1文字を src の index 番めから読み込む。
// index が 0 以下の場合は 0 として読み込まれる。 index が STRING長 - 1 以上の場合、STRING長 - 1 として読み込まれる
extern char read_charSTRING( STRING* src, int index );

// char 型の文字列 dst へ、STRING型 src から全文字を読み込む。 読み込んだ文字列の最後には必ず '¥0' が付加される。
//
// 注意:dst は十分すぎるほど十分な長さを確保しておくように。
//(Cにはガベージコレクションが無いので、使いやすくするために、あえて固定長配列の dst を引数にしてます。
//  開放忘れによるメモリの行方不明を防ぐため、char* を返す関数として内部で malloc するような作りにはあえてしてません。
// だからdstは十分な長さを確保して渡してください。
// 0xFFFFFF (16メガw)くらいあれば、まぁ、絶対大丈夫だと思います。(一行の長さが1600万文字のテキストファイルなんて、めったに存在しませんもんね...super_piの出力くらい?)
// 0xFFFF (64キロ)くらいでも、実用、十分かと思いますが。(一行の長さが6万4千文字のテキストファイル… まぁこれでも十分ですよね… 普通、一行は100文字程度でしょうし。)
extern void read_strSTRING( STRING* src, char* dst );

#endif // _STRING_H_

STRING.cpp (0.0.5)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "STRING.h"

// 初期化
// インスタンスの作成直後に必ず最初にこの関数を通して初期化する必要がある。
void initSTRING( STRING* str )
{
    str->c = (char*)malloc(sizeof(char));
    str->len = 0;
}

// char 型の文字列を len 文字分、STRINGに書き込む。この際、古いデータは破壊され、上書きによって置き換わる。(つまり感覚としては char -> STRINGへのコピーに近い)
// STRING のメモリーが足りない場合は自動的に確保される
void write_strSTRING( STRING* dst, char* src, int len )
{
    if( len <= 0 ) { len = 0; }    // len の範囲丸め

    // メモリが足りなかったら確保する
    if( dst->len < len ) {
        dst->len = len;

        free( (void*)(dst->c) );
        dst->c = (char*)malloc( sizeof(char) * dst->len );
    }

    int i;
    char* d = dst->c;
    char* s = src;
    for(i=0;i<len;i++){ *d++ = *s++; }
    dst->len = len;
}

// char 1文字を dst の index 番目に書き込む。
// STRING のメモリーが足りない場合は自動的に確保される。確保された分はスペースで初期化される。
void write_charSTRING( STRING* dst, int index, char c )
{
    if( index <= 0 ) { index = 0; }    // index の範囲丸め

    // メモリが足りなかったら確保する
    // index の場合は、たとえば len が10の配列では、実際に使用できるindexの最大値は9までなので、( dst->len - 1 ) と比較している
    if( dst->len - 1 < index ) {
        int old_len = dst->len;
        dst->len = index + 1;    // len を index の値とした配列だと、index - 1 番目までしか書き込めないので、それだと1足りないので ( index + 1 ) としている。

        dst->c = (char*)realloc( dst->c, sizeof(char) * dst->len );

        int i;
        char* d = dst->c;
        for(i=old_len; i<dst->len; i++ ) {
            *d++ = ' ';    // 新規確保したメモリーはスペースで初期化する
        }
    }
   
    dst->c[index] = c;   
}

// src の文字列を dst に書き込む。
// STRING のメモリーが足りない場合は自動的に確保される
void write_stringSTRING( STRING* dst, STRING* src )
{
    write_strSTRING( dst, src->c, src->len );
}

// char 1文字を src の index 番めから読み込む。
// index が 0 以下の場合は 0 として読み込まれる。 index が STRING長 - 1 以上の場合、STRING長 - 1 として読み込まれる
char read_charSTRING( STRING* src, int index )
{
    if( index <= 0 ) { index = 0; }    else if( index >= src->len - 1 ) { index = src->len - 1; }    // index の範囲丸め
   
    return( src->c[index] );
}

// char 型の文字列 dst へ、STRING型 src から全文字を読み込む。 読み込んだ文字列の最後には必ず '¥0' が付加される。
//
// 注意:dst は十分すぎるほど十分な長さを確保しておくように。
//(Cにはガベージコレクションが無いので、使いやすくするために、あえて固定長配列の dst を引数にしてます。
//  開放忘れによるメモリの行方不明を防ぐため、char* を返す関数として内部で malloc するような作りにはあえてしてません。
// だからdstは十分な長さを確保して渡してください。
// 0xFFFFFF (16メガw)くらいあれば、まぁ、絶対大丈夫だと思います。(一行の長さが1600万文字のテキストファイルなんて、めったに存在しませんもんね...super_piの出力くらい?)
// 0xFFFF (64キロ)くらいでも、実用、十分かと思いますが。(一行の長さが6万4千文字のテキストファイル… まぁこれでも十分ですよね… 普通、一行は100文字程度でしょうし。)
void read_strSTRING( STRING* src, char* dst )
{
    char* d = dst;
    char* s = src->c;
    int len = src->len;

    int i;
    for(i=0;i<len;i++){ *d++ = *s++; }

    switch( dst[len-1] ) {
    case '\0':break;
    default: dst[len] = '\0';
    }
}