function strfind() does NOT work
#1

So I've made this little function, which was supposed to return a simplified name of the weatherID (https://sampwiki.blast.hk/wiki/WeatherID).
PHP код:
new const _weathers[][] = {
    
"EXTRASUNNY_LA",
    
"SUNNY_LA",
    
"EXTRASUNNY_SMOG_LA",
    
"SUNNY_SMOG_LA",
    
"CLOUDY_LA",
    
"SUNNY_SF",
    
"EXTRASUNNY_SF",
    
"CLOUDY_SF",
    
"RAINY_SF",
    
"FOGGY_SF",
    
"SUNNY_VEGAS",
    
"EXTRASUNNY_VEGAS",
    
"CLOUDY_VEGAS",
    
"EXTRASUNNY_COUNTRYSIDE",
    
"SUNNY_COUNTRYSIDE",
    
"CLOUDY_COUNTRYSIDE",
    
"RAINY_COUNTRYSIDE",
    
"EXTRASUNNY_DESERT",
    
"SUNNY_DESERT"
};
stock GetWeatherSimplifiedNameFromID(weatherid) {
    new 
weathername[30];
    
weathername GetWeatherNameFromID(weatherid);
    new 
string[20];
    if (
strfind(weathername"SUNNY"true) != -1) {
        
string "Sunny";
        return 
string;
    }
    if (
strfind(weathername"ClOUDY"true) != -1) {
        
string "Cloudy";
        return 
string;
    }
    if (
strfind(weathername"RAINY"true) != -1) {
        
string "Rainy";
        return 
string;
    }
    if (
strfind(weathername"FOGGY"true) != -1) {
        
string "Foggy";
        return 
string;
    }
    else 
string "Unidentified";
    return 
string;

The function 'GetWeatherNameFromID()' returns the weather from the '_weathers' array and works perfectly fine (tested).

The problems:
  • The weathers that starts with 'SUNNY' returns 'Foggy'.
  • The weathers that starts with 'CLOUDY' returns 'Sunny'.
  • The weathers that starts with 'RAINY' returns 'Sunny'.
  • The weathers that starts with 'FOGGY' returns 'Sunny'.
NOTE: The weathers that starts with 'EXTRASUNNY' returns 'Sunny' as it should.

I've also considered to use `strcmp` (checking the first characters of the weather) instead of `strfind()`.

Any help/example/tutorial would be helpful.
Reply
#2

Quote:
Originally Posted by CeSuX
Посмотреть сообщение
So I've made this little function, which was supposed to return a simplified name of the weatherID (https://sampwiki.blast.hk/wiki/WeatherID).
PHP код:
new const _weathers[][] = {
    
"EXTRASUNNY_LA",
    
"SUNNY_LA",
    
"EXTRASUNNY_SMOG_LA",
    
"SUNNY_SMOG_LA",
    
"CLOUDY_LA",
    
"SUNNY_SF",
    
"EXTRASUNNY_SF",
    
"CLOUDY_SF",
    
"RAINY_SF",
    
"FOGGY_SF",
    
"SUNNY_VEGAS",
    
"EXTRASUNNY_VEGAS",
    
"CLOUDY_VEGAS",
    
"EXTRASUNNY_COUNTRYSIDE",
    
"SUNNY_COUNTRYSIDE",
    
"CLOUDY_COUNTRYSIDE",
    
"RAINY_COUNTRYSIDE",
    
"EXTRASUNNY_DESERT",
    
"SUNNY_DESERT"
};
stock GetWeatherSimplifiedNameFromID(weatherid) {
    new 
weathername[30];
    
weathername GetWeatherNameFromID(weatherid);
    new 
string[20];
    if (
strfind(weathername"SUNNY"true) != -1) {
        
string "Sunny";
        return 
string;
    }
    if (
strfind(weathername"ClOUDY"true) != -1) {
        
string "Cloudy";
        return 
string;
    }
    if (
strfind(weathername"RAINY"true) != -1) {
        
string "Rainy";
        return 
string;
    }
    if (
strfind(weathername"FOGGY"true) != -1) {
        
string "Foggy";
        return 
string;
    }
    else 
string "Unidentified";
    return 
string;

The function 'GetWeatherNameFromID()' returns the weather from the '_weathers' array and works perfectly fine (tested).

The problems:
  • The weathers that starts with 'SUNNY' returns 'Foggy'.
  • The weathers that starts with 'CLOUDY' returns 'Sunny'.
  • The weathers that starts with 'RAINY' returns 'Sunny'.
  • The weathers that starts with 'FOGGY' returns 'Sunny'.
NOTE: The weathers that starts with 'EXTRASUNNY' returns 'Sunny' as it should.

I've also considered to use `strcmp` (checking the first characters of the weather) instead of `strfind()`.

Any help/example/tutorial would be helpful.
Here are some bits that I've written for You.
pawn Код:
new const _weathers[][] = { // id  type         +bits
    "EXTRASUNNY_LA",        // 0  Sunny         2
    "SUNNY_LA",             // 1  Sunny         4
    "EXTRASUNNY_SMOG_LA",   // 2  Sunny         6
    "SUNNY_SMOG_LA",        // 3  Sunny         8
    "CLOUDY_LA",            // 4  Cloudy        10
    "SUNNY_SF",             // 5  Sunny         12
    "EXTRASUNNY_SF",        // 6  Sunny         14
    "CLOUDY_SF",            // 7  Cloudy        16
    "RAINY_SF",             // 8  Rainy         18
    "FOGGY_SF",             // 9  Foggy         20
    "SUNNY_VEGAS",          // a  Sunny         22
    "EXTRASUNNY_VEGAS",     // b  Sunny         24
    "CLOUDY_VEGAS",         // c  Cloudy        26
    "EXTRASUNNY_COUNTRYSIDE",   // d  Sunny     28
    "SUNNY_COUNTRYSIDE",    // e  Sounny        30
    "CLOUDY_COUNTRYSIDE",   // f  Cloudy        32
    "RAINY_COUNTRYSIDE",    // 10  Rainy        1 + 2
    "EXTRASUNNY_DESERT",    // 11  Sunny        1 + 4
    "SUNNY_DESERT"          // 12  Sunny        1 + 6
};

#define WEATHER_TYPES (19) // Just a quantity of _weathers array

new const _flags[] = {
    0x410e4100, 0x2
};

new const simplifiedNames[][] = {
    "Sunny", "Cloudy", "Rainy", "Foggy"
};

GetWeatherSimplifiedNameFromID(weatherid) {
    new output[10];
    if(weatherid >= WEATHER_TYPES) {
        format(output, 10, "Undefined");
    } else {
        new flagsCell = 0, wid = weatherid;
       
        while(wid >>= 4) flagsCell++; // We divide by 16, because that's how many types we can handle in single flag (_flags) - cells are 32 bit wide. We use 2 bits per weather, thus 32/2.
        weatherid %= 16;
        weatherid *= 2;
        weatherid = (_flags[flagsCell] >> weatherid) & 3;
       
        format(output, 10, "%s", simplifiedNames[weatherid]);
    }
    return output;
}
And the output for

pawn Код:
for(new i = 0; i < 22; i++) {
    printf("GetWeat..FromId(%d): %s", i, GetWeatherSimplifiedNameFromID(i));
}
Is:

Код:
[15:24:45] GetWeat..FromId(0): Sunny
[15:24:45] GetWeat..FromId(1): Sunny
[15:24:45] GetWeat..FromId(2): Sunny
[15:24:45] GetWeat..FromId(3): Sunny
[15:24:45] GetWeat..FromId(4): Cloudy
[15:24:45] GetWeat..FromId(5): Sunny
[15:24:45] GetWeat..FromId(6): Sunny
[15:24:45] GetWeat..FromId(7): Cloudy
[15:24:45] GetWeat..FromId(8): Rainy
[15:24:45] GetWeat..FromId(9): Foggy
[15:24:45] GetWeat..FromId(10): Sunny
[15:24:45] GetWeat..FromId(11): Sunny
[15:24:45] GetWeat..FromId(12): Cloudy
[15:24:45] GetWeat..FromId(13): Sunny
[15:24:45] GetWeat..FromId(14): Sunny
[15:24:45] GetWeat..FromId(15): Cloudy
[15:24:45] GetWeat..FromId(16): Rainy
[15:24:45] GetWeat..FromId(17): Sunny
[15:24:45] GetWeat..FromId(18): Sunny
[15:24:45] GetWeat..FromId(19): Undefined
[15:24:45] GetWeat..FromId(20): Undefined
[15:24:45] GetWeat..FromId(21): Undefined
.. which meets the expectations.

Explanation

Okay, so first of all, I've decided to hardcode weather types, because:
1) It is easy to redefine it in language-free way (i.e. you don't have to worry what foggy means)
2) It is relatively easier and faster for the CPU to compare numbers than to compare strings.. But it is obvious.

What's going on in here?

We have 4 weather types: 1) sunny, 2) cloudy 3) rainy, 4) foggy.
We can memorize those as follows:

