[
  {
    "path": ".gitignore",
    "content": "# Prerequisites\n*.d\n\n# Object files\n*.o\n*.ko\n*.obj\n*.elf\n\n# Linker output\n*.ilk\n*.map\n*.exp\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Libraries\n*.lib\n*.a\n*.la\n*.lo\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dylib\n\n# Executables\n*.exe\n*.out\n*.app\n*.i*86\n*.x86_64\n*.hex\n\n# Debug files\n*.dSYM/\n*.su\n*.idb\n*.pdb\n\n# Kernel Module Compile Results\n*.mod*\n*.cmd\n.tmp_versions/\nmodules.order\nModule.symvers\nMkfile.old\ndkms.conf\n\n\\.DS_Store\n\nexamples/bounce\n\nexamples/hello\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Paul Harrington\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Guide to making your first command line project with ncurses\n\n## Intro\nEveryone's first programming experience is on some form of command line, usually a hello world in your language of choice.\n\n```\nint main() {\n    printf(\"Hello World!\\n\");\n    return EXIT_SUCCESS;\n}\n```\n\nBut eventually you grow out of it, you start to think \"the command line is only for debugging\" well I'm here to defend the command line, and all of its glory. Writing full-blown apps in the command line is not only fun, but its easy, and it can look damn good (assuming you're down for a retro look). Making a game or app as a command line app is quicker and easier than messing around with complex graphics libraries, or god forbid, css.\n\nThis guide is going to be a look at how you can make command line apps and games (like [this one](https://github.com/harrinp/WalledIn)) simply and easily using the ncurses library. ncurses is a very common library for posix-compliant (_typically this means Macos and Linux_) command lines.\n\n##### Caveats\n\nThis guide isn't going to go over anything to do with windows, ncurses supports posix compliant terminals. You may be able to get ncurses working on windows, but I offer no guarantees. Further, there are other libraries like ncurses which are for windows, namely [conio.h](https://en.wikipedia.org/wiki/Conio.h). I won't cover it here but the principles should be similar.\n\n###### Other guides\nI'm not the expert, just a dev who already went through this learning process. This guide is going to be a bare-bones \"get up and running\" lesson, you can find a more detailed explanation of ncurses and all of its capabilities [here](https://invisible-island.net/ncurses/ncurses.faq.html) and [here](http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/).\n\n###### Language choice\nncurses, like many libraries is a C library, I wrote all of these programs and examples in C, partly because that's the library language, and partly because C is beautiful. I'm a firm believer that programmers should have at least a working knowledge of the C language since it's a building block of basically everything. But I digress, you could also use C++ or something else, but you might need a different library or a connection method, my knowledge is nonexistant in this area. I recommend trying these examples in C, even if you aren't a C guru these examples should be easy to understand and expand upon. Have fun!\n\n##### Example files\n\nAll example files will be included in the examples folder of this repository.\n\n## Getting started\n\n### Hello world v2\n\nLets redo our old hello world program and give it a fancy twist.\n\nMake sure you include ncurses.h\n```\n#include <ncurses.h>\n```\n\nNow we need to initialize ncurses, and make sure we leave ncurses mode when we're done. This is done with initscr() and endwin().\n```\nint main() {\n    initscr();\n    printf(\"Hello World!\\n\");\n    endwin();\n    return EXIT_SUCCESS;\n}\n```\n\nNow we need to update our printf with the ncurses variant, printw(). This works the same way as printf. Then we need to refresh() so that the data we've put in is shown. Then theres getch(), getch() is the ncurses function to get input as a character, but here we're using it so that the program will wait for a character before endwin(), where it clears the screen and returns to normal mode.\n\n```\nint main() {\n    initscr();\n    printw(\"Hello World!\");\n    refresh();\n    getch();\n    endwin();\n    return EXIT_SUCCESS;\n}\n```\nCompile - make sure to link ncurses with -lncurses\n```\ngcc helloWorld.c -o hello -lncurses\n```\nAnd run with `./hello`!\n\n![Not super exciting](images/hello3.png)\n\nFantastic, but thats not interesting. Lets spice it up. I'm going to now use mvprintw(), its the same as printw but you need to give it two coordinates, y then x, as the first two parameters.\n```\nint main() {\n    initscr();\n    mvprintw(5,5,\"Hello World!\");\n    refresh();\n    getch();\n    endwin();\n    return EXIT_SUCCESS;\n}\n```\nResult:\n\n![Not super exciting](images/hello4.png)\n\nSee? We've moved the hello world down 5 lines down and 5 characters over.\n\n### Terminal animation with ncurses\n\nNow lets do something more interesting. We'll make a ball (the character 'o') and have it bounce off the walls of the terminal window.\n\nWe'll create a new file BouncingO.c, and add in two structs to hold our data.\n\n```\n// Stores our balls position\ntypedef struct _Ball {\n    int x;\n    int y;\n} Ball;\n// Stores the direction that the ball is moving\ntypedef struct _Direction {\n    int x;\n    int y;\n} Direction;\n```\n\nInitialize with our ncurses functions\n```\ninitscr();              // Start ncurses\nnodelay(stdscr, TRUE);  // Don't wait for \\n for getch to parse input\ncbreak();               // Switch off input buffering\ncurs_set(FALSE);        // Don't place a cursor on the screen\n```\nInitialize our ball and window information\n```\nint height = 0;         // Window height\nint width = 0;          // Window width\n\n// initialize our ball struct and direction struct\nBall b = {\n    1,1\n};\nDirection d = {\n    1,1\n};\n\n// Get terminal window dimensions (rows and characters)\ngetmaxyx(stdscr, height, width);\n```\nNote: getmaxyx() does not get passed variable addresses, but it does change the variables you pass in.\n\nAnd finally, make our \"game\" loop:\n\n```\nwhile (getch() == ERR) {\n    // print ball\n    mvprintw(b.y,b.x,\"o\");\n\n    // move ball for next frame\n    b.y += d.y;\n    b.x += d.x;\n\n    // Check for ball being outside of our window boundaries\n    if (b.x == width - 1 || b.x == 0){\n        // change direction\n        d.x *= -1;\n        b.x += d.x;\n    }\n    if (b.y == height - 1 || b.y == 0){\n        // change direction\n        d.y *= -1;\n        b.y += d.y;\n    }\n\n    refresh();      // Refresh the output\n    usleep(50000);  // Sleep to show output (Single frame)\n    clear();        // Clear output\n}\n```\nMost of this is self explanatory but its worth noting that refresh() and clear() are ncurses functions and usleep is a unistd.h function. The \"game\" logic of the ball is just adding the direction -1 or 1 to the ball each frame, and changing the direction when it contacts the edge.\n\nResult:\n\n![Bouncing Ball](https://thumbs.gfycat.com/FailingDownrightHippopotamus-size_restricted.gif)\n\nFun Right?\n\n### Colors\nAny self respecting game dev needs to use colors, ncurses makes this easy to do in the terminal. Because of the way that terminals work with color this has to be done with _color pairs_. 1 is the id of this color pair.\n\n```\ninit_pair(1, COLOR_RED, COLOR_BLACK);  // Always start at 0\n// This makes a red foreground on a black background\n```\n\nYou then use it like this:\n```\nattron(COLOR_PAIR(1));  // Enable the color pair  \n// Print something\nattroff(COLOR_PAIR(1)); // Its good practice to disable it\n```\nThis is nice but its hard to use easily, I find it best to abstract this process. Here's an example for a colored, multi-ball version of the bouncingO program.\n\nThis function abstracts away the color pair creation process. Basically, ncurses deals with colors as color pairs only, foreground and background. Since I only want to color the balls, I used -1 as the background (you MUST call use_default_colors() before doing this). Since I don't care which colors are which I'm just using a for loop to make all the possible color pairs with a blank background. When making your own program you may want to use just a single or a couple color pairs. You would make those like this: init_pair(ID, COLOR_RED, COLOR_WHITE); That will have a red letter on a white background. The IDs must start at 1 and go up.\n\n```\nvoid makeColorPairs(){\n    for (int i = 0; i < 8; i++) {\n        init_pair(i+1, i, -1);\n    }\n```\nThen I use them by randomly selecting a color pair 1-8 for the balls. It looks like this after combining with randomized initial positions:\n\n![Bouncing Balls](https://thumbs.gfycat.com/PortlyVacantDutchshepherddog-size_restricted.gif)\n\nHere are the available colors in ncurses:\n```\nCOLOR_BLACK   0\nCOLOR_RED     1\nCOLOR_GREEN   2\nCOLOR_YELLOW  3\nCOLOR_BLUE    4\nCOLOR_MAGENTA 5\nCOLOR_CYAN    6\nCOLOR_WHITE   7\n```\n\n\n## Making a larger project\n\nHopefully now you should be able to see how you could make a terminal project, but I'm going to run through how I made the small terminal screensaver shown above.\n\nRepo here: [Bouncing Balls Repo](https://github.com/harrinp/BouncingBalls)\n\nWhen making a full-blown game my strategy is to abstract these printing functions so that the game logic is separate from the printing functions. In c this means that I create a main function that calls all of my logic and printing functions, but I keep any printing outside of my logic functions. Here's my main for the bouncing balls screensaver:\n\n```\nint main(int argc, char *argv[]) {\n    int numBalls = 100;          // If theres an argument process it\n    if (argc > 1){\n        numBalls = atoi(argv[1]);\n        // Theres no safeguard for bad input (because I'm lazy) don't try this at home\n    }\n    srand(time(NULL));\n    initscr();              // Start ncurses\n    nodelay(stdscr, TRUE);  // Don't wait for \\n for getch to parse input\n    cbreak();               // Switch off input buffering\n    curs_set(FALSE);        // Don't place a cursor on the screen\n    start_color();\n    use_default_colors();\n\n    makeColorPairs();       // Abstracted color pair function\n\n    Window w = initWindow(numBalls, 50000); // Initialize data structs\n\n    while (getch() == ERR) {\n        clear();                            // Clear screen\n        moveBalls(&w);                      // Movement logic\n        printWindow(&w);                    // Print the balls\n        usleep(w.sleepTime);                // Sleep to show screen\n    }\n    destroyWindow(&w);\n    nodelay(stdscr, FALSE);\n    nocbreak();\n    endwin();\n    return 0;\n}\n\n```\nmoveBalls() and printWindow() are abstracted from each other. One big benefit of this is that you can then multithread these two processes so that the game logic (or input for a game) can be processed while the print function sleeps. I did this for [walled in](https://github.com/harrinp/WalledIn) which gave the program much better performance than it otherwise would have had.\n\nthe `while (getch() == ERR){}` waits for any key press and then ends the program if it gets one.\n\nImportant to this strategy is using structs to hold your data, this allows you to keep the printing and logic separate - just pass the address (a pointer) of the game data struct(s) around and manipulate/read them for logic/printing.\n\nFor this project my print function looked like this:\n```\nvoid printWindow(Window * w) {\n    for (int i = 0; i < w->numBalls; i++) {\n        attron(COLOR_PAIR(w->balls[i].colorPair));      // Applying the ball's color\n        mvprintw(w->balls[i].y, w->balls[i].x, w->balls[i].avatar);\n        attroff(COLOR_PAIR(w->balls[i].colorPair));     // Stop printing in this color\n    }\n}\n```\n\nAnd here are the structs:\n```\ntypedef struct _Ball{\n    // Position\n    double x;\n    double y;\n    // How we display the ball\n    char * avatar;\n    // Speed (What we add to the x and y each loop iteration)\n    double speedX;\n    double speedY;\n\n    int colorPair;\n} Ball;\n\ntypedef struct _Window {\n    int height;\n    int width;\n    int sleepTime;\n    int numBalls;\n    Ball * balls;\n} Window;\n```\n\n## Conclusion\nHopefully this guide successfully illustrated how to make games for the terminal, and good strategy for constructing them. If you have any questions or suggestions please contact me!\n"
  },
  {
    "path": "examples/BouncingO.c",
    "content": "#include \"stdio.h\"\n#include \"stdlib.h\"\n#include \"unistd.h\"\n#include \"ncurses.h\"\n\n// Stores our balls position\ntypedef struct _Ball {\n    int x;\n    int y;\n} Ball;\n// Stores the direction that the ball is moving\ntypedef struct _Direction {\n    int x;\n    int y;\n} Direction;\n\nint main() {\n    initscr();              // Start ncurses\n    nodelay(stdscr, TRUE);  // Don't wait for \\n for getch to parse input\n    cbreak();               // Switch off input buffering\n    curs_set(FALSE);        // Don't place a cursor on the screen\n\n    int height = 0;         // Window height\n    int width = 0;          // Window width\n\n    // initialize our ball struct and direction struct\n    Ball b = {\n        1,1\n    };\n    Direction d = {\n        1,1\n    };\n\n    // Get terminal window dimensions (rows and characters)\n    getmaxyx(stdscr, height, width);\n\n    while (getch() == ERR) {\n        // print ball\n        mvprintw(b.y,b.x,\"o\");\n\n        // move ball for next frame\n        b.y += d.y;\n        b.x += d.x;\n\n        // Check for ball being outside of our window boundaries\n        if (b.x == width - 1 || b.x == 0){\n            // change direction\n            d.x *= -1;\n            b.x += d.x;\n        }\n        if (b.y == height - 1 || b.y == 0){\n            // change direction\n            d.y *= -1;\n            b.y += d.y;\n        }\n\n        refresh();      // Refresh the output\n        usleep(50000);  // Sleep to show output (Single frame)\n        clear();        // Clear output\n    }\n    destroyWindow(&w);\n    endwin();\n    return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "examples/helloWorld.c",
    "content": "#include \"stdio.h\"\n#include \"stdlib.h\"\n\nint main() {\n    printf(\"Hello World!\\n\");\n    return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "examples/helloWorldNew.c",
    "content": "#include \"stdio.h\"\n#include \"stdlib.h\"\n#include \"ncurses.h\"\n\nint main() {\n    initscr();\n    mvprintw(5,5,\"Hello World!\");\n    refresh();\n    getch();\n    endwin();\n    return EXIT_SUCCESS;\n}\n"
  }
]