Korutin és alkalmazása

Az előző bejegyzésben szó volt a generátorról. Azt egy olyan speciális iterátorként jellemeztük, amely lehetővé teszi a kétirányú adatmozgást a hívó kliens program és a generátor között. E tulajdonságot lehet kihasználni korutinok megvalósítására.

A korutinok olyan kódszerkezetek, amelyek egymást kölcsönösen meg tudják hívni úgy, hogy egy adott feladatot együttműködve megvalósítsanak. Ezért nevezik az ilyen kódszerkezeteket korutinoknak (coroutin), vagyis együttműködő programoknak (cooperative routines). Az együttműködés megvalósításához a korutinok nélkülözhetetlen tulajdonsága, hogy képesek a kódvégrehajtást – az állapotuk megőrzése mellett – akár többször is felfüggeszteni, és átadni a vezérlést egy másik programblokknak, majd kérésre folytatni az utasításvégehajtást attól a ponttól, ahol abbamaradt. Képesek továbbá minden folytatáskor adatot fogadni, illetve minden egyes programvégrehajtás felfüggesztésekor adatot átadni.

A korutinok működését egy egyszerű példával illusztráljuk. Kártyajátékot fogunk modellezi, amelyet három játékos játszik francia-kártyával. A megkevert kártyapakliból minden játékos kezdésnek 5 lapot kap. A maradék paklit az asztalra tesszük színével felfelé. A játékosok egymás után meghatározott sorrendben következnek. A szabály az, hogy a sorra kerülő játékosnak mindig az asztalon levő pakli tetején látható kártya színével megegyező, vagy ha nincs ilyen, akkor értékével egyenlő vagy értékesebb kártyát kell a kezéből az asztali pakli tetejére lerakni. Ha nem tud lerakni semmit, akkor fel kell húznia a kezébe a pakli tetején levő kártyát. Az nyer, akinek a kezéből legelőször fogynak el a kártyák.

A megvalósítás egy lehetséges programkódját láthatjuk alább.

A programban először létrehozzuk az 52 db kártyát egy-egy mezőneves tuple objektumként. A játékosokat egy-egy generátor alapú korutin fogja megvalósítani. Ehhez egy generátorfüggvényt definálunk, amely a kezdeti 5 db kiosztott kártyát egy listában fogadja. A függvénytörzsön belül a yield bal oldalán álló változóba fog kerülni az asztali pakli legfelső lapja, a jobb oldalán pedig a lerakott lap, ha van. Ha nincs, akkor ez None értékű lesz. A továbbiakban ellenőrizzük, hogy van-e lerakható lap. Ha van, akkor egyet kiválasztunk. Elsősorban az egyező színűt rakjuk le. Ha ilyen nincs, akkor választunk az értékek alapján megfelelőkből. Ha az eldobás után nem marad kártya az adott játékosnál, akkor ezt egy kivételdobással jelezzük. A kártyapakli megkeverése után létrehozzuk a játékosokat, és az azokat reprezentáló korutinokat kezdőállapotba hozzuk. Utána következhet maga a játék. Itt egy ciklusban sorban egymás után vesszük ki a játékosokat az azokat tartalmazó listából. Beazonosítjuk az asztali pakli legfelső lapját, és átadjuk a játékosnak a send() metódussal. Ha a játékos nem tud lerakni kártyát, akkor a legfelső lapot meg kell tartania, így eltávolítjuk a pakli tetejéről. Ha tudott lerakni, akkor az eldobott kártyát a pakli tetejére helyezzük. Ha a játékos köre befejeződött, akkor őt a lista végére tesszük, hogy újra rá tudjon kerülni a sor. Ha nyert valaki, akkor a kivételdobást lekezeljük és kiírjuk a nyertes nevét, ami után a játék véget ért (kilépünk a ciklusból).

Megjegyezzük, hogy a játék nem mindig tud nyertest eredményezni, ilyenkor nem áll le a futás. Lehetne erre is kódokat írni, és még számos helyen finomítani, de az ilyen extra kódok elvinnék a fókuszt az alapvető célról, ami most a korutin működésének bemutatása volt. A korutinokról és a példaprogramban szereplő egyéb nyelvi elemekről a Python tudásépítés lépésről lépésre című e-könyvben további részleteket olvashatunk.

Érdekel a Python tudásépítés lépésről lépésre az alapoktól az első asztali alkalmazásig című e-könyv.