Itsy's Janky Code Blog

... sit down, kick back and relax, and talk about anything that doesn't belong on one of the other forums.
Prykor
Posts: 61
Joined: Thu Jan 06, 2022 8:56 pm

Re: Itsy's Janky Code Blog

Post by Prykor » Wed May 25, 2022 9:54 am

I know it's a blog and you aren't here soliciting feedback, but I enjoy being a mixture of peanut gallery and good idea fairy that [s]sabotages[/s]helpfully expands the scope of projects!
Itesh wrote:
Wed May 25, 2022 7:18 am
I can't really decide on any of them, so this seems like someone else's problem: I dump options into Imm chat and solicit opinions like a cheap intellectual floozy.

And now we play the waiting game.
Perhaps I'm missing something, but 1 and 2 look identical to me.
The first two would be better for dumping to a text file following a specific person, and the second more useful for observing in real time through a telnet-style MUD interface. I'm not sure what options you guys have for the former, or if you see value or a use case for putting a watch on a specific person to dump to a log to check in at a later time to see what happened.
Itesh wrote:
Wed May 25, 2022 7:44 am

And then do this: clan_abbreviations[CLAN ID NUMBER]. And that's fine, I guess, but there's 78 clans and the thought of actually writing that all out makes me want to cry.
Could you grab the tag system that's on the who list that denotes [clan name] next to people?

Itesh
Posts: 807
Joined: Sat Feb 14, 2015 4:59 am

Re: Itsy's Janky Code Blog

Post by Itesh » Wed May 25, 2022 10:21 am

Prykor wrote:
Wed May 25, 2022 9:54 am
Perhaps I'm missing something, but 1 and 2 look identical to me.
You are missing something - one uses printed race, like 'Hu' for human - and the other factional designations like 'LS'. Also some minor letters missing. I think.
Prykor wrote:
Wed May 25, 2022 9:54 am
Could you grab the tag system that's on the who list that denotes [clan name] next to people?
This is what happens at the moment, and what I'm trying to provide a shorter, better version of. :)

Itesh
Posts: 807
Joined: Sat Feb 14, 2015 4:59 am

Re: Itsy's Janky Code Blog

Post by Itesh » Sat May 28, 2022 11:38 am

A tiny amount of tinkering gives us a shorter report string today:
[SAY: Testone drones 'testing testing one two three' | m51H no clan R1020]
[SAY: Testone drones 'It was the best of times, it was the worst of times. Seanchan was newly implemented, and for some reason instead of making a new clan structure we tried to shoehorn everything in with the old one, which was madness. The Empress was actually Bela, and everyone tried hard to avoid being purple trollocs, to no avail.' | m51H Seanchan Imperial Guard R1020]
Just knocked that out in an off minute and didn't really have time to update it fully.

Itesh
Posts: 807
Joined: Sat Feb 14, 2015 4:59 am

Re: Itsy's Janky Code Blog

Post by Itesh » Sat May 28, 2022 3:47 pm

Today (well, this evening, actually) I'll be taking some time to work on and explain for you all a new command I'm working up for Grey Men - the stalk command.

The command is actually basically done - I got the bulk of it completed around November 2021 - but it's been a while since I worked on it and other things have happened in the game since then, so the first thing I do is bring it back up to date with the master branch. Thankfully this proceeds without a hitch and as far as I can tell the master branch still exists, so I remain unfired for another day.

Here is what the stalk command does - copied from my comment above the function:

Code: Select all

/* Itesh 2021-11-15 stalk command for Gray Men:
  -- sets a target against whom you have some locate ability (eg "far southwest or similar")
  -- and OB bonuses ( 5 + clanlevel )
  -- and limited target switching ( only TO target ) */
This might not actually be all it does at the moment, and I'm going to have read the code to check because as I frequently state I cannot remember last week usually, let alone last November.

So How Does This Work?

Well, pretty simply, actually.

First of all, we add three variables to the runtime-only (i.e not saved to playerfile) section of player memory. We don't need to save this at all, so using runtime data keeps things pretty simple and saves me from having to actually learn file saving and loading properly. Hurray!

We add:
- 1 int variable, probably called something like stalking_count
- 1 pointer to character data called something like "stalking"
- 1 pointer to character data called something like "stalked_by"

So we can keep count of how many successful stalks we've managed, and store pointers both to the person we are stalking, and the person that is stalking us.

