BME Villamosmérnöki és Informatikai Kar
Mérnök-informatikus alapszak
Nappali tagozat
2015/2016-es tanév, őszi félév

Deklaratív programozás

3. kis házi feladat: Felesleges értékek elhagyása

1.0 változat
Utolsó módosítás: 2015-11-02
Kiadás: 2015-10-01
Beadási határidő: Erlang 2015-11-04, 23:59; Prolog 2015-11-04, 23:59

Bevezetés

A feladat a Mastermind játékhoz kapcsolódik, ezért kérjük, először olvassa el a jelen félév nagy házi feladatát.

Tekintsünk egy, a féléves nagy házi feladatban specifikált Mastermind-feladványt. Legyen Max a kódban megengedett maximális érték, míg H a kód hossza, azaz elemeinek a száma. A feladvány megoldásához érdemes bevezetni a közelítő megoldás adatstruktúrát, amelyben nyilvántarthatjuk, hogy a titkos kód egyes pozícióin (a tábla oszlopaiban) milyen értékek lehetségesek.

Egy (Max, H) paraméterű Mastermind-feladvány esetén közelítő megoldásnak nevezünk egy olyan H hosszúságú listát, amelynek elemei az 1..Max intervallumba eső egész számokból képzett, szigorúan monoton növő értéklisták. Egy közelítő megoldás érvényes, ha nincs benne üres lista.

Egy közelítő megoldás valójában titkos kódok egy halmazát határozza meg, nevezetesen azokat a kódokat, amelyeket úgy kapunk, hogy a közelítő megoldás minden egyes pozíciójáról egy elemet kiválasztunk. Például a [[3],[1,2,3,4],[1,2]] közelítő megoldás az alábbi nyolcelemű megoldáshalmazt határozza meg:

{ [3,1,1], [3,2,1], [3,3,1], [3,4,1],
  [3,1,2], [3,2,2], [3,3,2], [3,4,2] }.
Ezeket a titkos kódokat a közelítő megoldáshoz tartozó kódoknak fogjuk nevezni.

A lehető legáltalánosabb közelítő megoldás az a H hosszú értéklista, amelynek minden eleme az [1,2,...,Max] lista. Ez a közelítés nyilván nem tesz semmilyen megszorítást a megoldásra. A nagy házi feladat megoldása során viszont szűkíthetjük a közelítő megoldást, azaz bizonyos elemeket elhagyhatunk belőle a súgás-lista alapján. Ha például a súgás-listában van egy olyan tipp, pl. a [2,3,1], amelyhez 0 fekete válaszpálcika tartozik, akkor (a fehér válaszpálcikák számától függetlenül) biztosak lehetünk abban, hogy az első pozíción nincs 2-es, a második pozíción nincs 3-as, és a harmadik pozíción nincs 1-es érték. Tehát ezek az értékek feleslegesek, azaz elhagyhatók a közelítő megoldás adott pozícióján levő értéklistából (feltéve, hogy még benne vannak ebben a listában).

Ebben a kis házi feladatban egy érvényes közelítő Mastermind-megoldást kell szűkíteni egy tipp és a hozzá tartozó fekete válaszpálcikák, azaz a pontos találatok száma alapján. Arról nincs információnk, hogy az adott tipphez hány fehér válaszpálcika tartozik, ezek száma tetszőleges lehet.

Mielőtt a feladatot specifikálnánk, bemutatunk néhány példát. A példák mindegyikében Max = 4 és H = 3, a megadott közelítő megoldás pedig a [[3],[1,2,3,4],[1,2]] lista. Ez utóbbi azt jelenti, hogy valamilyen módon már kikövetkeztettük, hogy az első pozíción csak a 3-as érték lehet, az utolsón csak az 1 és 2 közül valamelyik, míg a középsőn a négy megengedett érték bármelyike állhat. Az eddig felsorolt bemeneti információk mellett az alábbi példákban megadunk még egy-egy tippet és a rájuk kapott fekete válaszpálcikák számát.

Először vizsgáljuk meg azt az esetet, amikor a [3,2,1] tipphez 1 fekete (és általunk nem ismert számú fehér) válaszpálcika tartozik. Mivel az első pozíción a kódban csak a 3 érték lehet, és a tippben is ez az érték szerepel ezen a helyen, ezért az egyetlen pontos találat az első pozíción lehet csak. Ebből következik, hogy a tippben a többi pozíción felsorolt értékek nem lehetnek pontos találatok. Így a 2. pozíción levő 2-es, és a 3. pozíción levő 1-es érték felesleges, azaz elhagyható a közelítő megoldásból. A kapott információ alapján tehát ezt a [[3],[1,3,4],[2]] közelítésre szűkíthetjük le.

Második – az előzőtől független – példánkban azt az információt kapjuk, hogy a [3,4,3] tippben 2 pontos találat van. Mivel az utolsó pozíción nem lehet pontos találat (a tippben levő 3-as szám nem szerepel a közelítő megoldás utolsó pozícióján levő értéklistában), ezért az első és a második pozíción lehetnek csak a pontos találatok, tehát a közelítő megoldást leszűkíthetjük a [[3],[4],[1,2]] listára (azaz az adott tipp-információ alapján a 2. pozíción levő 1-es, 2-es és 3-as értékek feleslegesekké válnak).

