Informatika érettségi 2007. Október
Ez az érettségi feladat a foci, tippmix és a LINQ kedvelőinek lesz kedvence. Lényegében egy egyszerű foci statisztika készítő alkalmazást kell gyártanunk. Ha elvonatkoztatunk a teszt adatok körítésétől, akkor még a való életben is hasznos alkalmazás kezdeményt kapunk.
A feladatkiírás
Perec város sportéletében fontos szerepet játszanak a fiatalok nagypályás labdarúgó mérkőzései. Tavasszal minden csapat minden csapattal pontosan egy mérkőzést játszott. A folyamatosan vezetett eredménylista azonban eltűnt, így csak a mérkőzések jegyzőkönyvei álltak rendelkezésre. A jegyzőkönyveket ismételten feldolgozták, ehhez első lépésként a meccs.txt állományba bejegyeztek néhány adatot. Önnek ezzel az állománnyal kell dolgoznia.
A meccs.txt állomány első sorában az állományban tárolt mérkőzések száma található.
Alatta minden sorban egy-egy mérkőzés adatai olvashatók. Egy mérkőzést 7 adat ír le. Az első megadja, hogy a mérkőzést melyik fordulóban játszották le. A második a hazai, a harmadik a vendégcsapat góljainak száma a mérkőzés végén, a negyedik és ötödik a félidőben elért gólokat jelöli. A hatodik szöveg a hazai csapat neve, a hetedik a vendégcsapat neve. Az egyes adatokat egyetlen szóköz választja el egymástól. A sor végén nincs szóköz. A csapatok és a fordulók száma nem haladja meg a 20, a mérkőzések száma pedig a 400 értéket. Egy csapat sem rúgott meccsenként 9 gólnál többet. A csapatok neve legfeljebb 20 karakter hosszú, a névben nincs szóköz.
Például:
112
14 1 2 0 2 Agarak Ovatosak
5 4 0 1 0 Erosek Agarak
4 0 2 0 2 Ijedtek Hevesek
8 1 1 0 0 Ijedtek Nyulak
8 3 2 3 1 Lelkesek Bogarak
13 0 1 0 1 Fineszesek Csikosak
2 1 0 0 0 Pechesek Csikosak
1 4 0 2 0 Csikosak Kedvesek
9 2 0 0 0 Nyulak Lelkesek
6 0 2 0 0 Ovatosak Nyulak
Az 2. sor mutatja, hogy a 14. fordulóban az otthon játszó Agarakat az Óvatosak 2-1-re megverték úgy, hogy a félidőben már vezettek 2-0-ra.
Készítsen programot, amely az alábbi kérdésekre válaszol! A program forráskódját mentse foci néven! (A program megírásakor a felhasználó által megadott adatok helyességét, érvényességét nem kell ellenőriznie.)
A képernyőre írást igénylő részfeladatok eredményének megjelenítése előtt írja a képernyőre a feladat sorszámát (például: 3. feladat:). Ha a felhasználótól kér be adatot, jelenítse meg a képernyőn, hogy milyen értéket vár!
- Olvassa be a meccs.txt állományban talált adatokat, s annak felhasználásával oldja meg a következő feladatokat! Ha az állományt nem tudja beolvasni, az első 10 mérkőzés adatait jegyezze be a programba és dolgozzon azzal!
- Kérje be a felhasználótól egy forduló számát, majd írja a képernyőre a bekért forduló mérkőzéseinek adatait a következő formában: Edes-Savanyu: 2-0 (1-0)! Soronként egy mérkőzést tüntessen fel! A különböző sorokban a csapatnevek ugyanazon a pozíción kezdődjenek!Például:
Edes-Savanyu: 2-0 (1-0) Ijedtek-Hevesek: 0-2 (0-2) ... - Határozza meg, hogy a bajnokság során mely csapatoknak sikerült megfordítaniuk az állást a második félidőben! Ez azt jelenti, hogy a csapat az első félidőben vesztésre állt ugyan, de sikerült a mérkőzést megnyernie. A képernyőn soronként tüntesse fel a forduló sorszámát és a győztes csapat nevét!
- Kérje be a felhasználótól egy csapat nevét, és tárolja el! A következő két feladat megoldásához ezt a csapatnevet használja! Ha nem tudta beolvasni, használja a Lelkesek csapatnevet!
- Határozza meg, majd írja ki, hogy az adott csapat összesen hány gólt lőtt és hány gólt kapott! Például:
lőtt: 23 kapott: 12 - Határozza meg, hogy az adott csapat otthon melyik fordulóban kapott ki először és melyik csapattól! Ha egyszer sem kapott ki (ilyen csapat például a Bogarak), akkor „A csapat otthon veretlen maradt.” szöveget írja a képernyőre!
- Készítsen statisztikát, amely megadja, hogy az egyes végeredmények hány alkalommal fordultak elő! Tekintse egyezőnek a fordított eredményeket (például 4-2 és 2-4)! A nagyobb számot mindig előre írja! Az elkészült listát a stat.txt állományban helyezze el!Például:
2-1: 18 darab 4-0: 2 darab 2-0: 19 darab ...
Az adatstruktúra
A statisztika készítéséhez viszonylag sok adatra van szükségünk. Ezeket szerencsére egy sorban megkapjuk, így a beolvasó kód viszonylag egyszerű lesz. Az egy sorban tárolt adatoknak készítettem egy osztályt, ami a Meccs nevet kapta.
Ez az osztály nem tartalmaz most logikát, mivel a feladatkiírásból nem következett, hogy egyszerűbb lenne az életünk, ha tennénk bele valami logikát.
Az ilyen osztályokat adat osztályoknak (data class) szokás nevezni és ha egy nagyobb alkalmazást tervezünk, akkor mindig célszerű az adattároló- és leíró osztályokat elválasztani a tényleges program logikától.
public class Meccs
{
public int Fordulo { get; set; }
public int HazaiGol { get; set; }
public int VendegGol { get; set; }
public int HazaiGolFelidoben { get; set; }
public int VendegGolFelidoben { get; set; }
public string HazaiCsapat { get; set; }
public string VendegCsapat { get; set; }
public Meccs()
{
HazaiCsapat = string.Empty;
VendegCsapat = string.Empty;
}
}
A megoldás
- Olvassa be a meccs.txt állományban talált adatokat, s annak felhasználásával oldja meg a következő feladatokat! Ha az állományt nem tudja beolvasni, az első 10 mérkőzés adatait jegyezze be a programba és dolgozzon azzal!
Az első feladat itt is a fájl beolvasása, korábban már volt hasonló adatszerkezet. Itt is egy sor kerül beolvasásra, majd szóköz szerint felbontjuk és az osztály megfelelő tulajdonságait beállítjuk konvertálás után.
Az adatokat a megoldás osztályban található List<Meccs> típusú _meccsek változó tárolja.
public void Feladat01()
{
using (var file = File.OpenText("meccs.txt"))
{
file.ReadLine(); //első sor nem kell
string? sor = null;
do
{
sor = file.ReadLine();
if (!string.IsNullOrEmpty(sor))
{
string[] darabok = sor.Split(' ');
_meccsek.Add(new Meccs
{
Fordulo = int.Parse(darabok[0]),
HazaiGol = int.Parse(darabok[1]),
VendegGol = int.Parse(darabok[2]),
HazaiGolFelidoben = int.Parse(darabok[3]),
VendegGolFelidoben = int.Parse(darabok[4]),
HazaiCsapat = darabok[5],
VendegCsapat = darabok[6]
});
}
}
while (sor != null);
}
}
- Kérje be a felhasználótól egy forduló számát, majd írja a képernyőre a bekért forduló mérkőzéseinek adatait a következő formában: Edes-Savanyu: 2-0 (1-0)! Soronként egy mérkőzést tüntessen fel! A különböző sorokban a csapatnevek ugyanazon a pozíción kezdődjenek!
Egyszerű kereséses feladat. Megadott forduló alapján ki kell írnunk az adott forduló eredményeit. LINQ Where feltétellel megkeressük a fordulót a listában, majd formázottan kiírjuk az adatokat.
public void Feladat02()
{
Console.WriteLine("Forduló száma:");
int fordulo = int.Parse(Console.ReadLine());
var fordulomeccsek = _meccsek.Where(m => m.Fordulo == fordulo);
foreach (var meccs in fordulomeccsek)
{
Console.WriteLine("{0}-{1}: {2}-{3} ({4}-{5})",
meccs.HazaiCsapat,
meccs.VendegCsapat,
meccs.HazaiGol,
meccs.VendegGol,
meccs.HazaiGolFelidoben,
meccs.VendegGolFelidoben);
}
}
- Határozza meg, hogy a bajnokság során mely csapatoknak sikerült megfordítaniuk az állást a második félidőben! Ez azt jelenti, hogy a csapat az első félidőben vesztésre állt ugyan, de sikerült a mérkőzést megnyernie. A képernyőn soronként tüntesse fel a forduló sorszámát és a győztes csapat nevét!
LINQ Where feltételes szűréssel viszonylag könnyen előállítható az eredmény, ha jól adjuk meg a szűrőfeltételeket. Ha a csapat otthon játszott, és állást fordított, akkor az egy meccshez tartozó HazaiGolFelidoben kisebb, mint a VendegGolFelidoben értéke úgy, hogy a HazaiGol nagyobb, mint a VendegGol. Ha pedig vendégként játszottak és állást fordítottak, akkor a VendegGolFelidoben kisebb, mint a HazaiGolFelidoben úgy, hogy a VendegGol nagyobb, mint a HazaiGol értéke.
A két kapott szűrés eredményét kell kiírnunk, de akár egyszerűsíthettünk volna is, ha az eredményeket egybevonjuk az Union utasítással.
public void Feladat03()
{
var hazaiforditott = _meccsek
.Where(m => m.HazaiGolFelidoben < m.VendegGolFelidoben
&& m.HazaiGol > m.VendegGol);
var vendegforditott = _meccsek
.Where(m => m.VendegGolFelidoben < m.HazaiGolFelidoben
&& m.VendegGol > m.HazaiGol);
foreach (var meccs in hazaiforditott)
{
Console.WriteLine("Forduló: {0} Csapat: {1}", meccs.Fordulo, meccs.HazaiCsapat);
}
foreach (var meccs in vendegforditott)
{
Console.WriteLine("Forduló: {0} Csapat: {1}", meccs.Fordulo, meccs.VendegCsapat);
}
}
- Kérje be a felhasználótól egy csapat nevét, és tárolja el! A következő két feladat megoldásához ezt a csapatnevet használja! Ha nem tudta beolvasni, használja a Lelkesek csapatnevet!
Jutalomfeladat pár pontért. A beolvasott csapatnevet a megoldás osztályban elhelyezett string típusú _csapatnev változó tárolja.
public void Feladat04()
{
Console.WriteLine("Kérek egy csapat nevet:");
_csapatnev = Console.ReadLine();
}
- Határozza meg, majd írja ki, hogy az adott csapat összesen hány gólt lőtt és hány gólt kapott! Például:
lőtt: 23 kapott: 12
A feladatban az a trükk, hogy külön tároljuk, hogy az adott csapat mikor játszott vendégcsapatként és mikor játszott hazai pályán. Ezért először ki kell szűrni, hogy mikor játszottak vendégként és mikor hazaiként. Ezután csak össze kell számolni a megfelelő mezők összegzésével, hogy hány gólt kaptak és mennyit lőttek. A végén pedig szépen formázottan ki kell írni a kapott eredményt.
public void Feladat05()
{
var hazaikent = _meccsek.Where(m => m.HazaiCsapat == _csapatnev);
var vendegkent = _meccsek.Where(m => m.VendegCsapat == _csapatnev);
int lott = 0;
int kapott = 0;
foreach(var meccs in hazaikent)
{
lott += meccs.HazaiGol;
kapott += meccs.VendegGol;
}
foreach (var meccs in vendegkent)
{
lott += meccs.VendegGol;
kapott += meccs.HazaiGol;
}
Console.WriteLine("lőtt: {0} kapott: {1}", lott, kapott);
}
- Határozza meg, hogy az adott csapat otthon melyik fordulóban kapott ki először és melyik csapattól! Ha egyszer sem kapott ki (ilyen csapat például a Bogarak), akkor „A csapat otthon veretlen maradt.” szöveget írja a képernyőre!
A FirstOrDefault() metódus használatával megoldható feladat. Ez a metódus null értéket ad vissza, ha a paraméterként megadott szűrés nem vezetett eredményre. Ezért egy szimpla null ellenőrzés után meg is mondható, hogy otthon veretlen maradt a csapat, vagy melyik fordulóban kaptak ki először.
public void Feladat06()
{
var eloszorkikapott = _meccsek.FirstOrDefault(m => m.HazaiCsapat == _csapatnev && m.HazaiGol < m.VendegGol);
if (eloszorkikapott == null)
{
Console.WriteLine("A csapat otthon veretlen maradt.");
}
else
{
Console.WriteLine("A {0}. fordulóban kapott ki otthon", eloszorkikapott.Fordulo);
}
}
- Készítsen statisztikát, amely megadja, hogy az egyes végeredmények hány alkalommal fordultak elő! Tekintse egyezőnek a fordított eredményeket (például 4-2 és 2-4)! A nagyobb számot mindig előre írja! Az elkészült listát a stat.txt állományban helyezze el!
A végére egy fájl írásos feladat egy kis statisztikával kombinálva. A statisztikai adatok kezeléséhez nagyon jól használható a Dictionary típus. Jelen esetben a kulcs szövegként tárolva a meccs végeredménye lesz. Pl. 4-2. Viszont mivel az, hogy a csapat hazaiként játszott vagy vendégként, a jelenlegi feladat szempontjából mindegy. Éppen ezért mind a két esetű kulcsot előállítjuk, és ha már van ilyen a Dictionary szerkezetben, akkor növeljük a darabszámot. Ha meg nincs ilyen, akkor 1-es darabszámmal rögzítjük.
A kiírás ezek után nem bonyolult. Végigmegyünk az előállított elemeken és kiírjuk a kulcsot, illetve a hozzá tartozó értéket formázottan.
public void Feladat07()
{
var statisztika = new Dictionary<string, int>();
foreach (var meccs in _meccsek)
{
string par1 = $"{meccs.HazaiGol}-{meccs.VendegGol}";
string par2 = $"{meccs.VendegGol}-{meccs.HazaiGol}";
if (statisztika.ContainsKey(par1))
{
++statisztika[par1];
}
else if (statisztika.ContainsKey(par2))
{
++statisztika[par2];
}
else
{
statisztika.Add(par1, 1);
}
}
using (var file = File.CreateText("stat.txt"))
{
foreach (var stat in statisztika)
{
file.WriteLine("{0}: {1} darab", stat.Key, stat.Value);
}
}
}