Why do we need to store a pointer to the person stalking us? (you might ask)

Okay, let's imagine X is stalking Y. X has their pointer to Y saved:

Code: Select all

X->stalking = Y;
Now, for instance, you can do stuff like this:

track(X->stalking) and you'll track where Y is. This is a made up function, by the way, that's not how track works.

Another example - X is fighting, and we need to check whether X is fighting the person they are stalking:

Code: Select all

if ( victim == X->stalking) {
    DO ALL THE THINGS;
}
Y has a pointer pointing back to X:

Code: Select all

Y->stalked_by = X;
Why might you need that? Here's one obvious example: Y logs off. Should we tell X their victim has gone? Probably, I would think. If you have a pointer, as part of the logoff process you can do something like this (and please appreciate I'm writing in shitty pseudocode here)

Code: Select all

Y->stalked_by->stalking = NULL;
That's cleared X's pointer - because Y->stalked_by *is* X.

If we didn't have that pointer pointing backwards, the only other way I could see to do this would be to iterate through every single person online, checking their stalking pointers to see if they point to Y. So that's like, I dunno, 20-30 operations instead of 1.

Plus I copy a lot of my code and some other stuff is already set up this way, so it seems like best practice...

So structurally that's more or less how it's set up. There's a stalk command of course, and it has a bunch of checks - am I even a Grey Man? Am I trying to stalk an NPC (because lol no). Is your victim fighting?

If we get through the checks, you get some flavour text depending on your stalk count. At the moment it's one message for 0 and a different one for anything else:
You start to prey on %s.
You refine your approach to your prey.
...It's not very inspired at the moment, I know. For those of you unfamiliar with some of the C library functions, the %s token just means that at a later point, some variable or other will be slotted in there - in this case, our victim's name.

After this, one final quick quick that makes sure that the person we are now stalking is the same as the person we were stalking last time. And actually, it occurs to me that that should probably happen one block higher, before the text I've just mentioned.

TIMER TIMER WOOP WOOP er I mean, so we do a timer. And the length is dependent on the amount of 'stalks' you already have on the victim, and very mildly affected by your clan rank. Not, you know, that I've set up a clan for Grey Men yet, because I haven't, but I will definitely get to that.

The timer length is:

Code: Select all

MAX(8,6+(GET_STALKING_COUNT(ch) * GET_STALKING_COUNT(ch)) - GET_CLANLEVEL(ch))
So er. Jesus. How does this work again? I'm sure I had a spreadsheet of this.

Okay so I junked the spreadsheet because I am an imbecile, but I found an embed of it in the Grey Man test discord, and now I'm typing numbers from a split screen like a pleb:

Code: Select all

	0	1	2	3	4	5	6	7	8	9
stalks
0	8	8	8	8	8	8	8	8	8	8
1	8	8	8	8	8	8	8	8	8	8
2	10	9	8	8	8	8	8	8	8	8
3	15	14	13	12	11	10	9	8	8	8
4	22	21	20	19	18	17	16	15	14	13
5	31	30	29	28	27	26	25	24	23	22
I expect there's zero chance this will render nicely on forums. Zero.

Cards on the table, I basically just ad-libbed the equation for this: my only objectives were to make higher-number stalks take an increasingly long time, and for clan rank to slight ameliorate the situation. Getting a really snazzy well-researched equation wasn't as important at the time as just getting it all to work.

You can have max five stalks, obviously. The first stalk sets your target, and subsequent stalks increment your count, so actually stalks = 1 means you've stalked *twice*. And this may be a stupid way to do it.

Post-timer, we have some flavour messages:
"You settle %s's routines in your mind, committing $S habits and routines to memory."
That $S will get replaced with an appropriate pronoun for your victim, depending on their gender.

So About This Locating Ability?

Yes, right. So, it seems logical to tie this to the sense command, which at the moment is Fade-only. I swift burst of logic that literally says 'if Grey Man, do this thing instead' forks us off to a completely different function which I am not ashamed to admit is a complete and utter copy of the innards of Locate Life - just using your stalking target as a, well, target.

If you don't have a target, it turns out I was feeling sassier than normal on the day I did this:
You sense nothing... except Shai'tan's disappointment.
...and other than that, it's *basically* the same as Locate Life, with the exception that the functional range is set to 5 + stalking count.

