Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Скидка до 20% на услуги дата-центра. Аренда серверной стойки. Colocation от 1U!

Миграция в облако #SotelCloud. Виртуальный сервер в облаке. Выбрать конфигурацию на сайте!

Виртуальная АТС для вашего бизнеса. Приветственные бонусы для новых клиентов!

Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPS\VDS

VPS/VDS серверы. 30 локаций на выбор

Серверы VPS/VDS с большим диском

Хорошие условия для реселлеров

Надежные VPS и выделенные серверы в Нидерландах

Storage VPS, High CPU VPS

Профессиональная техническая поддержка

Домены, SSL сертификаты, VPN

8.2.

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

    #include <dos.h>  /* там определено 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 <dos.h>  /* 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();
    }

Учтите, что при работе с экраном через видеопамять, курсор не перемещается! Если в обычной работе с экраном текст выводится в позиции курсора и курсор автоматически продвигается, то здесь курсор будет оставаться на своем прежнем месте. Для перемещения курсора в нужное вам место, вы должны его поставить явным образом по окончании записи в видеопамять (например, обращаясь к портам видеоконтроллера).

Обратите внимание, что спецификатор модели памяти 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 <stdarg.h>
    /* текущий цвет: белый по синему */
    static char currentColor = 0x1F;
    int videoprintf (int x, int y, char *fmt, ...){
        char buf[512], *s;
        va_list var;
        /* 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.

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

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 <setjmp.h>
    jmp_buf jmp; int found = 0;
    maze(){ /* Это головная функция */
        if( setjmp(jmp) == 0 ){ /* начало */
            if( неСтенка(x_входа, y_входа))
                GO( x_входа, y_входа);
        }
    }
    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 напишите функции для:
  • очистки экрана.
  • позиционирования курсора.
  • включения/выключения режима выделения текста инверсией.

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

Назад | Содержание | Вперед

Бесплатный конструктор сайтов и Landing Page

Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

SSD VPS в Нидерландах под различные задачи от 2.6$

Спринтхост — хостинг от 129 ₽ в месяц

Бесподобная поддержка, тестовый период 30 дней и домены от 149 ₽

Промокод на 30% кешбэк — CITFORUM

VPS в России, Европе и США

Бесплатная поддержка и администрирование

Оплата российскими и международными картами

🔥 VPS до 5.7 ГГц под любые задачи с AntiDDoS в 7 локациях

💸 Гифткод CITFORUM (250р на баланс) и попробуйте уже сейчас!

🛒 Скидка 15% на первый платеж (в течение 24ч)

Новости мира IT:

Архив новостей

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...