Почему при первом вызове функции ANSI печатает код, а во второй раз печатает цвета? - PullRequest
3 голосов
/ 30 сентября 2019

Я пытаюсь изменить цвет вывода моих операторов printf в игре connect 4. Я сделал функцию, чтобы установить цвет печати и сбросить его. Он работает для большей части моего кода, но не работает с первой функцией, которая вызывается при первом вызове, но работает оттуда. Рассматриваемая функция является первой функцией, вызываемой в основной программе.

Я пробовал по-разному позиционировать функцию, располагая ее по обе стороны от места вызова функции, и вводя цветовые коды непосредственно в функцию printf, ноон всегда терпит неудачу первый (и только первый раз).

#include <stdio.h>
void sprint_green();
void sprint_red();
int main_menu ( void ){
    int a = 0;
    char opt [20];
    sprint_red();
    printf("============================\n");
    printf("    Welcome to Connect4!\n");
    printf("============================\n");
    sprint_reset();
    // Continue asking for an option until a valid option (n/l/q) is entered
    while (a == 0)
    {
        sprint_green();
        printf("(N)ew game\n(L)oad game\n(Q)uit");
        sprint_reset();
        fgets(opt, 20, stdin);
    // if 'n', return 1
        if(opt[0] == 'n' || opt[0] == 'N'){
            a = 1;
        }
    // if 'l', return 2
        else if(opt[0] == 'l' || opt[0] == 'L'){
            a = 2;
        }
    // if 'q', return -1
        else if(opt[0] == 'q' || opt[0] == 'Q'){
            a = -1;
            printf("\nGoodbye!\n");
        }
    // if anything else, give error message and ask again..
        else
        {
            printf("Invalid option\n");
        }
    }
    system("cls");
    return(a);
}

int main (void)
{
    int i;

    for(i = 0; i < 5; i++)
    {
        main_menu();
    }
}

void sprint_green()
{
  printf("\033[1;32m");
}

void sprint_red()
{
  printf("\033[1;31m");
}

void sprint_reset()
{
  printf("\033[0m");
}

Первые три оператора printf должны быть напечатаны красным, а следующий должен быть напечатан зеленым. Однако в первый раз это называется печать цветовых кодов ANSI.

[1;31m============================
    Welcome to Connect4!
============================
[0m[1;32m(N)ew game
(L)oad game
(Q)uit[0m

Однако после однократного запуска игры и повторного запуска (без закрытия терминала) эти функции работают как положено.

Ответы [ 2 ]

0 голосов
/ 30 сентября 2019

Командная оболочка Windows по умолчанию не запускает эмуляцию vt100. Как отметил @Bodo в своем ответе, это можно запустить, выполнив команду оболочки cls. Однако технически команда оболочки не обязательно должна быть cls или даже действительной командой вообще. Вы можете запустить его просто пустым system(" ") звонком! Это также переносимо, потому что ничего не делает, кроме мгновенного запуска экземпляра оболочки и его уничтожения. Поэтому он должен одинаково хорошо работать в среде Windows или Linux.

Код с исправлением:

#include <stdio.h>
#include <stdlib.h> // for system()

void sprint_green();
void sprint_red();
int main_menu ( void ){
    int a = 0;
    char opt [20];
    system(" "); // Trigger ANSI emulation
    sprint_red();
    printf("============================\n");
    printf("    Welcome to Connect4!\n");
    printf("============================\n");
    sprint_reset();
    // Continue asking for an option until a valid option (n/l/q) is entered
    while (a == 0)
    {
        sprint_green();
        printf("(N)ew game\n(L)oad game\n(Q)uit");
        sprint_reset();
        fgets(opt, 20, stdin);
    // if 'n', return 1
        if(opt[0] == 'n' || opt[0] == 'N'){
            a = 1;
        }
    // if 'l', return 2
        else if(opt[0] == 'l' || opt[0] == 'L'){
            a = 2;
        }
    // if 'q', return -1
        else if(opt[0] == 'q' || opt[0] == 'Q'){
            a = -1;
            printf("\nGoodbye!\n");
        }
    // if anything else, give error message and ask again..
        else
        {
            printf("Invalid option\n");
        }
    }
    system("cls");
    return(a);
}

int main (void)
{
    int i;

    for(i = 0; i < 5; i++)
    {
        main_menu();
    }
}

void sprint_green()
{
  printf("\033[1;32m");
}

void sprint_red()
{
  printf("\033[1;31m");
}

void sprint_reset()
{
  printf("\033[0m");
}
0 голосов
/ 30 сентября 2019

В соответствии с
https://solarianprogrammer.com/2019/04/08/c-programming-ansi-escape-codes-windows-macos-linux-terminals/
и
https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences?redirectedfrom=MSDN
консоль Windows должна быть переведена в режим экранирования ANSI, чтобы иметь возможность обрабатывать экранированные последовательности вместо их печати. ​​

Видимо, выполнение команды cls, похоже, делает это.

Вы можете программно установить режим терминала, используя GetConsoleMode() и SetConsoleMode(), установив флаг ENABLE_VIRTUAL_TERMINAL_PROCESSING

КодПример, скопированный со ссылочной страницы Microsoft:

#include <stdio.h>
#include <wchar.h>
#include <windows.h>

int main()
{
    // Set output mode to handle virtual terminal sequences
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hOut == INVALID_HANDLE_VALUE)
    {
        return GetLastError();
    }

    DWORD dwMode = 0;
    if (!GetConsoleMode(hOut, &dwMode))
    {
        return GetLastError();
    }

    dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    if (!SetConsoleMode(hOut, dwMode))
    {
        return GetLastError();
    }

    // Try some Set Graphics Rendition (SGR) terminal escape sequences
    wprintf(L"\x1b[31mThis text has a red foreground using SGR.31.\r\n");
    wprintf(L"\x1b[1mThis text has a bright (bold) red foreground using SGR.1 to affect the previous color setting.\r\n");
    /* ... more examples removed */

    return 0;
}

Очевидно, что это решение предназначено только для Windows, но запуск system("cls") также непереносим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...