Harmadik – szintén az előzőektől független – példánkban azt az információt kapjuk, hogy a [2,2,3] tippben 2 pontos találat van. Ha összevetjük ezt a tippet a közelítő megoldással, akkor láthatjuk, hogy pontos találat nem lehetséges sem az első, sem a harmadik pozíción. Így legfeljebb egy pontos találat lehet, ami ellentmond a kapott információnak. A kis házi feladatnak jeleznie kell az ilyen jellegű ellentmondásokat, az alábbiakban részletezett (nyelvenként eltérő) módon.

A feladat

Egy adott, érvényes KM közelítő megoldásból – egy Tipp tipp és a hozzá tartozó pontos találatok P száma alapján – el kell hagyni az összes felesleges értéket. A KM lista i-edik pozícióján levő értéklista egy X eleme felesleges a Tipp-P párra nézve, ha abból, hogy a keresett titkos kód a KM-hez tartozik és a Tipp tippre P pontos találatot ad, következik, hogy a titkos kód i-edik pozícióján nem szerepelhet az X érték. Megjegyezzük, hogy a feladat megoldásához elegendő a fenti három példában használt következtetési lépések megvalósítása, természetesen általánosított formában.

Ha egy olyan felesleges elemet kell elhagynunk, amely már csak önmagában szerepel az adott pozíción, akkor érvénytelen közelítő megoldáshoz jutunk. Könnyen belátható, hogy ebben az esetben a közelítő megoldásban szereplő összes elem felesleges, azaz az eredménynek csupa üres listából kell állnia. Ez az elfajuló eset azt jelzi, hogy ellentmondás van a közelítő megoldás és a tipp-információ között.

A másik véglet az, hogy az adott KM közelítő megoldás eleve nem tartalmaz felesleges értéket. Ilyenkor értelemszerűen a KM-ből egyetlen értéket sem kell elhagyni.

A feladat bemenetei:

A feladat kimenete az az UjKM érvényes közelítő megoldás, amely a KM-ből a Tipp-P párra nézve felesleges elemek elhagyásával áll elő. Ha az így előálló megoldás érvénytelen, akkor a Prolog eljárás hiúsuljon meg, az Erlang függvény pedig az invalid_approx atomot adja eredményül.

Kiegészítésül megadjuk a felesleges érték fogalmának egy másfajta, a fentivel ekvivalens meghatározását is.

Egy KM közelítő megoldás i-edik pozícióján levő értéklista egy X eleme felesleges a Tipp-P párra nézve, ha a KM közelítő megoldáshoz tartozó titkos kódok között nincs olyan TK titkos kód, amely a Tipp tippre P darab pontos találatot ad, és amelyben az i-edik pozíción az X érték áll.

A definíció megértését segíti az alábbi példa.

Legyen KM=[[3],[1,2,3,4],[1,2]]. A KM közelítő megoldáshoz tartozó titkos kódok listája a TKL=[[3,1,1], [3,2,1], [3,3,1], [3,4,1], [3,1,2], [3,2,2], [3,3,2], [3,4,2]] lista.

Nézzük a Tipp=[3,2,1] és P=1 esetet. A TKL lista elemei közül a Tipp tippre a következők adnak P darab pontos találatot: [3,1,2], [3,3,2], [3,4,2]. Felesleges tehát a 2 érték a KM közelítő megoldás 2. értéklistájában, mert egyetlen P darab pontos találatot adó titkos kódban sem fordul elő a 2. pozícióban. Felesleges még a KM közelítő megoldás 3. értéklistájában az 1 érték is.

Prolog-specifikációk

Írjon Prolog-eljárást szukitese/3 néven az összes, egy adott párra nézve felesleges érték elhagyására egy adott közelítő megoldásból.
% :- type code          == list(int).
% :- type simple_hint ---> code-int.
% :- type approx        == list(list(int))

% :- pred szukitese(approx::in, simple_hint::in, approx::out).

% szukitese(KM0, Tipp_P, KM): A KM érvényes közelítő megoldás a KM0
% közelítésből a Tipp_P párra nézve felesleges értékek elhagyásával áll elő.

Erlang-specifikációk

Írjon Erlang-függvényt szukitese/2 néven az összes, egy adott párra nézve felesleges érték elhagyására egy adott közelítő megoldásból.
%% @type code()            = [integer()].
%% @type simple_hint()     = {code(),integer()}.
%% @type approx()          = [code()].
%% @type optional_approx() = approx() | invalid_approx.

