Jump to content
  • 0

pomoc Losovanie náhodného playerid


Danny

Dotaz

Čaute,

snažím sa vytvoriť skript povolania nájomného vraha. Po spustení práce sa hráčovi má ukázať jeden z pripojených hráčov ako ciel, ktorého má zabiť. Skúšal som na to ísť najprv úplne základnou cestou checkovania podmienok, no potom mi došlo, že to asi úplne fungovať nebude, pretože to checkovanie sa musí opakovať. Zosmolil som teda niečo takéto:

new randomid = random(GetPlayerPoolSize()); // zadefinoval som si ciel a priradil som mu náhodnú hodnotu z čísel od 0 po najvyššie ID
while(IsPlayerConnected(randomid) && !IsPlayerNPC(randomid) && randomid != playerid) randomid = random(GetPlayerPoolSize());
//Následne som použil cyklus, v ktorom som kontroloval či má dané vybrané ID splnené podmienky (nie je NPC, nejedná sa o hráča, ktorý prácu spustil)

Problém spočíva v tom, že po zahájení tohto padne server.

Link to comment
Share on other sites

11 odpovědí na tuto otázku

Recommended Posts

  • 3

1. rada - tabuj, nepoužívaj jednoriadkové podmienky s funkciou - zvyšuje to prehladnosť

2. rada - spoznaj všetky cykly :) uľahčí ti to prácu... je pekné že vieš while ale treba poznať aj do-while :)

3. rada - vždy si pozri svoj kód znova - tvoj kód hovorí, že pokiaľ je hráč pripojený A NIE JE npc, tak vylosuj nové náhodné číslo... to je blbosť, ty chceš aby sa vygenerovalo nové pokiaľ hráč NIE JE pripojený ALEBO je npc

4. rada - pozri si definiciu funkcii ktoré používaš - random je od 0 po zadané číslo ale exclusive, takže zadané číslo sa nevygeneruje, takže hráč s najvyšším ID nebude nikdy cieľom

Taktiež si určite pred spustením skontroluj, či je na servery viac ako 1 hráč... Ťažko budeš hladať cieľ keď tam je len ten zabijak - tvoj kód sa zacyklí

Každopádne som skúšal tvoj kód a nepadá to (samozrejme ani nefunguje), takže chyba bude buď v kóde pred alebo po. Prikladám ti cyklus ako by mal vyzerať.

new randomid;
do {
	randomid = random(GetPlayerPoolSize() + 1);
} while (!IsPlayerConnected(randomid) || IsPlayerNPC(randomid) || randomid == playerid)

 

Link to comment
Share on other sites

  • 3

Prepáč ale teraz nehovoríš dobre...

Súhlasím že GetPlayerPoolSize ti vráti aktuálne najvyššie pripojené ID, to som ani v mojom príspevku nepopieral (môžeš si ho prečítať znova). Ale funkcia RANDOM vracia čísla od 0 po zadané číslo exkluzívne, tj. ak bude random(10) tak vráti 0...9, čiže číslo 10 nebude výsledkom RANDOM... preto musíš v random použiť GetPlayerPoolSize() + 1

Presne toto som ti hore písal, že si máš najprv prečítať funkciu ktorú používaš...

A k tomu kódu... Tvoj kód nebude fungovať, pretože nerozumieš princípu while cyklu...

While by sa dal preložiť ako "opakuj pokiaľ platí", takže ty opakuješ ak je hráč pripojený a nie je NPC a skončíš akonáhle nájde NPC alebo nepripojeného hráča

Inak povedané, ty losuješ náhodné číslo až do okamihu, kedy sa vylosuje NPC alebo nepripojený hráč... Preto musíš tvoj cyklus opraviť tak ako som ti posielal.

Taktiež presne to je dôvod, prečo sa ti kód zacyklí a server padne.

A to tabovanie: je pekné že TY sa orientuješ, ale projekt skoro nikdy nerobíš sám a teda v robote by si mal písať kód tak, aby keď to chytí niekto po tebe tak vedel čo si chcel robiť

Edited by Quiter
  • Líbí se mi to! (+1) 4
Link to comment
Share on other sites

  • 1
před 56minutami, Quiter said:

SAMP berie najnižšie volné ID pri pripojení, takže toto je veľmi ojedinelý prípad... Naviac random funguje viac menej podla rovnomerného rozdelenia, takže ak je 100 hodnôt, každá má približne 1/100 šancu, a keď budú na servery 2 hráči, tak je to cca 50 cyklov... 50 cyklov v ktorých sa skoro nič nerobí je totálne nič :) 
Samozrejme existuje lepšie riešenie... napr. použiť list (arraylist) z PawnPlus a ukladať doň pripojených hráčov... vtedy by sa ten cyklus zopakoval cca 1x (môže sa stať že vygeneruje zabijaka a teda musí znova)

Jj, je to ojedinele. Ja necim podobnym uz jednou server "crashnul".. 

Link to comment
Share on other sites

  • 0