Zones have cartesian co-ordinates, and the distance is calculated thusly... you know what, actually, I'm writing this in Notepad and the symbols aren't there. Here is an online calculator: https://www.calculatorsoup.com/calculat ... points.php

I can't do the maths, and the mud already has functions built in that do it! The real point is, zones have a range from one another, and Locate Life - and therefore, Grey Man sensing, has a range. Bleh, maths.

FWIW, Locate Life has a lot better range than the Grey Man version. And I'm not fixed on 5 + stalk number, either. We could wind that back, nothing is certain.

This version has port codes stripped out, of course, because those are pointless,

This is what it looks like - bear in mind this is from an early version, where the Dark One would select you a target at random. We don't do that any more.
HP:Healthy MV:Fresh > sense
You sense nothing... except Shai'tan's disappointment.

HP:Healthy MV:Fresh > stalk
The Great Lord speaks in your mind:
"END THE LIFE OF Testone, WORM.
"
HP:Healthy MV:Fresh > sense
Testone - somewhere around here.
And Those OB Bonuses?
I haven't coded this yet. My feeling is, that OB is recalculated for each person at the start of each combat round. We only want the Grey Men to have extra OB against their actual targets (because they're assassins, right?)

So in each call to calculate player bonuses, we're going to have to write something like this:

Code: Select all

if ( is_fighting(gman) && gman->opponent == gman->stalking) {
OB = 5 + get_stalking_count(gman);
}
...and that'll probably work. I'll want to talk through those numbers with someone though. A max of 10 extra OB might be a bit too much. We could do something like get_stalking_count * 3 / 2:

Code: Select all

Stalks	OB
1	1
2	3
3	4
4	6
5	10
...which works kind of okay until you get to then, and then there you are too high again. But we have options, like doing a classic Aureus:

Code: Select all

MIN(8, get_stalking_count *3 /2);
It's not really a classic Aureus because I understand what I just did and thinking through that equation doesn't summon Elder Gods from the Cthonic realms.

Edit: Shout out to Yeri for pointing out that my maths is wrong in the example above which I claimed to understand! :P

And the Target Switching...

Okay that one IS easy - the code is already there for Fade target switching, so just add another case to that where it checks that the person you're trying to switch to is your stalking target, and if it is, then do the necessary. Keep that focus on your target.

And that's basically it, so far. I'm more or less finished, except...

No Really, What Haven't You Done?

I basically just haven't dealt with clearing the pointers whenever anyone logs off or quits. So at the moment it's fine, except, you may try and follow a pointer to a character who is no longer in memory. And That Would Be Bad.

I was going to fix that tonight, but for the last hour or so Spawn has been resisting the idea of going to actual bed, so I'm going to eat ice cream instead.

Edit: Why Did You Do This?

Well, Grey Men were feeling a little underpowered in combat versus the other remorts. And this *might* help, versus their actual targets, at least. And it's kinda cool. It synergizes nicely with Shadowmask, which will give you the opportunity to hang around people running secret timers on them. I guess we'll see how it pans out, in testing.

Itesh
Posts: 807
Joined: Sat Feb 14, 2015 4:59 am

Re: Itsy's Janky Code Blog

Post by Itesh » Sun May 29, 2022 11:34 am

Flash merged 9 branches last night, so today I'm going to take a brief look at what I currently have in the queue, and more importantly, whether any of it's actually been rejected by Aureus (because some of it definitely has) and whether I can fix it.

It turns out I have four things in the queue at the moment:

1: Gender neutral pronouns (approved)
2: Object stats on examine (approved)
3: Attach player names to butchered limbs (changes requested, that monster)
4: automatic clan rank cleanup (approved, but, waiting for Flash since November 2020, so probably dead at this point)

I'll look at the limb thing first, which I bring up to date with master with a quick mergeroony.

Then, onwards to work out what the hell Aureus was talking about! Luckily this is all in one file, so it might not be too complicated. Maybe.

First of all, he points out that the bool I'm declaring is unncessary, since I'm only using it once, and the condition I'm checking for could probably be used in its place. This is probably true, so I'll just do what he wants, which involves finding the singular reference to this variable and replacing it with the line I ran the if on earlier to set the variable to true - if that makes sense.

I quickly test that in the VM, and because I cannot be bothered to mess around excessively I just copy the entire butcher function over.