%% @spec khf3:szukitese(KM0::approx(),Tipp_P::simple_hint()) -> KM::optional_approx().
%% @doc  A KM közelítő megoldás a KM0 közelítésből a Tipp_P párra
%%       nézve felesleges értékek elhagyásával áll elő. Ha nincs
%%       érvényes megoldás, KM értéke az invalid_approx atom.
A programot tartalmazó modul attribútumai ezek legyenek:
-module(khf3).
-author('email@unit.org.hu').
-vsn('year-mm-dd').
-export([szukitese/2]).
%-compile(export_all).

Példák

Prolog

| ?- szukitese([[3],[1,2,3,4],[1,2]], [3,2,1]-1, KM).
KM = [[3],[1,3,4],[2]] ? ;
no
| ?- szukitese([[3],[1,2,3,4],[1,2]], [3,4,3]-2, KM).
KM = [[3],[4],[1,2]] ? ;
no
| ?- szukitese([[3],[1,2,3,4],[1,2]], [2,2,3]-2, KM).
no
| ?- szukitese([[3],[1,2,3,4],[1,2]], [2,2,3]-1, KM).
KM = [[3],[2],[1,2]] ? ;
no
| ?- szukitese([[3],[1,2,3,4],[1,2]], [2,2,3]-0, KM).
KM = [[3],[1,3,4],[1,2]] ? ;
no
| ?- szukitese([[3],[1,2,3,4],[1,2]], [3,2,2]-2, KM).
KM = [[3],[1,2,3,4],[1,2]] ? ;
no
| ?- szukitese([[3],[1,2,3,4],[1,2]], [3,2,1]-2, KM).
KM = [[3],[1,2,3,4],[1,2]] ? ;
no
| ?- szukitese([[1,2,4],[1,3,4],[1,2,3]], [3,2,1]-3, KM).
no
| ?- szukitese([[1,2,4],[1,3,4],[1,2,3]], [2,3,1]-3, KM).
KM = [[2],[3],[1]] ? ;
no
| ?- szukitese([[1,2,4],[1,3,4],[1,2,3]], [2,3,1]-0, KM).
KM = [[1,4],[1,4],[2,3]] ? ;
no
| ?- szukitese([[1,2,4],[1,3,4],[1,2,3]], [2,3,1]-1, KM).
KM = [[1,2,4],[1,3,4],[1,2,3]] ? ;
no
| ?-

Erlang

1> khf3:szukitese([[3],[1,2,3,4],[1,2]], {[3,2,1],1}).
[[3],[1,3,4],[2]]

2> khf3:szukitese([[3],[1,2,3,4],[1,2]], {[3,4,3],2}).
[[3],[4],[1,2]]

3> khf3:szukitese([[3],[1,2,3,4],[1,2]], {[2,2,3],2}).
invalid_approx

4> khf3:szukitese([[3],[1,2,3,4],[1,2]], {[2,2,3],1}).
[[3],[2],[1,2]]

5> khf3:szukitese([[3],[1,2,3,4],[1,2]], {[2,2,3],0}).
[[3],[1,3,4],[1,2]]

6> khf3:szukitese([[3],[1,2,3,4],[1,2]], {[3,2,2],2}).
[[3],[1,2,3,4],[1,2]]

7> khf3:szukitese([[3],[1,2,3,4],[1,2]], {[3,2,1],2}).
[[3],[1,2,3,4],[1,2]]

8> khf3:szukitese([[1,2,4],[1,3,4],[1,2,3]], {[3,2,1],3}).
invalid_approx

9> khf3:szukitese([[1,2,4],[1,3,4],[1,2,3]], {[2,3,1],3}).
[[2],[3],[1]]

10> khf3:szukitese([[1,2,4],[1,3,4],[1,2,3]], {[2,3,1],0}).
[[1,4],[1,4],[2,3]]

11> khf3:szukitese([[1,2,4],[1,3,4],[1,2,3]], {[2,3,1],1}).
[[1,2,4],[1,3,4],[1,2,3]]

Tudnivalók a beadásról

A programok készülhetnek MS Windows alatt is, de Linux alatt is működniük kell. A beadott programokat Linux környezetben a SICStus Prolog 4.2.x, ill. az Erlang/OTP R14A rendszerekkel teszteljük.

Ennek a kis házi feladatnak a beadása ugyan nem kötelező, azonban a félévközi követelmények teljesítéséhez a félév során legalább három kisházifeladat-megoldást – közülük legalább egyet Prolog és legalább egyet Erlang nyelven – sikeresen be kell adni. Sikeres az a megoldás, amelyik az összes tesztesetre helyes választ ad. Ha ezt a kis házi feladatot mindkét nyelven sikeresen beadja, az természetesen két megoldásnak számit.

A programot az Elektronikus Tanársegéd (ETS) segítségével weben keresztül lehet beadni, a HF beadás menüpont alatt. Ez a hármas számú kis házi feladat, ennek megfelelően az ETS a beküldött megoldást khf3.pl, ill. khf3.erl néven tárolja el és hivatkozik rá. (A feltöltendő állomány neve tetszőleges lehet, az ETS átnevezi.)

Az osztályzat megállapításakor a határidőre beadott, minden tesztesetre helyesen működő feladatmegoldásért plusz 1-1 pont jár.