Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)
Demon's Souls |#9| Heart of surprises

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Богатырев А. Весь текст 1009.15 Kb

Хрестоматия по программированию на Си в Unix

Предыдущая страница Следующая страница
1 ... 61 62 63 64 65 66 67  68 69 70 71 72 73 74 ... 87
                    attr = GETATTR( x, y );

                    if( !white(ch, attr)){
                            firstnospace = y;
                            goto Fall;
                    }
            }

    AllSpaces:       /* в данном столбце все упало */
            return 0;
    Fall:
            /* "уронить" букву */
            for( y = firstnospace ; y < firstspace ; y++ ){
                    /* переместить символ на экране на одну позицию вниз */
                    ch   = GET( x, y );
                    attr = GETATTR( x, y );

                    PUT( x, y, 0 );
                    PUTATTR( x, y, 0 );

                    PUT( x, y+1 , ch );
                    PUTATTR( x, y+1, attr );

                    nap( DELAY );   /* подождать DELAY миллисекунд */
            }
            return 1;               /* что-то изменилось */
    }

8.2.  Для работы может оказаться более удобным иметь указатель на видеопамять как  на
массив структур. Приведем пример для системы MS DOS:

А. Богатырев, 1992-95                  - 355 -                              Си в UNIX

    #include   /* там определено MK_FP */
    char far *screen =
             MK_FP(0xB800 /*сегмент*/, 0x0000 /*смещение*/);
    struct symb{
            char chr; char attr;
    } far *scr, far *ptr;
    #define COLS  80        /* число колонок */
    #define LINES 25        /* число строк   */
    #define SCR(x,y)   scr[(x) + COLS * (y)]
    /* x из 0..79, y из 0..24 */

    void main(){
      int x, y;
      char c;
      scr = (struct symb far *) screen;
      /* или сразу
       * scr = (struct symb far *) MK_FP(0xB800,0x0000);
       */

      /* переписать строки экрана справа налево */
      for(x=0; x < COLS/2; x++ )
        for( y=0; y < LINES; y++ ){
             c = SCR(x,y).chr;
             SCR(x,y).chr = SCR(COLS-1-x, y).chr;
             SCR(COLS-1-x, y).chr = c;
        }

      /* сделать цвет экрана: желтым по синему */
      for(x=0; x < COLS; x++)
        for(y=0; y < LINES; y++)
             SCR(x,y).attr = (0xE | (0x1 << 4));
                        /* желтый + синий фон */

      /* прочесть любую кнопку с клавиатуры (пауза) */
      (void) getch();
    }

И, наконец, еще удобнее работа с видеопамятью как с двумерным массивом структур:

    #include   /* MS DOS */
    #define COLS 80
    #define LINES 25
    struct symb {
           char chr; char attr;
    } (far *scr)[ COLS ] = MK_FP(0xB800, 0);

    void main(void){
         register x, y;
         for(y=0; y < LINES; y++)
             for(x=0; x < COLS; ++x){
                 scr[y][x].chr = '?';
                 scr[y][x].attr = (y << 4) | (x & 0xF);
             }
         getch();
    }

Учтите, что при работе с экраном через видеопамять, курсор не  перемещается!  Если  в

А. Богатырев, 1992-95                  - 356 -                              Си в UNIX

обычной  работе  с  экраном  текст выводится в позиции курсора и курсор автоматически
продвигается, то здесь курсор будет оставаться на своем прежнем месте. Для  перемеще-
ния  курсора  в  нужное вам место, вы должны его поставить явным образом по окончании
записи в видеопамять (например, обращаясь к портам видеоконтроллера).
     Обратите внимание, что спецификатор модели памяти far должен  указываться  перед
КАЖДЫМ  указателем (именно для иллюстрации этого в первом примере описан неиспользуе-
мый указатель ptr).

8.3.  Составьте программу сохранения содержимого экрана IBM PC (видеопамяти) в  текс-
товом режиме в файл и обратно (в системе XENIX).

