0

I am making a game in C, and when the user input the Konami code (cheat code), the program should print out the correct answer. (edit #3) found out that my program does not "read" the arrow keys whenever I input it, how do I make it so? pls. see my comment below

Here is my updated code (edit #2): //try konami

#include<stdio.h>
#include<string.h>

main() {

    int c;
    char cheat[] = {24,24,25,25,27,26,27,26,98,97}; //thanks to Vicky for clarifying this
    char guess[100];

    printf("Enter guess: "); 
    scanf("%c", &guess);

    //just checking if the cheat array is right, and yes it is. I'll remove this later
    for ( c = 0; c < 11; c++ ) {
        printf("%c", cheat[c]);
    }


    //comparison of the guess (input) to the cheat code
    if (strcmp (cheat, guess) == 0  )
       printf("\nYou win!");
    else
       printf("\nLol!");

}

Now, my problem is it always prints Lol! even though I input the cheat code correctly . . .

note: this is for my intro class in programming (my first time in c too). lessons covered so far are basics, loops, arrays and strings (no functions yet but i understood that now, no structures and further pls. thank you :)

dragosht
  • 3,237
  • 2
  • 23
  • 32
user3203014
  • 19
  • 1
  • 1
  • 5
  • you are implementing Contra in C? – How Chen Jan 28 '14 at 14:53
  • 1
    In C, you can't compare strings with `foo == bar`. You need to use `strcmp()`. – Marc B Jan 28 '14 at 14:56
  • oh, right. but my major concern is how to initialize my cheat array with the arrow keys to compare it with the input of the user. – user3203014 Jan 28 '14 at 14:59
  • @user3203014, so your question has nothing to do with "cheat" or stuff like that? You simply don't know how to put arrow keys in the array? Then, please edit your question (and title) accordingly. – Jens Gustedt Jan 28 '14 at 15:02
  • How do you know 24 represents the up button – Brandin Jan 28 '14 at 15:22
  • When you say you've covered chars, strings, and arrays....you might want to revisit that. Your initialisation for your array `"24,24,25,25,27,26,27,26,66,65"`is a string containing character 2, character 4, character comma, character 2.... etc. – Vicky Jan 28 '14 at 15:24
  • @Vicky woops. i've changed that into this, pasted the older/wrong one: char cheat[] = {'24','24','25','25','27','26','27','26','66','65'}; – user3203014 Jan 28 '14 at 15:34
  • @user3203014 that won't even compile - have you tried compiling (with warning levels turned up) and looking at the output?? If you're specifying the ASCII character values you don't need any kind of quotes at all. – Vicky Jan 28 '14 at 15:50
  • @Vicky I tried printing the first element of the guess input: printf("%c", guess[0]); but it just prints the letter b, meaning, it ignores the arrow keys. why is that so? how can I make my program "read" the arrow keys when inputted? (again my cheat code is: upupdowndownleftrightleftrightba – user3203014 Jan 28 '14 at 16:45
  • You can't do this in standard C unless your system is set up to make your arrow keys produce regular characters, just like the most of the other keys, in which case you need to read the manuals for your system. If not, you're going to have to use some kind of terminal handling library such as ncurses, or win32. – Crowman Jan 28 '14 at 16:52
  • @PaulGriffiths My OS is Win7, at school is Linux, my prof's Mac. I'm gonna submit it it online so I'm not sure (is that the system you're referring to?) But we all use the MinGW compiler. I'll search for ncurses and win32 but can you suggest which is easier to comprehend? – user3203014 Jan 28 '14 at 17:07
  • 2
    @user3203014: If you've only just started C, then frankly, neither of them will be. I'd suggest just using a cheat word, and forgetting about the arrow keys, but if you really must try, and you're familiar with neither, then ncurses is probably marginally simpler than win32's console API. – Crowman Jan 28 '14 at 17:10
  • As of 2023, [here](https://stackoverflow.com/a/75499310/6013016) is the solution – Scott Feb 20 '23 at 00:09

1 Answers1

6

my question is how do i check it coming from the user

I'm hearing that you want to know when the user presses an arrow key? I had to do this in C++ and it turned out to be a very enlightening experience, so although you are using C and not C++ i will still share what i remember.

Arrow keys take a sequence of bytes instead of one AND are usually implemented at the hardware level!

Though whatever operating system you are using should have support (goodbye portability), the term you need to be looking for is key codes and in windows they call them Virtual-Key Codes

On Windows I had learn to program with the win32api.

I can easily show you the key codes for windows (and i will paste them from that link) but they are no good to you unless you want to commit to a windows event driven type program (maybe you already are?), these codes are fetched from the key events in your program and are not ascii-codes and i would go as far to assume specific to windows.

VK_LEFT
0x25
LEFT ARROW key
VK_UP
0x26
UP ARROW key
VK_RIGHT
0x27
RIGHT ARROW key
VK_DOWN
0x28

And in linux I still had to deal with events, this time using X11, oh the joys i had with X11! the keycodes here are called XK_[key] i.e XK_left.

These key codes are defined in the header <X11/keysymdef.h> - Xlib programming manual

see header online

#define XK_Left                          0xff51  /* Move left, left arrow */
#define XK_Up                            0xff52  /* Move up, up arrow */
#define XK_Right                         0xff53  /* Move right, right arrow */
#define XK_Down                          0xff54  /* Move down, down arrow */

Hopefully this can set you on the right path, whenever i need arrow keys now i just use wasd.


EDIT: This is the windows one, i condensed it down from the C++ game i made to this C program,it's a lot of code, anything that looks like it shouldn't be there probably shouldn't, but it compiles and reads the arrow keys, so everything you need is in this source atleast.

WINDOWS;

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

        //directional keys
#define key_left  0x25
#define key_up  0x26
#define key_right  0x27
#define key_down  0x28

        // to quit
#define key_escape  0x1B


char checkType(INPUT_RECORD *buffer, int i);
int checkKey(INPUT_RECORD *buffer, int i);
void outputString(const char *str, SHORT col, SHORT row);
void outputChar(char ch, SHORT col, SHORT row);
void clearScreen(void);

CHAR_INFO *p_consoleBuffer;


HANDLE whnd;    // handle to write console
HANDLE rhnd;    // handle to read console


SMALL_RECT winSize;
COORD buffSize;

SHORT consoleHeight = 25;
SHORT consoleWidth = 60;

DWORD Events = 0; // Event count
DWORD EventsRead = 0; // Events read from console



int _tmain(int argc, _TCHAR* argv[]){

    // set up handles for read/writing:
    whnd = GetStdHandle(STD_OUTPUT_HANDLE);
    rhnd = GetStdHandle(STD_INPUT_HANDLE);

    SetConsoleTitle(TEXT("DEMO WIN PROG"));

    SMALL_RECT winLen = {0,0,((SHORT)consoleWidth-1),((SHORT)consoleHeight-1)};

    COORD bLen = {consoleWidth,consoleHeight}; // width / height
    winSize = winLen;

    // set console size
    SetConsoleWindowInfo(whnd, TRUE, &winSize);

    // set the buffer size coords
    SetConsoleScreenBufferSize(whnd, buffSize);

    CHAR_INFO consoleBuffer[consoleHeight*consoleWidth];
    p_consoleBuffer = consoleBuffer;

    CONSOLE_CURSOR_INFO cci;
    cci.dwSize = 1;
    cci.bVisible = FALSE;
    SetConsoleCursorInfo(whnd, &cci);

    clearScreen();

    int Running = 1;
    char type = 0;

    while(Running) {
        //game loop

        GetNumberOfConsoleInputEvents(rhnd, &Events);

        if(Events != 0){ // something happened

            // create buffer the size of how many Events & store
            INPUT_RECORD eventBuffer[Events];
            // fills buffer with events and save count in EventsRead
            ReadConsoleInput(rhnd, eventBuffer, Events, &EventsRead);


            DWORD i;
            for(i = 0; i<EventsRead; ++i){
                type = checkType(eventBuffer,i);

                if(type == 'k'){ // event type was key

                    int key = checkKey(eventBuffer, i);
                    int arrow_key_pressed = FALSE;

                    switch (key){
                        case key_up:
                        case key_down:
                        case key_left:
                        case key_right:
                            // IF ANY ARROW KEY WAS PRESSED, EXECUTION WILL "COLLAPSE" TO HERE
                            arrow_key_pressed = TRUE;
                            break;

                        case key_escape:
                            // escape was pressed
                            Running = 0;
                            break;

                        default:
                            // no case was pressed
                            break;
                    }


                    clearScreen();
                    if(arrow_key_pressed){
                        const char *str = "Arrow key was pressed";
                        outputString(str, 20, 12); // roughly centre
                    }else {
                        const char *str = "Arrow key was not pressed";
                        outputString(str, 20, 12);
                    }


                }else if(type == 'm'){
                    // MOUSE CLICK, I'M NOT COVERING SORRY.
                }
            }
        }
    }
    return 0;
}

char checkType(INPUT_RECORD *buffer, int i){
    if(buffer[i].EventType == MOUSE_EVENT){
        return ('m');
    }else if(buffer[i].EventType == KEY_EVENT){
        return ('k');
    }else return (0);
}

int checkKey(INPUT_RECORD *buffer, int i){
    return (buffer[i].Event.KeyEvent.wVirtualKeyCode);
}

void outputString(const char *str, SHORT col, SHORT row){
    SHORT fs_len = strlen(str);
    int i;
    for(i = 0; i<fs_len; ++i){
        outputChar(str[i], col++, row);
    }
}

void outputChar(char ch, SHORT col, SHORT row){
    p_consoleBuffer[row*consoleWidth+col].Char.AsciiChar = ch;
    p_consoleBuffer[row*consoleWidth+col].Attributes = 240;

    SHORT CH = consoleHeight, CW = consoleWidth;
    COORD charBufSize = {CW,CH};
    COORD charPos = {0,0};
    SMALL_RECT writeArea = {0,0,CW,CH};
    WriteConsoleOutputA(whnd,p_consoleBuffer,charBufSize,charPos,&writeArea);
}

void clearScreen(void){
    int i;
    for(i = 0; i<(consoleHeight*consoleWidth); ++i){
        //fill it with white-backgrounded spaces
        p_consoleBuffer[i].Char.AsciiChar = ' ';
        p_consoleBuffer[i].Attributes =
            BACKGROUND_BLUE |
            BACKGROUND_GREEN |
            BACKGROUND_RED |
            BACKGROUND_INTENSITY;
    }

    // clear screen
    SHORT CH = consoleHeight, CW = consoleWidth;
    COORD charBufSize = {CW,CH};
    COORD charPos = {0,0};
    SMALL_RECT writeArea = {0,0,CW,CH};
    WriteConsoleOutputA(whnd,p_consoleBuffer,charBufSize,charPos,&writeArea);

}

/* Remember i did this in c++, i made a class with these ints
   to represent the virtual key codes, you can define them how you
   want like i did or use windows actual definitions.

        //special keys
        key_escape = 0x1B;
        key_space = 0x20;
        key_home = 0x24;
        key_end = 0x23;
        key_pgUp = 0x21;
        key_pgDown = 0x22;
        key_caps = 0x13;
        key_shift = 0x10;
        key_ctrl = 0x11;
        key_backspace = 0x08;
        key_tab = 0x09;
        key_enter = 0x0D;
        key_alt = 0x12;
        key_delete = 0x2E;

        //directional keys
        key_left = 0x25;
        key_up = 0x26;
        key_right = 0x27;
        key_down = 0x28;

        //number keys
        key_0 = 0x30;
        key_1 = 0x31;
        key_2 = 0x32;
        key_3 = 0x33;
        key_4 = 0x34;
        key_5 = 0x35;
        key_6 = 0x36;
        key_7 = 0x37;
        key_8 = 0x38;
        key_9 = 0x39;

        // alphabet keys
        key_a = 0x41;
        key_b = 0x42;
        key_c = 0x43;
        key_d = 0x44;
        key_e = 0x45;
        key_f = 0x46;
        key_g = 0x47;
        key_h = 0x48;
        key_i = 0x49;
        key_j = 0x4A;
        key_k = 0x4B;
        key_l = 0x4C;
        key_m = 0x4D;
        key_n = 0x4E;
        key_o = 0x4F;
        key_p = 0x50;
        key_q = 0x51;
        key_r = 0x52;
        key_s = 0x53;
        key_t = 0x54;
        key_u = 0x55;
        key_v = 0x56;
        key_w = 0x57;
        key_x = 0x58;
        key_y = 0x59;
        key_z = 0x5A;
*/

LINUX: (X11) This is that example program i used, it was actually when i first started programming that i wanted to do this myself, and i cannot remember where it came from or who wrote it, so i cannot credit them unfortunately, but here is the source;

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
/*Linux users will need to add -ldl to the Makefile to compile
 *this example.
 */
Display *dis;
Window win;
XEvent report;
GC green_gc;
XColor green_col;
Colormap colormap;
/*
Try changing the green[] = below to a different color.
The color can also be from /usr/X11R6/lib/X11/rgb.txt, such as RoyalBlue4.
A # (number sign) is only needed when using hexadecimal colors.
*/
char green[] = "#00FF00";

int main() {
        dis = XOpenDisplay(NULL);
        win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 500, 500, 0, BlackPixel (dis, 0), BlackPixel(dis, 0));
        XMapWindow(dis, win);
        colormap = DefaultColormap(dis, 0);
        green_gc = XCreateGC(dis, win, 0, 0);
        XParseColor(dis, colormap, green, &green_col);
        XAllocColor(dis, colormap, &green_col);
        XSetForeground(dis, green_gc, green_col.pixel);

        XSelectInput(dis, win, ExposureMask | KeyPressMask | ButtonPressMask);

        XDrawRectangle(dis, win, green_gc, 1, 1, 497, 497);
        XDrawRectangle(dis, win, green_gc, 50, 50, 398, 398);
        XFlush(dis);

        while (1)  {
        XNextEvent(dis, &report);
        switch  (report.type) {
            case Expose:
                fprintf(stdout, "I have been exposed.\n");
                                XDrawRectangle(dis, win, green_gc, 1, 1, 497, 497);
                                XDrawRectangle(dis, win, green_gc, 50, 50, 398, 398);
                                XFlush(dis);
                        break;
            case KeyPress:
            /*Close the program if q is pressed.*/
                    if (XLookupKeysym(&report.xkey, 0) == XK_q) {
                        exit(0);
                    }
                    break;
                }
        }

        return 0;
}
James
  • 1,009
  • 10
  • 11
  • seems like my MinGW compiler doesn't have the since it says "No such file or directory compilation terminated" works but I'm having a problem understanding how to use the key-codes. Do I make them like this i.e. - #define VK_LEFT 0x25 // LEFT ARROW key ? Then how do I make them as a string/array to compare them to the guess input? Can you enlightened me further please. Thanks – user3203014 Jan 28 '14 at 18:52
  • Oh sorry, `X11` for _linux_, though you can download it for other platforms like `windows` i think, also i think `X11` might have needed some flags when compiled! With windows i can edit into my answer a C program using the win32api (just keep in mind, i'm no windows pro, i probably did things wrong, but at least it reads the arrow keys right?), and i'll have a look for the example program i was using in Linux to wrap a my mind around `X11` for you. BUT i think if you are just beginning, you should not bother with this yet, these api's use everything available to them in a language. – James Jan 29 '14 at 03:57
  • X11 headers are for X11 programs. They do nothing for console programs, on any OS. – n. m. could be an AI Jan 29 '14 at 04:42
  • What part of my answer are you replying to? I'm not sure what you're trying to tell me, i don't know what you mean by "X11 headers are for X11 programs" or "They do nothing for console programs", you will need to expand on this, I don't know a whole lot about X11 in the first place and it was a long time ago i had any exposure to it, but when i did, i made a crappy console paint program and the X11 headers seemed to be doing everything in my program?? I'm not trying to argue, i'm just a little confused. – James Jan 29 '14 at 05:01
  • @n.m oh wait, if it opens a new window it's not a console program? is that what i'm overlooking? – James Jan 29 '14 at 07:46
  • By "console" people generally understand the text terminal, not any kind of graphic screen. You cannot read arrow keys from the text terminal using XK_ symbols, it's a totally different API. – n. m. could be an AI Jan 29 '14 at 08:48
  • @n.m okay, i didn't realize OP wanted a strictly in the terminal program, the windows one is a proper console program, so that is still a solution, and i guess for linux others have mentioned `ncurses`, something i have never used, so i don't know if that's a good answer or not. – James Jan 29 '14 at 10:03
  • `ncurses` would be generally OK, but probably less so for someone who's just starting to learn C. – n. m. could be an AI Jan 29 '14 at 11:00