States Sunny Cloudy Rainy Foggy
Decimal0123
Binary011011
Therefore, we can save information about one state in 2 bits. Well, that comes handy, when we'd like to store as much information as possible in single cell.
Pawn's cells are 32 bit wide - in single cell we can save 32/2 = 16 states.

0x410e4100 (_flags[0]) is equal to
00 00 00 00 01 00 00 01 00 00 11 10 01 00 00 01 00 00 00 00

I hope you can clearly see what is going on in here. Especially, if you take a look at _weathers array.
However, keep in mind that those are in reversed order (thus read it from right to left). This is to avoid more complicated maths later on.

In general, this:
pawn Код:
new const _flags[] = {
    0x410E4100, 0x2
};
is just another way of saying this:

pawn Код:
#define WEATHER_SUNNY (0)
#define WEATHER_CLOUDY (1)
#define WEATHER_RAINY (2)
#define WEATHER_FOGGY (3)

new const _weatherTypes[] = {
    WEATHER_SUNNY, // EXTRASUNNY_LA
    WEATHER_SUNNY, // SUNNY_LA
    WEATHER_SUNNY  // EXTRASUNNY_SMOG_LA
    ...
};
.. however, the second option consumes 9.5 times more space (and we're wasting 570 bits)
MethodMathResult (in bits)Bits that are acutally usedBits waste(%)
Using flags32*2643840
2nd method32*196083893
The last thing, which should be descripted is this piece:

pawn Код:
while(wid >>= 4) flagsCell++;
weatherid %= 16;
weatherid *= 2;
weatherid = (_flags[flagsCell] >> weatherid) & 3;
1. It didives weatherid (alias: wid) untill the result's less than 16 (shifting 4 bits right = divide by 16), so that we can determine which _flags[] cell's gonna be used.
2. We take weather modulo 16, so that our offset is always from 0 to 15 (because we can save 16 different 2-bit states in a cell. That would vary, if i.e. we would use more states -> more bits per single state)
3. We multiply it by 2 to get the offset (how many bits we have to shift to get our final answer)
4. We're shifting our flag by weatherid bits and ANDing with 3 (binary: 11), as we're interested in only those last 2 bits of our result.

Any questions - lemme know.
Greetings.

If I have made any mistake in the explanation above, please correct me. Thank You.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)