8.4.  Пользуясь прямым доступом в видеопамять, напишите функции для спасения  прямоу-
гольной области экрана в массив и обратно. Вот функция для спасения в массив:

    typedef struct {
       short xlen, ylen;
       char  *save;
    } Pict;
    extern void *malloc(unsigned);

    Pict *gettext (int x, int y, int xlen, int ylen){
       Pict *n   = (Pict *) malloc(sizeof *n);
       register char *s; register i, j;

       n->xlen = xlen; n->ylen = ylen;
       s = n->save = (char *) malloc( 2 * xlen * ylen );
       for(i=y; i < y+ylen; i++)
            for(j=x; j < x+xlen; j++){
                *s++ = SCR(j,i).chr ;
                *s++ = SCR(j,i).attr;
            }
       return n;
    }

Добавьте проверки на корректность xlen, ylen (в пределах экрана).   Напишите  функцию
puttext для вывода спасенной области обратно; функцию free(buf) лучше в нее не встав-
лять.

    void puttext (Pict *n, int x, int y){
       register char *s = n->save;
       register i, j;
       for(i=y; i < y + n->ylen; i++)
            for(j=x; j < x + n->xlen; j++){
                SCR(j,i).chr  = *s++;
                SCR(j,i).attr = *s++;
            }
    }
    /* очистка памяти текстового буфера */
    void deltext(Pict *n){ free(n->save); free(n); }

Приведем еще одну полезную функцию, которая может вам пригодиться - это аналог printf
при прямой работе с видеопамятью.

    #include 
    /* текущий цвет: белый по синему */
    static char currentColor = 0x1F;

    int videoprintf (int x, int y, char *fmt, ...){
        char buf[512], *s;
        va_list var;

А. Богатырев, 1992-95                  - 357 -                              Си в UNIX

        /* clipping (отсечение по границам экрана) */
        if( y < 0 || y >= LINES ) return x;

        va_start(var, fmt);
        vsprintf(buf, fmt, var);
        va_end(var);

        for(s=buf; *s; s++, x++){
            /* отсечение */
            if(x < 0    ) continue;
            if(x >= COLS) break;
            SCR(x,y).chr = *s;
            SCR(x,y).attr = currentColor;
        }
        return x;
    }
    void setcolor (int col){ currentColor = col; }

8.5.  Пользуясь написанными функциями, реализуйте функции  для  "выскакивающих"  окон
(pop-up window):

    Pict *save;
      save = gettext (x,y,xlen,ylen);

      // ... рисуем цветными пробелами прямоугольник с
      // углами (x,y) вверху-слева и (x+xlen-1,y+ylen-1)
      // внизу-справа...

      // ...рисуем некие таблицы, меню, текст в этой зоне...

      // стираем нарисованное окно, восстановив то изображение,
      // поверх которого оно "всплыло".
      puttext (save,x,y);
      deltext (save);

Для начала напишите "выскакивающее" окно с сообщением; окно должно исчезать по  нажа-
тию любой клавиши.

       c = message(x, y,   text);

Размер окна вычисляйте по длине строки text. Код клавиши возвращайте в качестве  зна-
чения функции.
     Теперь сделайте text массивом строк: char *text[]; (последняя строка - NULL).

8.6.  Сделайте так, чтобы "выскакивающие" окна имели тень. Для этого надо сохранить в
некоторый буфер атрибуты символов (сами символы не надо!), находящихся на местах $:

            ##########
            ##########$
            ##########$
             $$$$$$$$$$

а затем прописать этим символам на экране атрибут 0x07 (белый по черному). При стира-
нии  окна (puttext-ом) следует восстановить спасенные атрибуты этих символов (стереть
тень). Если окно имеет размер xlen*ylen, то размер буфера равен xlen+ylen-1 байт.

8.7.  Напишите функцию, рисующую на экране прямоугольную рамку.  Используйте  ее  для
рисования рамки окна.

А. Богатырев, 1992-95                  - 358 -                              Си в UNIX

8.8.  Напишите "выскакивающее" окно, которое проявляется на экране как бы  расширяясь
из точки:

                           ##############
                ######     ##############
       ###      ######     ##############
                ######     ##############
                           ##############

