Diskuze: Náhrada konstrukce switch
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Tvůrce

Zobrazeno 26 zpráv z 26.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
V gml například vidím switch docela rád, protože nenásilně vede k
používání
hodnoty default a k přemýšlení nad situací, kdy je vstupem nečekaná
hodnota.
Ale to je výhoda hlavně pro začátečníky, kteří rádi zapomínají, že
se vždycky
najde někdo, kdo na výzvu "Zadej číslo: " napíše: "dvaatřicet".
1-4 je nic neříkající hodnota, proto ji budeš pořád ifovat a switchovat. Jak jsem psal, udělej si smerx a smery.
Musíš si uvědomit, že switch je vlastně náhrada if ... else if ... else if ... A když potřebuješ někde v programu takovouhle hrůzu, něco je špatně.
Aby těch odpovědí nebylo málo, tady je jak položit loď v daném směru do pole:
Generování:
int smerx = 0;
int smery = 0;
while (Math.Abs(smerx) == Math.Abs(smery))
{
smerx = random.Next(-1, 2);
smery = random.Next(-1, 2);
}
A položení lodě ve směru:
int i = x;
int j = y;
for (int k = 0; k < delka; k++)
{
pole[i, j] = delka;
i += smerx;
j += smery;
}
Můj žák tam měl nejprve switch na směr jako ty, kód jsem zmenšil na 1/4 a ještě ubral na generování směru.
Dobře přesvědčil jsi mě . Přemýšlím zda vůbec ukázat ten kód s tím generováním
směru. Generuje to bludiště -> pokládá zdi v náhodném směru. Ještě
to občas holt mám pěkně ošklivý :[
Mě to asi nedá a posílám kód, je opravdu strašný, je starší a doteď
jsem ho neopravil i když na
něm zakládám novou hru. Musím to přepsat, já vím
Bacha na infarkt
private bool Put(Point put, int smer, int n)
{
int pocet = 0;
switch (smer)
{
case 0: // vlevo
for (int x = put.X; x > 0; x--)
{
if (pole[x, put.Y] == 2)
{
pole[x, put.Y] = -1;
position.Remove(new Point(x, put.Y));
pocet++;
if (pocet >= n)
break;
}
else if (pole[x, put.Y] == 0)
pole[x, put.Y] = -1;
else break;
}
break;
case 1: //vpravo
for (int x = put.X; x < sizeX; x++)
{
if (pole[x, put.Y] == 2)
{
pole[x, put.Y] = -1;
position.Remove(new Point(x, put.Y));
pocet++;
if (pocet >= n)
break;
}
else if (pole[x, put.Y] == 0)
pole[x, put.Y] = -1;
else break;
}
break;
case 2: // nahoru
for (int y = put.Y; y > 0; y--)
{
if (pole[put.X, y] == 2)
{
pole[put.X, y] = -1;
position.Remove(new Point(put.X, y));
pocet++;
if (pocet >= n)
break;
}
else if (pole[put.X, y] == 0)
pole[put.X, y] = -1;
else break;
}
break;
case 3: //dolu
for (int y = put.Y; y < sizeY; y++)
{
if (pole[put.X, y] == 2) // nalezl základnu
{
pole[put.X, y] = -1; // položí zed
position.Remove(new Point(put.X, y)); // vymaže základnu
pocet++;
if (pocet >= n)
break;
}
else if (pole[put.X, y] == 0)
pole[put.X, y] = -1;
else break;
}
break;
}
if (position.Count == 0)
return true;
else
return Put(position[rnd.Next(0, position.Count)], rnd.Next(0, 4), rnd.Next(2, position.Count)); ;
}
jestli máte neznámou X, které může mít hodnoty 1 až něco, a ty hodnoty mají zastupovat nějaký obsah, tak bych to neřešil přes switch, ale přes pole, kde by každá hodnota X měla svůj obsah. Procházet to něčím komplikovanějším, je dle mého názoru zbytečná zátěž pro výpočty. Samozřejmě, by tam musela být kontrola, zda obsahové pole tuto X hodnotu má a když ne, vsadila by se hodnota univerzální, třeba zeď.
No, to je přesně ono
Máš tam 4x to samé, když uděláš směr jak jsme ti psal, budeš mít 4x
kratší kód a ještě kratší generování.
Na to by byla rychlejší nějaká hashovací kolekci, ale pořád lepší
než switch
Teoretická výhoda konstrukce switch spočívá v tom, že ji překladač může za jistých podmínek optimalizovat a zajistit tím lepší výkon programu (oproti variantě programu s if-selse-...-if-else). Ale půjde to udělat royumně jen za předpokladu, že se v rámci konstrukce switch ptáte na hodnoty v malém rozsahu (například z enumu).
Překladač může bloky kódu následujícími za jednotlivými větvemi (mezi slovy case a break), aderesy těchto bloků umístit do tabulky (pole) a potom prováděcí kód může vypadat nějak takto:
cmp eax, 8 ; prvni hodnota vyssi nez cokoliv v case prikazu
jge default
jmp bloky[eax]
Což je jistě rychlejší než dělat sekvenci if-else-if-else-...-else, samozřejmě co se týče počtu instrukcí. Ale nedá se to takto vyoptimalizovat vždycky, jak už jsem psal výše. Tenhle kód by se asi dal použít, pokud se v rámci konstrukce switch ptám na hodnoty 0 až 7 a ostatní posílám do větve default. Což by splňovalo použití výčtové proměnné (enum).
Jinak co se týče toho problému se směry, tak (jak už tady zaznělo), stačí si daný směr reprezentovat dvojicí (x;y), který budou nabývat hodnot -1,0,1. Pokud se ti používání dvojice nehodí, můžeš ji zakódovat do jednoho čísla, pak ale záleží na tom, kolik hodnot v každé ose dovolíš.
Jak jsem už psal, switch sám o sobě špatný není, ale často se používá špatně. Převádíš dvě hodnoty (x, y) do jedné (0-3), což se dá označit za serializaci. Tuto hodnotu dáváš do switche, který vlastně dělá deserializaci. Jak známo, serializace a deserializace obecně s sebou nese režii. Pokud přenášíme data mezi objekty, použijeme opět objekt či kontejner, které mají tu režii nižší a neztrácí se sémantika (proč je hodnota 2 nahoru?)
Představ si, že bys do svého příkladu chtěl zapracovat i pohyb po úhlopříčce. Tak asi ten infarkt dostaneš. Nezapomeň umět i stát na místě.
Ano máš pravdu A psal
jsem, tento kód je starší a nyní už to mám přepsané
. Proč 2 nahoru ? Protože jsem si
to tak řekl. Switch ještě by se dal použít jak psal Vrtule při enums.
Další možností je nadefinovat konstantu POHYB_NAHORU = 2.
Pokud pohyb nahoru přeneseš jako dvojici (x=0, y=-1), tak realizaci pohybu
můžeš udělat pouhým opakovaným přičítáním x
a
y
k hodnotám v put
. A nebudeš potřebovat vůbec
žádný switch.
Za chviličku postnu upravenou a zkrácenější verzi a budu zvědavý na
názor zda je to lepší
Ono se musíš prostě zamyslet nad tím, co to pohyb je. Pohyb má 2 složky, posun po 2 osách. Proto ho takto i uložím. Je to jako kdybys switchoval barvy jako 1-modrá, 2 zelená a podobně. Barva má 3 složky RGB, měla by se tedy i takto uložit. Switch jsem již nepoužil strašně dlouho v žádné své aplikaci, když se správně navrhuje, není potřeba. Hodně toho zmůže také reflexe.
No při generování si nic neukládám a dávám za pravdu, switch se dá
nahradit . Zneužil jsem tvého
příkladu a při rychlejší úpravě to vypadá takto. To náhodné sY je
ošetření pouze toho aby vzniklo vždy toto (nechci diagonální směry). Tj
vdy musí vzniknout tyto možné kombinace
když Sx == -1 || Sx==1 tak Sy= 0 jinak Sx=0 tak Sy = -1 ||Sy=1
Šlo by to ještě nějak více nahradit ? Každopádně zde celá metody která pokládá zdi
private bool Put(Position put, int n)
{
int sX = rnd.Next(-1, 2);
int sY = 0;
if (sX == 0)
{
while (Math.Abs(sY) != 1)
{
sY = rnd.Next(-1, 2);
}
}
int pX = put.X;
int pY = put.Y;
for (int p = 0; p < n; p++)
{
if (pX >= 0 && pX < pole.GetLength(0) && pY >= 0 && pY < pole.GetLength(1))
{
if (pole[pX, pY] == 2)
Base.Remove(new Position(pX, pY));
else if (pole[pX, pY] == 1)
break;
pole[pX, pY] = 1;
}
else break;
pX += sX;
pY += sY;
}
if (Base.Count == 0)
return true;
else
return Put(Base[rnd.Next(0, Base.Count)], rnd.Next(2,9));
}
Parametr put je start nového pokládání, n je maximální počet pokládání. Je tam nastavený roszsah 2-8
Ta má verze je také bez diagonálních směrů, proto je tam Abs. Vyleze z toho vždy jeden ze 4 směrů.
No právě že u tebe vyleze například že x a y = 1 ? Nebo jsem úplně
mimo ? Pokud to tak je, tak
vlastně pokládám například vždy v poli o x+1, y+1 => pokládám
diagonální směr.
Ne, kontroluji právě aby nebyly stejné abs. hodnoty, takže 1,1 vylézt nemůže, ani -1,1 a podobně, stejně tak i 0,0.
Podle mne je jednodušší ten směr do x, y vygenerovat z intervalu 0..3 třeba takto:
int[] Pole = {1, 0, -1, 0, 1};
smer = random.Next(0, 4);
x = Pole[smer];
y = Pole[smer+1];
Jo vidím to a uvědomil jsem si to když jsem opouštěl školu . Opět jsem psal příspěvek a
trošku poslouchal učitele a občas to prostě nejde spojit bez toho abych
nenapsal nějakou blbost, a to já mám občas ve zvyku
Stejěn zd přibude podmínka, abychom nešli mimo hranici pole. Ale asi to
bude i rychlejší než přes cyklus
Ach jo já dneska perlím ... už mlčím , opravdu
nevím na co nesutále myslím
Samozřejmě, nepřibude
Zobrazeno 26 zpráv z 26.