...^ is what I wrote before realising that one of the pointers is recycled and doing it Aureus' way will actually break EVERYTHING. So astonishingly, I actually reject this comment. This has never happened before and I cannot shake the feeling that I am still somehow wrong. Which is probably true.

Trying to work out why I did any of this this way last November is actually pretty challenging, NGL.

After (kinda) adding an NPC check in a place that needs one, I attempt to deal with the second to last complaint, which is that my method of name-storing is inefficient, given the corpse stores the ID number and we can fetch the name from the ID. Apparently, and I say that because I can't work out how to do that, and resolve to just ask Aureus when he sobers up.

Finally, I free something that he told me to free, without worrying much about it other than that.

That was a lie, I worry about it and end up dropping Aureus a message. Because the issue is about freeing 'name' because of strdup using malloc, but I'm using strdup on 'buf' and writing to a part of the corpse and I don't see that 'name' is involved at all. I suspect he'll have to explain again in very small words.

It turns out 'gender neutral pronouns' can't be brought up to date with master without some extra work - not sure what that's going to involve. 'Object stats on examine' can, so I do. And with some trepidation I attempt to do it with 'auto clan cleanup', the oldest branch. No dice. So that's another job.

I manage to resolve the conflicts in Gender Neutral Pronouns in VSC. Astonishingly, the only conflict is that Aureus has added his name to the file credits in a place where I have also indulged my own massive ego in adding my name to the file credits. This process is terrifying and makes me worry I'm about to delete the MUD, like, A LOT.

So obviously before I tackle doing that for auto clan cleanup, I go and make dinner. It's pork steaks with onion marmalade and cheese on them, from Hello Fresh.

Detritus
Posts: 261
Joined: Thu Aug 06, 2020 8:22 am

Re: Itsy's Janky Code Blog

Post by Detritus » Sun May 29, 2022 9:02 pm

I love this blog, particularly some of the posts like the last which makes me think of some of my university classes and my interactions with TAs and tutors.

Making C+ projects work and TAs always saying that's great and more than we asked for but you really should redo it xyz way.

Itesh
Posts: 807
Joined: Sat Feb 14, 2015 4:59 am

Re: Itsy's Janky Code Blog

Post by Itesh » Sun Jun 05, 2022 4:50 pm

I've had a smol brainwave about the clan tag issue for the Watcher Log, which is that I'll just code a function that returns the first letter of each word in the clan name as an acronym. I'm going to knock that up now in a non-mud version, and because it's non-codebase I can show you the C! WHAT A DELIGHT FOR YOU.

Okay. Christ.

So I knock together a quick program just to quickly check I've remembered how to make strings:

Code: Select all

#include <stdio.h>

int main(void) {

    char * clan_name = "Defenders of the Stone";

    printf("The clan we're talking about is %s.\n",clan_name);
    
}
So what's happening here is:

1: we include the stdio.h header file so we can use the printf function.
2: We declare the main function - main is a special function that will be the one run automatically when we compile. We say that it returns an 'int': when it finishes, it'll send a 0 to the computer. In the parentheses, we write 'void', which just means that this function is not taking any arguments. And then we open the curly braces of destiny.
3: We define a string called 'clan_name' and store 'Defenders of the Stone' in it. Strictly speaking C doesn't have a 'string' type, so what we're actually doing is declaring a pointer to a character and then glueing "Defenders of the Stone into memory. The pointer points to the initial letter, but...
4: We tell printf to expect a string with the %s token, so it starts at the pointer we give it (clan_name) and then, and this is the crucial bit, it keeps printing until it hits the NULL character. But wait Itesh, you said nothing about NULL! And that is true, but here we go: when you use double quotes in C, it tells it 'here is a string' and it null-terminates it for you automatically.

"Defenders of the Stone" stores "Defenders of the Stone\0"

\0 is how NULL is written. If your strings don't end in NULL, somehow, Bad Things Happen.

Output:
The clan we're talking about is Defenders of the Stone.
Output if we wrote %c (for character) instead of %s (for string)
The clan we're talking about is D.
And what if we type this?
printf("The clan we're talking about is %s.\n",clan_name + 1);
The clan we're talking about is efenders of the Stone.
Pointers are fun, huh?

Onwards - A bit More Faffing Around to Check Everything Works Like I Think It Does

Code: Select all

#include <stdio.h>