Neber to uplne zle ale bud sa my nechapeme, alebo tomu vobec nerozumies. Funkcia GetPlayerPoolSize vrati najvyssie pripojene ID, ktore je na serveri.

Citace

3. rada - vždy si pozri svoj kód znova - tvoj kód hovorí, že pokiaľ je hráč pripojený A NIE JE npc, tak vylosuj nové náhodné číslo... to je blbosť, ty chceš aby sa vygenerovalo nové pokiaľ hráč NIE JE pripojený ALEBO je npc

Nie? Ja chcem presne to, co hovori moj kod, tj. chcem sa uistit, ze vybrate ID je pripojene a zaroven zadat podmienku, aby nebolo NPC, tzv. aby vyber ciela nepadol na NPC, ktore hrac nebude moct zabit.

Tabovanie samozrejme poznam, ale svoj kod chcem napisat tak, aby mal co najmensi pocet riadkov a v tom, akym sposobom si ho pisem sa uz po takej dobe relativne orientujem.

Podmienku kontroly toho, ze ci je na serveri aspon jeden hrac som pridal, avsak nepomohlo. Kod sa zacyklil aj ked nas tam bolo 5.

Link to comment
Share on other sites

  • 0
On 21. 4. 2021 at 18:16, Quiter said:

1. rada - tabuj, nepoužívaj jednoriadkové podmienky s funkciou - zvyšuje to prehladnosť

2. rada - spoznaj všetky cykly :) uľahčí ti to prácu... je pekné že vieš while ale treba poznať aj do-while :)

3. rada - vždy si pozri svoj kód znova - tvoj kód hovorí, že pokiaľ je hráč pripojený A NIE JE npc, tak vylosuj nové náhodné číslo... to je blbosť, ty chceš aby sa vygenerovalo nové pokiaľ hráč NIE JE pripojený ALEBO je npc

4. rada - pozri si definiciu funkcii ktoré používaš - random je od 0 po zadané číslo ale exclusive, takže zadané číslo sa nevygeneruje, takže hráč s najvyšším ID nebude nikdy cieľom

Taktiež si určite pred spustením skontroluj, či je na servery viac ako 1 hráč... Ťažko budeš hladať cieľ keď tam je len ten zabijak - tvoj kód sa zacyklí

Každopádne som skúšal tvoj kód a nepadá to (samozrejme ani nefunguje), takže chyba bude buď v kóde pred alebo po. Prikladám ti cyklus ako by mal vyzerať.


new randomid;
do {
	randomid = random(GetPlayerPoolSize() + 1);
} while (!IsPlayerConnected(randomid) || IsPlayerNPC(randomid) || randomid == playerid)

 

Tvůj kód má problém v tom, že pokud bude připojený pouze jeden hráč, tak se bude jednat o nekonečný cyklus a server "padne".

Link to comment
Share on other sites

  • 0
před 10hodinami, Lukasz said:

Tvůj kód má problém v tom, že pokud bude připojený pouze jeden hráč, tak se bude jednat o nekonečný cyklus a server "padne".

Treba čítať celé:

Taktiež si určite pred spustením skontroluj, či je na servery viac ako 1 hráč...

Link to comment
Share on other sites

  • 0
před 1hodinou, Quiter said:

Treba čítať celé:

Taktiež si určite pred spustením skontroluj, či je na servery viac ako 1 hráč...

Jo, jsem slepý.

Ono by bylo stejně asi lepší vzít reálný počet hráčů na serveru, vygenerovat podle toho náhodné číslo a dopočítat k jakému playerid to sedí. Ono když ti GetPlayerPoolSize() vrátí třeba 100 (na jeho serveru nereálné, pokud to nezaplní NPC), na serveru máš ale jen dva hráče, tak to pak dá zabrat trefit se do správného playerid.

Link to comment
Share on other sites

  • 0
před 4hodinami, Lukasz said:

Jo, jsem slepý.

Ono by bylo stejně asi lepší vzít reálný počet hráčů na serveru, vygenerovat podle toho náhodné číslo a dopočítat k jakému playerid to sedí. Ono když ti GetPlayerPoolSize() vrátí třeba 100 (na jeho serveru nereálné, pokud to nezaplní NPC), na serveru máš ale jen dva hráče, tak to pak dá zabrat trefit se do správného playerid.

SAMP berie najnižšie volné ID pri pripojení, takže toto je veľmi ojedinelý prípad... Naviac random funguje viac menej podla rovnomerného rozdelenia, takže ak je 100 hodnôt, každá má približne 1/100 šancu, a keď budú na servery 2 hráči, tak je to cca 50 cyklov... 50 cyklov v ktorých sa skoro nič nerobí je totálne nič :) 
Samozrejme existuje lepšie riešenie... napr. použiť list (arraylist) z PawnPlus a ukladať doň pripojených hráčov... vtedy by sa ten cyklus zopakoval cca 1x (môže sa stať že vygeneruje zabijaka a teda musí znova)

