Sokan szerencsés vagy balszerencsés napnak tartják a péntek tizenharmadikát. Évente 1-2-3 alkalommal megtörténik, hogy a hónap 13. napja péntekre esik (minden vasárnap kezdődő hónapban). A hónap 13. napja valamivel valószínűbben péntekre esik, mint a hét bármely más napja. Átlagosan 212,35 naponként fordul elő péntek 13. Előfordulhat két egymást követő hónapban is, de akár 14 hónap is eltelhet két péntek 13 között.
A nap említése sok helyen előfordult: regényekben, filmekben, híres emberek születése vagy halála is esett péntek 13-ra. Átlag alatti közlekedési baleset szokott előfordulni ezeken a napokon – talán mert az emberek óvatosabbak. Kimutatható összefüggést/korrelációt, „péntek 13 hatást” figyeltek meg a tőzsdén is.
Hasznos lehet, ha írunk egy Java programot, amely néhány egymást követő év esetén listázza a konzolra azokat a hónapokat, amikor 13-a péntekre esik.
Tervezés
Legyen egy
listFriday13(year) eljárás, amely a paraméterként átvett évben kiírja azokat a hónapokat a konzolra, amelyekben 13-a péntekre esett/esik. Például:
2017: január, október. A hónapok nevei magyar nyelven jelenjenek meg. Az adott év hónapjain végighaladó ciklus legyen hatékony. Optimalizáljunk a ciklus lépésszámára! A ciklus álljon le, ha már talált 3 hónapot (mivel nem lehet több).
1. megoldás
A megoldást a tematika Tömbök témakörében az alábbiak szerint készíthetjük el. Előismeretek: változók, operátorok, ciklusok, programozási tételek, metódusok, tömbök,
String összehasonlítás. Az ismert öröknaptár algoritmusokból implementáljuk az egyiket, például:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
static boolean isLeapYear(int year) { return (year>=1582) && ((year%4==0 && year%100!=0) || (year%400==0)); } public static String dayOfWeek(int year, int month, int day) { int centuryCode=2*(3-year/100%4); int yearOfCentury=year%100; int monthCode=new int[] {-1, isLeapYear(year)?6:0, isLeapYear(year)?2:3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 }[month]; int dayCode=(centuryCode+yearOfCentury+ yearOfCentury/4+monthCode+day)%7; return new String[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }[dayCode]; } public static void listFriday13v1(int year) { String[] months={"", "január", "február", "március", "április", "május", "június", "július", "augusztus", "szeptember", "október", "november", "december"}; System.out.print(year+": "); for(int month=1, count=1; month<=12 && count<=3; month++) if(dayOfWeek(year, month, 13).equals("Friday")) { System.out.print(months[month]+", "); count++; } System.out.println(); } |
A
listFriday13v1(year) eljárásban az elemi döntés egyszerű:
dayOfWeek(year, month, 13).equals("Friday"). Épít az öröknaptárt megvalósító – saját – szöveget visszaadó függvényre. A függvény az algoritmus szerinti kódok előállításához (
centuryCode,
monthCode,
dayCode) felhasználja a szökőév (
isLeapYear(year)) függvényt, valamint két – konstansnak is tekinthető – névtelen tömböt (
new int[],
new String[]).
2. megoldás
A megoldást a tematika Objektumorientált programozás témakörében az alábbiak szerint készíthetjük el. Felhasználjuk eddigi ismereteinket és a JDK beépített dátumkezelő (tároló, formázó) funkcióit (osztályok, interfészek, konstansok, felsorolások).
|
public static void listFriday13v2(int year) { SimpleDateFormat dfMonth= new SimpleDateFormat("MMMM", new Locale("hu")); ArrayList<String> listMonths=new ArrayList<>(); for(int month=1, count=1; month<=12 && count<=3; month++) { GregorianCalendar date=new GregorianCalendar(year, month-1, 13); if(date.get(Calendar.DAY_OF_WEEK)==Calendar.FRIDAY) { listMonths.add(dfMonth.format(date.getTime())); count++; } } System.out.println(year+": "+String.join(", ", listMonths)); } |
A
listFriday13v2(year) eljárás a
Calendar absztrakt osztály konstansait használja fel az elemi döntéshez:
date.get(Calendar.DAY_OF_WEEK)==Calendar.FRIDAY. A dátumot a
GregorianCalendar konstruktora példányosítja és figyelni kell a 0-bázisú hónapkezelésre. A dátum formázása során (
dfMonth) beállítjuk a megfelelően paraméterezett (
"hu")
Locale típusú objektumot és a hónap hosszú nevét kérjük (
"MMMM"). A metódus generikus listába gyűjti a kiválasztott hónapok nevét, amiket végül a
String.join() függvény fűz össze a megjelenítéshez.
Eredmény
A vezérlésben egy ciklus 2017-től 2036-ig szervezve az alábbi eredményt adja:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
Péntek 13 előfordulások 2017: január, október 2018: április, július 2019: szeptember, december 2020: március, november 2021: augusztus 2022: május 2023: január, október 2024: szeptember, december 2025: június 2026: február, március, november 2027: augusztus 2028: október 2029: április, július 2030: szeptember, december 2031: június 2032: február, augusztus 2033: május 2034: január, október 2035: április, július 2036: június |
A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.
A feladat a Java SE szoftverfejlesztő tanfolyam tematikájához kötődik a fentiek szerint: 13-16. óra: Tömbök alkalom, illetve 17-28. óra: Objektumorientált programozás alkalom.
Aki gyakorolna a témához kötődően: írjon olyan Java programot, ami listázza a konzolra a 21. század éveit olyan hónapokba csoportosítva, amikor 13-a péntekre esik. Egy év többször is előfordulhat. Például: január – 2006, 2012, 2017, 2023, 2034, 2040, 2045, 2051, 2062, 2068, 2073, 2079, 2090, 2096. A megoldásokat hallgatóinktól az ILIAS-ra, érdeklődőinktől hozzászólásban várjuk.