char * return_clan_acronym(char * clan_name_string); // note 1

int main(void) {

    char * clan_name = "Defenders of the Stone";

    printf("The clan we're talking about is %s.\n",return_clan_acronym(clan_name)); // note 3
    
}

char * return_clan_acronym(char * clan_name_string) {

    return "Illian Companions"; // note 2

}
1: This is a function 'declaration' (or 'prototype'). It basically says 'don't worry Compiler, I'm going to explain how this function works later in the file. If I had written the function *above* 'main' I wouldn't need to do this but I'd rather keep things in their logical order.
2: This is the function 'definition' - the bit where all the work is done. We're returning a pointer to a string (Illian Companions, in this case), and takes a char * - you know what, I'm just going to say string from now on - it takes a string as an argument. Which it will refer to internally as 'clan_name_string'. We do *nothing* with this, and return 'Illian Companions' no matter what.
3: I've made this look more complex than it is - what we're passing to %s is whatever comes back from return_clan_acronym when we send return_clan_acronym whatever is stored in clan_name. And per note 2, what's coming back is 'Illian Companions'.

Test Compile:
The clan we're talking about is Illian Companions.

[Done] exited with code=0 in 0.641 seconds
The basic structure looks fine, so let's write the damn function!

First of all we need somewhere to store our new acronym, so I declare an array of type char and set the size arbitrarily at ten elements. This should be far too much space.

char acronym[10]

...C doesn't initialise variables to 0, generally, and out of curiosity I quickly print the contents of this array:
64
0
-48
-2
97
0
8
-1
97
0
Classic C.

It occurs to me that while it's staggeringly unlikely that we'll run out of space, we probably should make sure, so we need to count the number of words in the string. And I'm awful so we're doing that the quick and lazy way, which is to define a variable called 'words', set it to 1, then scan over the whole string and count spaces and add them to 'words'.

Code: Select all

char * return_clan_acronym(char * clan_name_string) {

    #define MAX_ACRO_LENGTH 10 // note 1

    char acronym[MAX_ACRO_LENGTH]; //note 2
    int words = 1;
    int i = 0;

    while (*(clan_name_string + i) != '\0') { //note 3
        if (*(clan_name_string + i) == ' ') { // note 4
            words++; // note 5
        }
        i++; // note 6
    }

    if (words >= MAX_ACRO_LENGTH) {
        return "ERROR: Max Length Exceeded.\n";
    }
    else {
        printf("%s has %i words.\n", clan_name_string, words);
    }

    return "Illian Companions";

}
1: This is like a mud alias - as part of compiling (during preprocessing) anywhere this phrase appears gets replaced with 10.
2: Like here, for instance.
3: This reads awfully, but it says 'go through our string letter by letter until we hit the null character at the end'
4: This says 'hey, that letter we're looking at, is it a space?
5: If it *is* a space, add 1 to words. words++ is the same as writing words = words + 1.
6: Add one to i, which is what we're using to skip merrily through the letters.

Test Compile:
Defenders of the Stone has 4 words.
The clan we're talking about is Illian Companions.

[Done] exited with code=0 in 0.245 seconds
Works, astonishingly. I mean, I'm not telling you about the two domestic rooster-ups during compilation, obviously.

So, how are we going to get our acronym? Well, we're *already* looping through the string, and we don't really want to do that twice, so maybe we can do double duty as we loop through?

First of all, we need to keep track of where our next character is going into our array for the acronym. We already have i as an iterator, so in common with hard-to-read convention, we'll use j. I declare that, and assign it the value 1. We already know that the first letter of the clan name is going in [0], so j is keeping the position warm for the *next* letter.

We add a line, something like:
acronym[0] = *clan_name_string;
My hope is that this will work, since it's really only pointing at a single character. But I don't really know, so I'm going to test it thusly:

Code: Select all

    printf("First letter is %c.\n", acronym[0]);
First letter is D.
Defenders of the Stone has 4 words.
The clan we're talking about is Illian Companions.

[Done] exited with code=0 in 0.256 seconds
I'm pretty astonished this works, but okay!

So we need to find the first character of the next word and bear with me here. If a space is at clan_name_string + i, then the next letter is at clan_name_string + i + 1. Yeaaaaah pointers are fun, aren't they!

We need to do this in the existing if, so not only do we increment 'words', we also do that deeply suspicious thing I just said, then remember to move j up by one for the next letter.