Link to comment
Share on other sites

  • 0
new PlayerCount,Players[MAX_PLAYERS];

for(new i,j=GetPlayerPoolSize();i<=j;i++)
{
	if(IsPlayerConnected(i) && !IsPlayerNPC(i) && i != playerid)
	{
		Players[PlayerCount] = i;
		PlayerCount++;
	}
}
if(!PlayerCount) return INVALID_PLAYER_ID;//nikdo kdo by vyhovoval podminkam neni pripojen
new random_connected_playerid = Players[random(PlayerCount)];

PS: random generuje pseudonahodna cisla, ktera nemaji normalni rozdeleni. Ale to je fuk, jeste jsem neprisel k pripadu kdy bych potreboval bazirovat na roznonernosti nahodneho rozdeleni (aspon ne ve hre, v poli matematiky je to o cenem jinem...).

Edited by ATomas
Link to comment
Share on other sites

  • 0

Off topic:
 

před 11hodinami, ATomas said:

PS: random generuje pseudonahodna cisla, ktera nemaji normalni rozdeleni.

Z hodín štatistiky som si síce veľa neodniesol, ale zaujímalo by ma, prečo by si chcel normálne rozdelenie.

Pokiaľ viem, v normálnom rozdelení má najvyššiu pravdepodobnosť výskytu priemerná hodnota a táto pravdepodobnosť so vzdialenosťou od priemernej hodnoty klesá.
Ak by teda funkcia random generovala čísla takýmto spôsobom, znamenalo by to, že by niektoré čísla boli generované častejšie ako iné (v tomto konkrétnom prípade by boli nejaké ID vyberané častejšie ako iné).

Myslím si, že v tomto prípade chceš skôr rovnomerné rozdelenie, v ktorom majú všetky hodnoty (z daného intervalu) rovnakú pravdepodobnosť výskytu.
Trochu som testoval som funkciu random a mám pocit, že sa všetky čísla generujú s rovnakou pravdepodobnosťou (čo je asi presne to, čo chceme, pretože každý hráč by mal mať rovnakú šancu na to, aby bol vybraný). 
 

Spoiler

#define FILTERSCRIPT

#include <a_samp>

#if defined MAX_PLAYERS
    #undef MAX_PLAYERS
#endif
#define MAX_PLAYERS 100

public OnFilterScriptInit()
{
    new frequency[MAX_PLAYERS];
    for (new i = 0; i < 1_000_000 * sizeof(frequency); ++i)
        ++frequency[random(sizeof(frequency))];

    for (new i = 0; i < sizeof(frequency); ++i)
        printf("frequency[%d] = %d", i, frequency[i]);
        
    return 1;
}

Výstup:
 


frequency[0] = 1001392
frequency[1] = 998450
frequency[2] = 999887
.
.
.
frequency[99] = 1001046

Celý výstup

 

Edited by DuFF
  • Líbí se mi to! (+1) 3
Link to comment
Share on other sites

  • 0
před 19hodinami, DuFF said:

Off topic:
 

Z hodín štatistiky som si síce veľa neodniesol, ale zaujímalo by ma, prečo by si chcel normálne rozdelenie.

Pokiaľ viem, v normálnom rozdelení má najvyššiu pravdepodobnosť výskytu priemerná hodnota a táto pravdepodobnosť so vzdialenosťou od priemernej hodnoty klesá.
Ak by teda funkcia random generovala čísla takýmto spôsobom, znamenalo by to, že by niektoré čísla boli generované častejšie ako iné (v tomto konkrétnom prípade by boli nejaké ID vyberané častejšie ako iné).

Myslím si, že v tomto prípade chceš skôr rovnomerné rozdelenie, v ktorom majú všetky hodnoty (z daného intervalu) rovnakú pravdepodobnosť výskytu.
Trochu som testoval som funkciu random a mám pocit, že sa všetky čísla generujú s rovnakou pravdepodobnosťou (čo je asi presne to, čo chceme, pretože každý hráč by mal mať rovnakú šancu na to, aby bol vybraný). 
 

  Ukázat skrytý obsah


#define FILTERSCRIPT

#include <a_samp>

#if defined MAX_PLAYERS
    #undef MAX_PLAYERS
#endif
#define MAX_PLAYERS 100

public OnFilterScriptInit()
{
    new frequency[MAX_PLAYERS];
    for (new i = 0; i < 1_000_000 * sizeof(frequency); ++i)
        ++frequency[random(sizeof(frequency))];

    for (new i = 0; i < sizeof(frequency); ++i)
        printf("frequency[%d] = %d", i, frequency[i]);
        
    return 1;
}

Výstup:
 



frequency[0] = 1001392
frequency[1] = 998450
frequency[2] = 999887
.
.
.
frequency[99] = 1001046

Celý výstup

 

Ano mas pravdu, melo tam byt rovnomerne rozdeleni. Uz jsem padal unavou kdyz jsem to psal :)

Edited by ATomas
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...