瀏覽代碼

Again, minor revision...

master
父節點
當前提交
642459a19c
共有 11 個文件被更改,包括 121 次插入16 次删除
  1. +4
    -1
      chapter/chapter_2.c
  2. +13
    -10
      chapter/chapter_3.c
  3. +6
    -3
      chapter/chapter_3.h
  4. +1
    -1
      chapter/chapter_x.c
  5. +1
    -1
      chapter/chapter_y.c
  6. +49
    -0
      program/program_2.c
  7. +7
    -0
      program/program_3.c
  8. +7
    -0
      program/program_4.c
  9. +7
    -0
      program/program_5.c
  10. +7
    -0
      program/program_6.c
  11. +19
    -0
      program/program_z.c

+ 4
- 1
chapter/chapter_2.c 查看文件

@@ -355,7 +355,7 @@ void curses_synchronize (void) {
curses_character = signal; // We need literal value of 'signal' for text input.

if (signal == '\033') { // And then we modify the actual 'curses_signal'.
curses_signal |= SIGNAL_ESCAPE;
curses_signal = SIGNAL_ESCAPE;
} else if (character_is_digit ((char) signal) != 0) {
curses_signal |= SIGNAL_0 + (int) (signal - '0');
} else if (character_is_lowercase ((char) signal) != 0) {
@@ -363,6 +363,8 @@ void curses_synchronize (void) {
} else if (character_is_uppercase ((char) signal) != 0) {
curses_signal |= SIGNAL_A + (int) (signal - 'A');
curses_signal |= SIGNAL_SHIFT;
} else if ((signal == SIGNAL_ARROW_UP) || (signal == SIGNAL_ARROW_DOWN) || (signal == SIGNAL_ARROW_RIGHT) || (signal == SIGNAL_ARROW_LEFT)) {
curses_signal = signal;
} else {
curses_signal = SIGNAL_NONE;
}
@@ -370,6 +372,7 @@ void curses_synchronize (void) {
for (signal = 0; signal != curses_action_count; ++signal) { // Now, it's time to loop over bound actions.
if (curses_signal == curses_activator [signal]) { // If we have a bound signal, then:
curses_action [signal] (); // We execute corresponding action (function).
break;
}
}



+ 13
- 10
chapter/chapter_3.c 查看文件

@@ -35,12 +35,6 @@ can fall-through, like in the example below. Sad truth is, people are dumb, and
case(s) in your switch statement. Lets explain what 'echo_one_by_one' function would do.

@C
// Print out some stuff, it'll look like this for these inputs (and it'll do nothing for input that isn't between 0 and 3 (inclusive)):
// echo_one_by_one (0) => "Zero One Two Three"
// echo_one_by_one (1) => "One Two Three"
// echo_one_by_one (2) => "Two Three"
// echo_one_by_one (3) => "Three"

static void echo_one_by_one (int number) {
switch (number) {
case 0: echo ("Zero ");
@@ -50,13 +44,18 @@ static void echo_one_by_one (int number) {
default: break;
}
}

// Print out some stuff, it'll look like this for these inputs (and it'll do nothing for input that isn't between 0 and 3 (inclusive)):
// echo_one_by_one (0) => "Zero One Two Three"
// echo_one_by_one (1) => "One Two Three"
// echo_one_by_one (2) => "Two Three"
// echo_one_by_one (3) => "Three"
@

You can find situations in which fall-through cases are good, for example, they can be very useful when encoding some CPU instructions into machine code, but guess what? The
compiler will think you've made some kind of mistake, like that you forgot to break from those cases, and it'll warn you about it. I like to clean all compiler warnings (and some
linter warnings, if they're not totally brain-dead), so I just don't use them. I know, sounds stupid, but there's usually some other way to do it, to get the same solution.

Since we have several methods for printing text, they use standard output (terminal), file descriptor and a string respectively, we could implement them in separate functions, use
linter warnings, if they're not totally brain-dead), so I just don't use them. I know, sounds stupid, but there's usually some other way to do it, to get the same solution. Since
we have several methods for printing text, they use standard output (terminal), file descriptor and a string respectively, we could implement them in separate functions, use
function pointers or simply copy+paste bunch of code into lot of functions, and form a "function family". Lets do something very simple and straight forward. We'll end up with
repeated code, but sometimes the simplicity can benefit us more than some smart solutions that are harder to understand. I'll explain as we progress...
*/
@@ -68,7 +67,8 @@ static void to_string (char * data, int size, int file, char * string) { (void)
/*
Lets break down what's going on here, since it might be confusing for beginners. We've defined 3 internal functions, that'll only be used in this file and no other. They look
similar, and they ignore some of their arguments by casting them to 'void', that's how you silence the compiler warnings about unused function agruments. But why are we passing
those arguments if we won't use them? Because we can safely use one function pointer to any of those 3 functions.
those arguments if we won't use them? Because we can safely use one function pointer to any of those 3 functions. Now, before we proceed, variables can hold memory addresses of
other variables, constants and functions. We use that fact now.

Internal variable 'printing' is a function pointer to one of those 3 functions, and the default value for it is the memory address of function 'to_output'. So, if we just use it,
by default it'll print to standard output. If we call functions below, they'll change the value of 'printing' to coresponding function memory address. I chose to use concatenation
@@ -184,6 +184,9 @@ void print (char * format, ...) {
va_end (list); // Every variadic function needs to end with this macro... Pun intended.
}
@

Also, needless to say, I don't usually align nor write my programs like this, I did it so you can compare those 3 functions easier. You can see what's changed, what's ignored or
what's same. If you're writing something serious, align it properly, not like this please.
*/

void print ( char * format, ...) { va_list list; printing = to_output; va_start (list, format); print_select (format, list, 0, NULL); va_end (list); }


+ 6
- 3
chapter/chapter_3.h 查看文件

@@ -76,14 +76,17 @@ printf ("Heyo world!");
@

Now, don't get scared, C is old language, and I'm aware that this looks like someone made a joke 50 years ago and nobody understood it, they took it serious. In the end, variadic
argument list type 'va_list' is black magic, as well as other 'va_*' stuff. Since 'va_arg' takes only fully promoted types, we're left with types 'int', 'double' and 'char *'
pretty much. Also, keep in mind that you don't need more arguments in 'printf' function, only that "const char * fmt" needs to be there always. It may take some time to get used
to this function, but you can use it for very quick and easy debugging. If you're not sure what value your variables hold at some point, you can just print it there.
argument list type 'va_list' is black magic, as well as other 'va_*' stuff. Since 'va_arg' takes only fully promoted types, we're left with types 'int', 'double', 'void *' and
'char *'. Also, keep in mind that you don't need more arguments in 'printf' function, only that "const char * fmt" needs to be there always. It may take some time to get used to
this function, but you can use it for very quick and easy debugging. If you're not sure what value your variables hold at some point, you can just print it there.

I'll show you how to implement variadic argument functions, and we'll use these in few places, but I'm still not a big fan of them. Of course, we won't implement everything that
'printf' function from standard library has, or any more of its' alternatives, just these three below. However, we'll add few small additions, like colouring text with ASCII
escape sequences and doing some basic formatting. Once you learn C better, you should take a look at manual pages for functions that you find interesting. Or even better, instead
of reading stuff, try to implement them yourself, it's the best approach to learning anything.

If you wonder why did we cover curses in chapter two, and printing in chapter three, which is simpler and shorter essentially, it's because curses use few "black magic" functions
from header file <termios.h>, while printing uses <stdarg.h>, which is more difficult to use. We'll use it more in later chapters, but only as a show-case.
*/

extern void print ( char * format, ...); // Notice the "...", which means it can accept any amount of arguments after that 'format'.


+ 1
- 1
chapter/chapter_x.c 查看文件

@@ -9,7 +9,7 @@ It is distributed in the hope that it will be useful or harmful, it really depen
#ifndef CHAPTER_5_SOURCE
#define CHAPTER_5_SOURCE

#include "chapter_5.h"
#include "chapter_x.h"

/*
So, what are actually getters and setters, and why you should never use them? Lets explain.


+ 1
- 1
chapter/chapter_y.c 查看文件

@@ -9,7 +9,7 @@ It is distributed in the hope that it will be useful or harmful, it really depen
#ifndef CHAPTER_6_SOURCE
#define CHAPTER_6_SOURCE

#include "chapter_6.h"
#include "chapter_y.h"

#define UNUSED(variable) (void) variable



+ 49
- 0
program/program_2.c 查看文件

@@ -0,0 +1,49 @@
/*
Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic

Xhartae is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation.
And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version.
It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3.
*/

#include "../chapter/chapter_0.c"
#include "../chapter/chapter_1.c"
#include "../chapter/chapter_2.c"

static int player_x = 0;
static int player_y = 0;

static void player_move_up (void) { player_y -= 1; limit (& player_y, 0, curses_screen_height - 1); }
static void player_move_down (void) { player_y += 1; limit (& player_y, 0, curses_screen_height - 1); }
static void player_move_left (void) { player_x -= 1; limit (& player_x, 0, curses_screen_width - 1); }
static void player_move_right (void) { player_x += 1; limit (& player_x, 0, curses_screen_width - 1); }

int main (void) {
terminal_show_cursor (FALSE);

curses_configure ();
/*
curses_bind (SIGNAL_ARROW_UP, player_move_up);
curses_bind (SIGNAL_ARROW_DOWN, player_move_down);
curses_bind (SIGNAL_ARROW_LEFT, player_move_left);
curses_bind (SIGNAL_ARROW_RIGHT, player_move_right);
*/
while (curses_active) {
curses_render_background ('.', COLOUR_GREY, EFFECT_BOLD);
curses_render_character ('@', COLOUR_CYAN, EFFECT_BOLD, player_x, player_y);

switch (curses_character) {
case 'w': player_move_up (); break;
case 'a': player_move_down (); break;
case 's': player_move_left (); break;
case 'd': player_move_right (); break;
default: break;
}

curses_synchronize ();
}

terminal_show_cursor (TRUE);

return (EXIT_SUCCESS);
}

+ 7
- 0
program/program_3.c 查看文件

@@ -0,0 +1,7 @@
/*
Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic

Xhartae is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation.
And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version.
It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3.
*/

+ 7
- 0
program/program_4.c 查看文件

@@ -0,0 +1,7 @@
/*
Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic

Xhartae is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation.
And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version.
It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3.
*/

+ 7
- 0
program/program_5.c 查看文件

@@ -0,0 +1,7 @@
/*
Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic

Xhartae is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation.
And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version.
It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3.
*/

+ 7
- 0
program/program_6.c 查看文件

@@ -0,0 +1,7 @@
/*
Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic

Xhartae is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation.
And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version.
It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3.
*/

+ 19
- 0
program/program_z.c 查看文件

@@ -0,0 +1,19 @@
/*
Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic

Xhartae is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation.
And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version.
It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3.
*/

#include "../chapter/chapter_0.c"
#include "../chapter/chapter_1.c"
#include "../chapter/chapter_2.c"
#include "../chapter/chapter_x.c"
#include "../chapter/chapter_y.c"

int main (void) { // EXPERIMENTAL (WILL BE DELETED)...
play_game ();

return (EXIT_SUCCESS);
}

Loading…
取消
儲存