A test compile reveals a problem:
acro.c:41:12: warning: function returns address of local variable [-Wreturn-local-addr]
41 | return acronym;
| ^~~~~~~
So I add the keyword static to the array declaration, which makes the array not get destroyed after function end, and everything compiles and runs correctly. This might not be the best solution to this problem and I'm going to bend Aureus' ear about later, but for now it'll do.
First letter is D.
Defenders of the Stone has 4 words.
The clan we're talking about is DotS.

[Done] exited with code=0 in 0.258 seconds
Doing it this way has actually rendered that length check utterly useless, so we move to inside the while loop.

A quick test for the new name length checker:

Code: Select all

    char * clan_name = "Defenders of the Stone Which Definitely Does Not Suffer From Erosion and Has Few Issues With Acid Rain";
The clan we're talking about is ERROR: Max Length Exceeded.
...and a quick check with some one-word clans like Gleemen, Wisdoms etc.
The clan we're talking about is W.
...which seems fine.

And so here's the final program:

Code: Select all

#include <stdio.h>

char * return_clan_acronym(char * clan_name_string);

int main(void) {

    char * clan_name = "Children of the Light";

    printf("The clan we're talking about is %s.\n",return_clan_acronym(clan_name));
    
}

char * return_clan_acronym(char * clan_name_string) {

    #define MAX_ACRO_LENGTH 10

    static char acronym[MAX_ACRO_LENGTH];
    int words = 1;
    int i = 0;
    int j = 1;

    // assign first letter
    acronym[0] = *clan_name_string;

    // scan through string 
    while (*(clan_name_string + i) != '\0') {
        if (*(clan_name_string + i) == ' ') {
            // if we find a space we use the next char
            acronym[j] = *(clan_name_string + i + 1);
            words++;
            j++;
        }
        if (words >= MAX_ACRO_LENGTH - 1) {
            return "ERROR: Max Length Exceeded";
        }
        else {
            i++;
        }
    }

    return acronym;

}
Which at the moment, with CoL, is returning this:
The clan we're talking about is CotL.

[Done] exited with code=0 in 0.58 seconds
And so I guess this works!

Okay so about those *s...

C uses the * symbol in three seperate and entirely different ways, which is what's making some of this hard to read.

1: Maths
1 * 2, or x * y. It works how you'd expect.

2: Pointer declarations
int * p;
This means we have created a pointer called p, and it will point to ints.

3: Actually following that pointer:
if ( *p == 3 )

p is pointing at something in memory. The actual value of p is that memory address. if we want to look at what p is pointing at, we preface p with an asterix. This looks unhelpfully like the pointer declaration.

For more information see literally any C tutorial which will explain this far better than I just did. Because I did it *poorly*.

Itesh
Posts: 807
Joined: Sat Feb 14, 2015 4:59 am

Re: Itsy's Janky Code Blog

Post by Itesh » Mon Jun 06, 2022 8:38 am

Detritus wrote:
Sun May 29, 2022 9:02 pm
I love this blog, particularly some of the posts like the last which makes me think of some of my university classes and my interactions with TAs and tutors.

Making C+ projects work and TAs always saying that's great and more than we asked for but you really should redo it xyz way.
You'll be glad to know my co-coder's response to the last bit of code was "That's not that bad, actually, but you should scan for apostrophes as well so you cover Morat'raken (Mr), Morat'torm (Mt), Dha,vol (Dv) etc".

And he's not wrong at all, so:

This line:

Code: Select all

if (*(clan_name_string + i) == ' ') 
Gets changed to:

Code: Select all

if ((*(clan_name_string + i) == ' ')  ||  (*(clan_name_string + i) == '\'') )
... which'll probably work, and which I'll test later.

Jomin
Posts: 159
Joined: Thu Feb 19, 2015 3:54 pm
Location: White Tower Libraries or Deepest Wiltshire, UK

Re: Itsy's Janky Code Blog

Post by Jomin » Fri Jun 10, 2022 9:28 pm

Regarding this function:

Code: Select all