Вам следует написать функцию box(x,y,width,height), рисующую цветной прямоугольник  с
верхним  левым  углом  (x,y)  и размером (width,height). Пусть конечное окно задается
углом (x0,y0) и размером (W,H). Тогда "вырастание" окна описывается таким алгоритмом:

    void zoom(int x0, int y0, int W, int H){
        int x, y, w, h, hprev; /* промежуточное окно */
        for(hprev=0, w=1; w < W; w++){
            h = H * w; h /= W;  /* W/H == w/h */
            if(h == hprev) continue;
            hprev = h;
            x = x0 + (W - w)/2; /* чтобы центры окон */
            y = y0 + (H - h)/2; /* совпадали         */
            box(x, y, w, h);
            delay(10);      /* задержка 10 миллисек. */
        }
        box(x0, y0, W, H);
    }

8.9.  Составьте библиотеку функций, аналогичных библиотеке curses, для ЭВМ  IBM PC  в
ОС XENIX.  Используйте прямой доступ в видеопамять.

8.10.  Напишите рекурсивное решение задачи "ханойские башни" (перекладывание  дисков:
есть  три  стержня, на один из них надеты диски убывающего к вершине диаметра. Требу-
ется переложить их на третий стержень, никогда не кладя диск большего диаметра поверх
диска  меньшего  диаметра).   Усложнение  -  используйте пакет curses для изображения
перекладывания дисков на экране терминала.  Указание: идея рекурсивного алгоритма:

      carry(n, from, to, by) = if( n > 0 ){
                    carry( n-1, from, by, to );
                    перенесиОдинДиск( from, to );
                    carry( n-1, by,   to, from );
                 }
      Вызов:     carry( n, 0, 1, 2 );
      n    - сколько дисков перенести (n > 0).
      from - откуда (номер стержня).
      to   - куда.
      by   - при помощи (промежуточный стержень).

n дисков потребуют (2**n)-1 переносов.

8.11.  Напишите программу, ищущую выход из лабиринта ("червяк в  лабиринте").   Лаби-
ринт  загружается  из  файла  .maze (не забудьте про расширение табуляций!). Алгоритм
имеет рекурсивную природу и выглядит примерно так:

    #include 
    jmp_buf jmp; int found = 0;

    maze(){ /* Это головная функция */
        if( setjmp(jmp) == 0 ){ /* начало */
            if( неСтенка(x_входа, y_входа))
                GO( x_входа, y_входа);

А. Богатырев, 1992-95                  - 359 -                              Си в UNIX

        }
    }
    GO(x, y){       /* пойти в точку (x, y) */
        if( этоВыход(x, y)){ found = 1;  /* нашел выход */
            пометить(x, y); longjmp(jmp, 1);}
        пометить(x, y);
        if( неСтенка(x-1,y)) GO(x-1, y);  /* влево */
        if( неСтенка(x,y-1)) GO(x, y-1);  /* вверх */
        if( неСтенка(x+1,y)) GO(x+1, y);  /* вправо */
        if( неСтенка(x,y+1)) GO(x, y+1);  /* вниз   */
        снятьПометку(x, y);
    }
    #define пометить(x, y)     лабиринт[y][x] = '*'
    #define снятьПометку(x, y) лабиринт[y][x] = ' '
    #define этоВыход(x, y)   (x == x_выхода && y == y_выхода)
    /* можно искать "золото":  (лабиринт[y][x] == '$') */

    неСтенка(x, y){ /* стенку изображайте символом @ или # */
      if( координатыВнеПоля(x, y)) return 0; /*край лабиринта*/
      return (лабиринт[y][x] == ' ');
    }

Отобразите массив лабиринт на видеопамять (или воспользуйтесь curses-ом). Вы  увидите
червяка, ползающего по лабиринту в своих исканиях.

8.12.  Используя библиотеку termcap напишите функции для:
-    очистки экрана.
-    позиционирования курсора.
-    включения/выключения режима выделения текста инверсией.

8.13.  Используя написанные функции, реализуйте программу выбора в  меню.   Выбранную
строку выделяйте инверсией фона.

    /*#!/bin/cc termio.c -O -o termio -ltermcap
     * Смотри   man termio, termcap и screen.
     *              Работа с  терминалом в стиле System-V.
     *              Работа с  системой команд терминала через /etc/termcap
     *              Работа со временем.
     *              Работа с  будильником.
     */

    #include               /* standard input/output */
    #include           /* system typedefs */
    #include              /* terminal input/output */
    #include              /* signals */
    #include               /* file control */
Предыдущая страница Следующая страница
1 ... 61 62 63 64 65 66 67  68 69 70 71 72 73 74 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама