Informatika érettségi 2006. Május
Az előző érettségihez hasonlóan itt is egy összetett adattípussal kell dolgozni, de ezen érettségi esetén az igazán nehéz a domain tudás elsajátítása rövid idő alatt. A feladat a fehérjék és az aminosavak világába vezet be bennünket viszonylag részletesen és ezekhez kapcsolódó feladatokat állít elébünk.
A feladatkiírás
A fehérjék óriás molekulák, amelyeknek egy része az élő szervezetekben végbemenő folyamatokat katalizálják. Egy-egy fehérje aminosavak százaiból épül fel, melyek láncszerűen kapcsolódnak egymáshoz. A természetben a fehérjék fajtája több millió. Minden fehérje húszféle aminosav különböző mennyiségű és sorrendű összekapcsolódásával épül fel.
Az alábbi táblázat tartalmazza az aminosavak legfontosabb adatait, a megnevezéseket és az őket alkotó atomok számát (az aminosavak mindegyike tartalmaz szenet, hidrogént, oxigént és nitrogént, néhányban kén is van):
Készítsen programot feherje néven, ami megoldja a következő feladatokat! Ügyeljen arra, hogy a program forráskódját a megadott helyre mentse!
- Töltse be az aminosav.txt fájlból az aminosavak adatait! A fájlban minden adat külön sorban található, a fájl az aminosavak nevét nem tartalmazza. Ha az adatbetöltés nem sikerül, vegye fel a fenti táblázat alapján állandóként az első öt adatsort, és azzal dolgozzon!
Az első néhány adat:
Gly
G
2
5
2
1
0
Ala
A
3
7
2
1
0
…
- Határozza meg az aminosavak relatív molekulatömegét, ha a szén atomtömege 12, a hidrogéné 1, az oxigéné 16, a nitrogéné 14 és a kén atomtömege 32! Például a Glicin esetén a relatív molekulatömeg 2·12 + 5·1 + 2·16 + 1·14 + 0·32 = 75.
A következő feladatok eredményeit írja képernyőre, illetve az eredmeny.txt fájlba! A kiírást a feladat sorszámának feltüntetésével kezdje (például: 4. feladat)!
- Rendezze növekvő sorrendbe az aminosavakat a relatív molekulatömeg szerint! Írja ki a képernyőre és az eredmeny.txt fájlba az aminosavak hárombetűs azonosítóját és a molekulatömeget! Az azonosítót és hozzátartozó molekulatömeget egy sorba, szóközzel elválasztva írja ki!
- A bsa.txt a BSA nevű fehérje aminosav sorrendjét tartalmazza – egybetűs jelöléssel. (A fehérjelánc legfeljebb 1000 aminosavat tartalmaz.) Határozza meg a fehérje összegképletét (azaz a C, H, O, N és S számát)! A meghatározásánál vegye figyelembe, hogy az aminosavak összekapcsolódása során minden kapcsolat létrejöttekor egy vízmolekula (H2O) lép ki! Az összegképletet a képernyőre és az eredmeny.txt fájlba az alábbi formában írja ki:Például: C 16321 H 34324 O 4234 N 8210 S 2231
- A fehérjék szekvencia szerkezetét hasításos eljárással határozzák meg. Egyes enzimek bizonyos aminosavak után kettéhasítják a fehérjemolekulát. Például a Kimotripszin enzim a Tirozin (Y), Fenilalanin (W) és a Triptofán (F) után hasít.Határozza meg, és írja ki képernyőre a Kimotripszin enzimmel széthasított BSA lánc leghosszabb darabjának hosszát és az eredeti láncban elfoglalt helyét (első és utolsó aminosavának sorszámát)! A kiíráskor nevezze meg a kiírt adatot, például: „kezdet helye:”!
- Egy másik enzim (a Factor XI) az Arginin (R) után hasít, de csak akkor, ha Alinin (A) vagy Valin (V) követi. Határozza meg, hogy a hasítás során keletkező első fehérjelánc részletben hány Cisztein (C) található! A választ teljes mondatba illesztve írja ki a képernyőre!
Az adatstruktúra
Aminosavakkal kell dolgoznunk. Egy Aminosav rendelkezik rövidítéssel és betűjellel, valamint felsorolt darabszámú különböző atomból áll. Ezt egy osztályban könnyen modellezhetjük.
A RelativTomeg számításra a 2. és 3. feladatban szükségünk lesz, ezért ezt már itt egy csak olvasható tulajdonságként érdemes implementálni.
public class Aminosav
{
public string Rovidites { get; set; }
public string Betujel { get; set; }
public int C { get; set; }
public int H { get; set; }
public int O { get; set; }
public int N { get; set; }
public int S { get; set; }
public int RelativTomeg
{
get
{
return (C * 12) + H + (O * 16) + (N * 14) + (S * 32);
}
}
public Aminosav()
{
Rovidites = string.Empty;
Betujel = string.Empty;
}
}
A megoldás
- Töltse be az aminosav.txt fájlból az aminosavak adatait! A fájlban minden adat külön sorban található, a fájl az aminosavak nevét nem tartalmazza. Ha az adatbetöltés nem sikerül, vegye fel a fenti táblázat alapján állandóként az első öt adatsort, és azzal dolgozzon!
Ez az érettségi feladat is a „Kreténebbik” fajtából való, vagyis több sornyi adat beolvasása kell egy Aminosav osztály előállításához. Hasonlóan az előző érettségi feladathoz, itt is a sorok számolásában rejlik a kulcs. A beolvasó, ami itt készült, az nem bolondbiztos, vagyis csak arra van felkészítve, hogy a sorok száma 7 többszöröse. Egy, a való életben hibavédelemmel ellátott változat bőven több sor lenne.
Lényegében 7 sort olvasunk egy átmeneti bufferbe, amiből majd megfelelő átalakítás után fel tudjuk tölteni az Aminosav osztály példányunkat. Az aminosavak listáját a _aminosavak List<Aminosav> típusú változó tárolja a megoldás osztályunkban.
public void Feladat01()
{
using (var file = File.OpenText("aminosav.txt"))
{
string? sor = string.Empty;
string[]? buffer = null;
do
{
buffer = new string[7];
for (int i=0; i<7; i++)
{
sor = file.ReadLine();
if (string.IsNullOrEmpty(sor))
{
buffer = null;
break;
}
buffer[i] = sor;
}
if (buffer != null)
{
_aminosavak.Add(new Aminosav
{
Rovidites = buffer[0],
Betujel = buffer[1],
C = int.Parse(buffer[2]),
H = int.Parse(buffer[3]),
O = int.Parse(buffer[4]),
N = int.Parse(buffer[5]),
S = int.Parse(buffer[6]),
});
}
}
while (sor != null);
}
}
- Határozza meg az aminosavak relatív molekulatömegét, ha a szén atomtömege 12, a hidrogéné 1, az oxigéné 16, a nitrogéné 14 és a kén atomtömege 32! Például a Glicin esetén a relatív molekulatömeg 2·12 + 5·1 + 2·16 + 1·14 + 0·32 = 75.
A második feladat megoldása a Aminosav osztályban található tulajdonságként. Itt megjegyzem, hogy a korrekt számítási eredmény és az olvashatóság érdekében minden esetben zárójelezzük a kifejezéseinket úgy, ahogy mi szeretnénk kiértékelni, mert lehet nekünk egyértelmű az 1+1*1+1 kifejezés eredménye, de sajnos sokaknak nem és a fordító sem biztos, hogy azt gondolja eredménynek, mint amit mi gondolunk.
- Rendezze növekvő sorrendbe az aminosavakat a relatív molekulatömeg szerint! Írja ki a képernyőre és az eredmeny.txt fájlba az aminosavak hárombetűs azonosítóját és a molekulatömeget! Az azonosítót és hozzátartozó molekulatömeget egy sorba, szóközzel elválasztva írja ki!
Mivel az előző feladat megoldását tulajdonságként implementáltuk az osztályban, ezért nagyon egyszerű LINQ segítségével a tulajdonságunk alapján sorba rendezni, majd kiírni az elemeket.
Itt egy trükk van, méghozzá az, hogy fájlba kell írni a 3., 4., 5., és 6. feladat eredményét. Ezt igazán szépen úgy kellene megoldani, hogy a 3., 4., 5., és 6. feladat hívás között bezárjuk a fájlt, amit írunk és a feladat elején nyitjuk újra. Viszont a kiírásunk rövidsége miatt jelen esetben a program futása alatt nyitva marad a fájl és majd csak a műveletek elvégzése után engedjük el.
A fájl megnyitása írásra már a Megoldas osztály konstruktorában megtörténik és a fájlba a _eredmeny StreamWriter típusú változón keresztül tudunk írni.
A megoldás osztályunk jelen esetben azért implementálja az IDisposable felületet, hogy a natív fájl erőforrás elengedéséről egy using blokk segítségével gondoskodni tudjunk a főprogramban.
public void Feladat03()
{
var rendezett = _aminosavak.OrderBy(a => a.RelativTomeg);
foreach (var aminosav in rendezett)
{
_eredmeny?.WriteLine("{0} {1}", aminosav.Rovidites, aminosav.RelativTomeg);
Console.WriteLine("{0} {1}", aminosav.Rovidites, aminosav.RelativTomeg);
}
}
- A bsa.txt a BSA nevű fehérje aminosav sorrendjét tartalmazza – egybetűs jelöléssel. (A fehérjelánc legfeljebb 1000 aminosavat tartalmaz.) Határozza meg a fehérje összegképletét (azaz a C, H, O, N és S számát)! A meghatározásánál vegye figyelembe, hogy az aminosavak összekapcsolódása során minden kapcsolat létrejöttekor egy vízmolekula (H2O) lép ki! Az összegképletet a képernyőre és az eredmeny.txt fájlba az alábbi formában írja ki: Például:
C 16321 H 34324 O 4234 N 8210 S 2231
Ismételten egy fájl olvasás, de hogy ne legyen annyira egyszerű, kombinálva van a dolog egy számítással is. És hogy igazán nehéz legyen a dolog, csak példa van megadva, konkrét eredmény nincs.
Első körben be kell olvasnunk a bsa.txt állományt, amibe valaki soronként felvitte az aminosavakat betűjellel. Ezek alapján a korábban beolvasott aminosavakból ki kell keresnünk a megfelelőt, majd az összegképletet kell meghatároznunk, figyelembe véve, hogy minden egyes aminosav összekapcsolódás után H2O keletkezik, vagyis az összeadásnál már eleve ki kell vonni a H értékből kettőt, az O értékből pedig egyet.
Itt viszont hiányos egy kicsit a feladat leírása, mivel nem lehet tudni, hogy van-e olyan aminosav, amiben nincs hidrogén és oxigén atom. Ez azért lenne fontos információ, mert a „beégetett” hidrogén és oxigén kivonás a számítás közben nagyon extrém esetben eredményezhetne negatív darabszámot ezen alkotóelemek esetén, ami a való életben nem fordulhat elő.
A konkrét implementáció esetén, mivel a sorok csak egy betűt tartalmaznak, felesleges lenne egy listában tárolni őket, helyette a StringBuilder osztály segítségével a sorok elemeit kombináljuk egy string típusba. Mivel az 5. feladat is épít a beolvasott fájl eredményére, ezért ezt a szöveget a _bsalanc változó tárolja a megoldás osztályunkban.
Ezután végigmegyünk a lánc elemein, megkeressük a betűjelhez tartozó aminosavat LINQ segítségével és összeadjuk, hogy miből mennyi van az adott aminosavban, majd az összegzés eredményét formázottan kiírjuk a fájlba és a képernyőre.
public void Feladat04()
{
const int h2o = 18; //ezt majd le kell vonni összeadás után
List<Aminosav> bsaFeherje = new List<Aminosav>();
//bsa.txt beolvaása
StringBuilder bsaLanc = new StringBuilder(); //később lesz rá szükség
using (var bsa = File.OpenText("bsa.txt"))
{
string? sor = null;
do
{
sor = bsa.ReadLine();
if (sor != null)
{
bsaLanc.Append(sor);
var aminosav = _aminosavak.FirstOrDefault(a => a.Betujel == sor);
bsaFeherje.Add(aminosav);
}
}
while (sor != null);
}
_bsalanc = bsaLanc.ToString();
//számolás
int c =0, h = 0, o = 0, n = 0, s = 0;
foreach (var aminosav in bsaFeherje)
{
c += aminosav.C;
h += (aminosav.H - 2); //h2O keletkezés miatt
o += (aminosav.O - 1); //h2o keletkezés miatt
n += aminosav.N;
s += aminosav.S;
}
_eredmeny?.WriteLine("C {0} H {1} O {2} N {3} S {4}", c, h, o, n, s);
Console.WriteLine("C {0} H {1} O {2} N {3} S {4}", c, h, o, n, s);
}
- A fehérjék szekvencia szerkezetét hasításos eljárással határozzák meg. Egyes enzimek bizonyos aminosavak után kettéhasítják a fehérjemolekulát. Például a Kimotripszin enzim a Tirozin (Y), Fenilalanin (W) és a Triptofán (F) után hasít. Határozza meg, és írja ki képernyőre a Kimotripszin enzimmel széthasított BSA lánc leghosszabb darabjának hosszát és az eredeti láncban elfoglalt helyét (első és utolsó aminosavának sorszámát)! A kiíráskor nevezze meg a kiírt adatot, például: „kezdet helye:”!
Ez viszonylag egy egyszerű feladat, de a sok ismeretlen szó és adat miatt bonyolultnak tűnhet.
Szintén végig kell menni a lánc elemein és megfelelő karakterek mentén fel kell vágni a szöveget kisebb szövegekre. Erre használhattuk volna a string osztály Split() metódusát megfelelő paraméterezéssel, de sajátot írni sem nehéz erre a célra.
A megoldáshoz kell egy buffer, amibe a karaktereket egyesével rakjuk. Ha olyan karakterhez érünk, ami alapján vágni kell, akkor a buffer tartalmát egy listához fűzzük, majd a buffert töröljük. Ezt a lépéssorozatot a szöveg végéig ismételve kapunk egy szövegekből álló listát, ami a bemeneti szövegünket a megadott karakterek mentén feldarabolta.
Ezekből ez után ki kell választani a leghosszabbat, majd megmondani, hogy az a fájl melyik sorában kezdődik.
A leghosszabb meghatározása LINQ segítségével itt is pofon egyszerű. Miután ez megvan, meg kell keresnünk, hogy az eredeti beolvasott láncban hol kezdődik ez a szövegrészlet. Ezt a string IndexOf() metódusával könnyen meg tudjuk határozni. A kapott szám pedig a sor száma lesz, mivel az eredeti fájlban egy sorban egy betű volt található.
A kapott eredményeket itt is szintén fájlba és a képernyőre is ki kell írnunk.
public void Feladat05()
{
List<string> hasitott = new List<string>();
StringBuilder buffer = new StringBuilder();
foreach (var chr in _bsalanc)
{
buffer.Append(chr);
if (chr == 'Y' || chr == 'W' || chr == 'F')
{
hasitott.Add(buffer.ToString());
buffer.Clear();
}
}
string leghosszabb = hasitott
.OrderByDescending(h => h.Length)
.FirstOrDefault();
int kezdete = _bsalanc.IndexOf(leghosszabb);
int vege = kezdete + leghosszabb.Length;
Console.WriteLine("Leghosszabb darab hossza: {0}, pozíciója: {1} - {2}", leghosszabb.Length, kezdete, vege);
_eredmeny?.WriteLine("Leghosszabb darab hossza: {0}, pozíciója: {1} - {2}", leghosszabb.Length, kezdete, vege);
}
- Egy másik enzim (a Factor XI) az Arginin (R) után hasít, de csak akkor, ha Alinin (A) vagy Valin (V) követi. Határozza meg, hogy a hasítás során keletkező első fehérjelánc részletben hány Cisztein (C) található! A választ teljes mondatba illesztve írja ki a képernyőre!
Az utolsó feladat lényegében az előző egy kicsavart változata, hogy tényleg ne legyen egyszerű az életünk. A felvágás esetén különbség csak a feltételben van, illetve abban, hogy hogyan kezeljük azt az esetet, hogy ha a szöveg végére értünk és szükségünk lenne még egy elemre, hogy megállapítsuk, mi a következő elem.
Az összegzés rész ezután LINQ segítségével megtehető, majd ismételten formázottan ki kell írnunk fájlba és képernyőre az eredményt.
public void Feladat06()
{
string elso = string.Empty;
StringBuilder buffer = new StringBuilder();
for (int i=0; i<_bsalanc.Length; i++)
{
char chr = _bsalanc[i];
//ha nincs következő, mert a végén vagyunk, akkor egy '0' karakter a következő
char kovetkezo = i + 1 < _bsalanc.Length ? _bsalanc[i + 1] : '0';
buffer.Append(chr);
if (chr == 'R' && (kovetkezo == 'A' || kovetkezo == 'V'))
{
elso = buffer.ToString();
break;
}
}
int cisztein = elso.Count(chr => chr == 'C');
Console.WriteLine("A hasítás során keletkező első fehérjelánc részletben {0} Cisztein található", cisztein);
_eredmeny?.WriteLine("A hasítás során keletkező első fehérjelánc részletben {0} Cisztein található", cisztein);
}
Összességében a korábbi érettségikhez képest ez a feladatsor brutálisan nehéz.
Egyrészt a domain absztraktsága miatt nehéz végiggondolni. A másik buktatója a feladatsornak a rengeteg összegzés és keresés, ami LINQ nélkül igencsak megdobná a kód méretét. És akkor még nem beszéltünk a szinte mindenhol elvárás formázott file és képernyőre írásról, amit hajlamos az ember CTRL+C és CTRL+V kombinációval másolni, vagy szimplán elveszve a részletek között kihagyni és emiatt pontot veszíteni.