char * return_clan_acronym(char * clan_name_string) {

    #define MAX_ACRO_LENGTH 10 // note 1

    char acronym[MAX_ACRO_LENGTH]; //note 2
    int words = 1;
    int i = 0;

    while (*(clan_name_string + i) != '\0') { //note 3
        if (*(clan_name_string + i) == ' ') { // note 4
            words++; // note 5
        }
        i++; // note 6
    }

    if (words >= MAX_ACRO_LENGTH) {
        return "ERROR: Max Length Exceeded.\n";
    }
    else {
        printf("%s has %i words.\n", clan_name_string, words);
    }

    return "Illian Companions";

}
  • If you define this function before you use it - i.e. list it above the main(...) one then you do not have to declare it first in this trivial test code...
  • You really ought to remove a space around the '*'s that are used to indicate pointer types, either make them butt up against the type declaration (the char) or the variable/function identifier (e.g. the clan_name_string) - leaving it floating in mid-air is just asking for it to be forgotten somewhere - which can have nasty effects!
  • as a C "string" is actually a C "array" of "char" type variables - so instead of explicitly showing the pointer arithmetic as "*(clan_name_string + i)" you can be slightly more terse, and conform to what normal{!?} C coders are likely to use as "clan_name_string[ i ]" which means exactly the same IIRC...
  • try and "#define" things right at the top of the file where someone else deciphering your code in the far future would generally expect to find such definitions - the thing you are defining will not exist in the file before the point in the file where it is defined and if someone adds some code that uses that which you define before there they literally won't have anything to play with - as the preprocessor will just remove the identifier and replace it with nothing. Whilst this is desirable in some situations - particularly in "header" files where some conditions such as the "Operating System the code is being compiled for" requires such behaviour otherwise such things can lead to gnashing of teeth and wailing.
  • an "anti-pattern" I've learn of in the last year or so is that having an "else" part of an "if" after code that always does a "return" if the test is "true" is redundant - and can lead to unnecessary levels of indentation in the source code; e.g. see: https://stackoverflow.com/a/46875487/4805858

Aureus
Posts: 727
Joined: Mon Dec 28, 2020 11:13 pm

Re: Itsy's Janky Code Blog

Post by Aureus » Fri Jun 10, 2022 11:39 pm

Jomin wrote:
Fri Jun 10, 2022 9:28 pm
Regarding this function:

Code: Select all

char * return_clan_acronym(char * clan_name_string) {

    #define MAX_ACRO_LENGTH 10 // note 1

    char acronym[MAX_ACRO_LENGTH]; //note 2
    int words = 1;
    int i = 0;

    while (*(clan_name_string + i) != '\0') { //note 3
        if (*(clan_name_string + i) == ' ') { // note 4
            words++; // note 5
        }
        i++; // note 6
    }

    if (words >= MAX_ACRO_LENGTH) {
        return "ERROR: Max Length Exceeded.\n";
    }
    else {
        printf("%s has %i words.\n", clan_name_string, words);
    }

    return "Illian Companions";

}
  • If you define this function before you use it - i.e. list it above the main(...) one then you do not have to declare it first in this trivial test code...
  • You really ought to remove a space around the '*'s that are used to indicate pointer types, either make them butt up against the type declaration (the char) or the variable/function identifier (e.g. the clan_name_string) - leaving it floating in mid-air is just asking for it to be forgotten somewhere - which can have nasty effects!
  • as a C "string" is actually a C "array" of "char" type variables - so instead of explicitly showing the pointer arithmetic as "*(clan_name_string + i)" you can be slightly more terse, and conform to what normal{!?} C coders are likely to use as "clan_name_string[ i ]" which means exactly the same IIRC...
  • try and "#define" things right at the top of the file where someone else deciphering your code in the far future would generally expect to find such definitions - the thing you are defining will not exist in the file before the point in the file where it is defined and if someone adds some code that uses that which you define before there they literally won't have anything to play with - as the preprocessor will just remove the identifier and replace it with nothing. Whilst this is desirable in some situations - particularly in "header" files where some conditions such as the "Operating System the code is being compiled for" requires such behaviour otherwise such things can lead to gnashing of teeth and wailing.
  • an "anti-pattern" I've learn of in the last year or so is that having an "else" part of an "if" after code that always does a "return" if the test is "true" is redundant - and can lead to unnecessary levels of indentation in the source code; e.g. see: https://stackoverflow.com/a/46875487/4805858
:lol: :lol: :lol: :lol: :lol: :lol: :lol: :lol: :lol: :lol:

Oh hi Itesh. I feel seen!

Post Reply