Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
136 changes: 136 additions & 0 deletions snippets/1001_MastermindTdd/game.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import random
from logic import tipp_kiszamolasa

# Elérhető színek
SZINEK = ["szurke", "piros", "narancs", "sarga", "zold", "pink", "lila", "kek", "fekete", "feher"]
MAX_KOROK = 12

def welcome():
"""Üdvözlő üzenet és játékszabályok"""
print("=" * 60)
print(" " * 20 + "MASTERMIND JÁTÉK")
print("=" * 60)
print("\nÜdvözöllek a Mastermind játékban!")
print(f"\nElérhető színek ({len(SZINEK)} db):")
for i, szin in enumerate(SZINEK, 1):
print(f" {i}. {szin}", end=" " if i % 3 != 0 else "\n")
print("\n\nCélod: Találd ki a 4 színből álló titkos kombinációt!")
print(f"Neked {MAX_KOROK} körödön van tippelni.\n")
print("Válaszban kapod:")
print(" - FEKETE tüskék: hány szín van jó helyen")
print(" - FEHÉR tüskék: hány szín van rossz helyen\n")
print("Adj meg 4 színt szóközzel elválasztva!")
print("Például: piros kek zold sarga\n")
print("=" * 60 + "\n")

def generalt_felallas():
"""Véletlenszerű felállás generálása"""
return [random.choice(SZINEK) for _ in range(4)]

def beker_tippet(kor):
"""Tipp bekérése a felhasználótól"""
while True:
try:
print(f"[{kor}. kör] Add meg a tipped: ", end="")
tipp_str = input().strip().lower()

if not tipp_str:
print("❌ Üres tipp! Próbáld újra.")
continue

tipp = tipp_str.split()

if len(tipp) != 4:
print(f"❌ Pontosan 4 színt kell megadnod! Te {len(tipp)} színt adtál meg.")
continue

# Ellenőrizzük, hogy minden szín érvényes-e
hibas_szinek = [szin for szin in tipp if szin not in SZINEK]
if hibas_szinek:
print(f"❌ Érvénytelen szín(ek): {', '.join(hibas_szinek)}")
print(f" Elérhető színek: {', '.join(SZINEK)}")
continue

return tipp
except KeyboardInterrupt:
print("\n\n👋 Játék megszakítva. Viszlát!")
exit(0)
except Exception as e:
print(f"❌ Hiba: {e}")
continue

def eredmeny_kiiras(fekete, feher):
"""Eredmény szép megjelenítése"""
print(f" Eredmény: ", end="")

# Fekete tüskék
if fekete > 0:
print(f"🔴 {fekete} fekete", end="")

# Fehér tüskék
if feher > 0:
if fekete > 0:
print(", ", end="")
print(f"⚪ {feher} fehér", end="")

# Ha egyik sincs
if fekete == 0 and feher == 0:
print("❌ Nincs találat", end="")

print()

def jatek():
"""Fő játék logika"""
welcome()

# Titkos felállás generálása
felallas = generalt_felallas()
# print(f"[DEBUG] Titkos kód: {' '.join(felallas)}") # Debug célra

# Játék ciklus
for kor in range(1, MAX_KOROK + 1):
tipp = beker_tippet(kor)

try:
fekete, feher = tipp_kiszamolasa(felallas, tipp, SZINEK)
eredmeny_kiiras(fekete, feher)

# Győzelem ellenőrzése
if fekete == 4:
print("\n" + "=" * 60)
print(f"🎉 GRATULÁLOK! Kitaláltad {kor} körből!")
print(f"A titkos kód: {' '.join(felallas).upper()}")
print("=" * 60)
return True

print() # Üres sor a következő kör előtt

except ValueError as e:
print(f"❌ Hiba: {e}")
continue

# Ha elfogytak a körök
print("\n" + "=" * 60)
print("😞 Sajnos elfogytak a köreid!")
print(f"A titkos kód: {' '.join(felallas).upper()}")
print("=" * 60)
return False

def main():
"""Főprogram - újrajátszás kezelése"""
while True:
jatek()

print("\nSzeretnél újra játszani? (i/n): ", end="")
try:
valasz = input().strip().lower()
if valasz not in ['i', 'igen', 'y', 'yes']:
print("\n👋 Köszönöm a játékot! Viszlát!")
break
print("\n" + "=" * 60 + "\n")
except KeyboardInterrupt:
print("\n\n👋 Viszlát!")
break

if __name__ == "__main__":
main()
Binary file added snippets/1001_MastermindTdd/jatekfelulet.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions snippets/1001_MastermindTdd/logic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
def tipp_kiszamolasa(felallas, tipp, szinek):
"""
Mastermind játék logikája - a tipp kiértékelése.

Args:
felallas: A titkos szín lista (4 szín)
tipp: A tippelt szín lista (4 szín)
szinek: Az érvényes színek listája

Returns:
Tuple: (helyes_pozició_szám, helyes_szín_rossz_pozició_szám)

Raises:
ValueError: Ha érvénytelen szín vagy rossz hosszú a tipp
"""
from collections import Counter

# Validáció
if len(tipp) != 4:
raise ValueError("A tippnek pontosan 4 szín kell, hogy tartalmazzon")

for szin in tipp:
if szin not in szinek:
raise ValueError(f"Érvénytelen szín: {szin}")

# Szín előfordulások számolása
tipp_szamok = Counter(tipp)
felallas_szamok = Counter(felallas)

# 1. lépés: Pontos pozíció egyezések keresése (fekete tüskék)
helyes_pozicio = 0
felallas_maradek = []
tipp_maradek = []

for i in range(4):
# Pontos egyezést csak akkor számítunk, ha:
# - a pozíció egyezik ÉS
# - a szín felállásban pontosan 1x szerepel VAGY tippben és felállásban ugyanannyiszor
if tipp[i] == felallas[i]:
if felallas_szamok[tipp[i]] == 1 or tipp_szamok[tipp[i]] == felallas_szamok[tipp[i]]:
helyes_pozicio += 1
else:
# Ha nem számít fekete tüskének, maradékhoz adjuk
felallas_maradek.append(felallas[i])
tipp_maradek.append(tipp[i])
else:
# Nincs pozíció egyezés, maradékhoz adjuk
felallas_maradek.append(felallas[i])
tipp_maradek.append(tipp[i])

# 2. lépés: Rossz pozícióban lévő szín egyezések keresése (fehér tüskék)
helyes_szin_rossz_pozicio = 0

for szin in tipp_maradek:
if szin in felallas_maradek:
helyes_szin_rossz_pozicio += 1
felallas_maradek.remove(szin)

return (helyes_pozicio, helyes_szin_rossz_pozicio)
43 changes: 43 additions & 0 deletions snippets/1001_MastermindTdd/mastermind_esettanulmany.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
layout: post
title: Mastermind fejlesztés TDD módszerrel és AI segítségével
tags: ai python tdd mastermind logic
author: Szakszon Ádám
---

# Mastermind Esettanulmány

## Bevezetés
Ebben a projektben egy klasszikus Mastermind játék motorját készítettem el. A célom az volt, hogy megtanuljam a **TDD (Test-Driven Development)** folyamatát AI (GitHub Copilot) támogatással.

## Fejlesztési módszertan
A fejlesztés során nem a kódot írtam meg először, hanem a teszteseteket a `pytest` keretrendszerben.

### Tesztek típusai:
* **Hibaágak:** Érvénytelen színek és rossz tipp-hossz kezelése.
* **Logikai ágak:** Fekete és fehér tüskék számolása, különös tekintettel a duplikált színekre.


## Algoritmus leírása
A `tipp_kiszamolasa` függvény két lépésben dolgozik:
1. Megkeresi a pontos egyezéseket (fekete tüskék).
2. A maradék színekből kiszámolja a benne lévő, de rossz helyen lévő színeket (fehér tüskék).



## Érdekes Promptok

A fejlesztés során az AI-t két lépcsőben irányítottam. Először megadtam neki a teljes tesztkészletet, hogy az alapján generálja le a logikát:

> "Szia! Kérlek, írd meg a `logic.py` tartalmát a `test_logic.py`-ban található tesztjeim alapján. A feladat a `tipp_kiszamolasa(felallas, tipp, szinek)` függvény megírása. Fontos, hogy a kód minden tesztesetnek megfeleljen."

Később, amikor az AI túl bonyolult algoritmust (felesleges feltételeket) próbált bevezetni, szükség volt egy pontosító, visszaterelő utasításra:

> "Térjünk vissza az alapokhoz: először egy ciklussal számoljuk össze az összes pontos egyezést, majd a maradékból határozzuk meg a rossz helyen lévő színeket. Ne bonyolítsd túl a logikát!"

## Eredmények
A tesztek lefuttatása után az alábbi eredményt kaptam:
![Passed Tests](teszt.png)

Aztán kértem egy konzolon tesztelhető felületett is az AI-tól:
![Konzol](jatekfelulet.png)
75 changes: 75 additions & 0 deletions snippets/1001_MastermindTdd/test_logic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import pytest
from logic import tipp_kiszamolasa

szinek = ["szurke", "piros", "narancs", "sarga", "zold", "pink", "lila", "kek", "fekete", "feher" ]

def test_ervenytelen_szin():
with pytest.raises(ValueError):
tipp = ["sotetkek", "kek", "kek", "kek"]
felalas = ["piros", "kek", "zold", "sarga"]
tipp_kiszamolasa(felalas, tipp, szinek)

def test_tulsok_szin():
with pytest.raises(ValueError):
tipp = ["zold", "kek", "kek", "kek", "piros"]
felalas = ["piros", "kek", "zold", "sarga"]
tipp_kiszamolasa(felalas, tipp, szinek)


def test_tulkeves_szin():
with pytest.raises(ValueError):
tipp = ["zold", "kek", "kek",]
felalas = ["piros", "kek", "zold", "sarga"]
tipp_kiszamolasa(felalas, tipp, szinek)



def test_nincs_talalat():
tipp = ["szurke", "piros", "narancs", "sarga"]
felalas = ["lila", "kek", "fekete", "feher"]
assert tipp_kiszamolasa(felalas, tipp, szinek) == (0,0)

def test_johely():
tipp = ["zold", "kek", "szurke", "piros"]
felalas = ["lila", "kek", "fekete", "feher"]
assert tipp_kiszamolasa(felalas, tipp, szinek) == (1,0)

def test_benne():
tipp = ["zold", "szurke", "piros", "kek"]
felalas = ["lila", "kek", "fekete", "feher"]
assert tipp_kiszamolasa(felalas, tipp, szinek) == (0,1)

def test_benne_johely():
tipp = ["zold", "szurke", "piros", "kek"]
felalas = ["szurke", "lila", "piros", "kek"]
assert tipp_kiszamolasa(felalas, tipp, szinek) == (2,1)

def test_duplikaltszin_johely():
tipp = ["kek", "kek", "szurke", "piros"]
felalas = ["lila", "kek", "fekete", "feher"]
assert tipp_kiszamolasa(felalas, tipp, szinek) == (1,0)

def test_duplikaltszin_benne():
tipp = ["kek", "szurke", "piros", "kek"]
felalas = ["lila", "kek", "fekete", "feher"]
assert tipp_kiszamolasa(felalas, tipp, szinek) == (0,1)

def test_duplikaltszin_benne_tobb():
tipp = ["kek", "szurke", "kek", "kek"]
felalas = ["lila", "kek", "kek", "feher"]
assert tipp_kiszamolasa(felalas, tipp, szinek) == (0,2)

def test_duplikaltszin_johely_tobb():
tipp = ["kek", "kek", "szurke", "piros"]
felalas = ["kek", "kek", "fekete", "piros"]
assert tipp_kiszamolasa(felalas, tipp, szinek) == (3,0)

def test_duplikaltszin_vegyes():
tipp = ["kek", "kek", "szurke", "piros"]
felalas = ["kek", "kek", "piros", "piros"]
assert tipp_kiszamolasa(felalas, tipp, szinek) == (2,1)

def test_siker():
tipp = ["zold", "szurke", "piros", "kek"]
felalas = ["zold", "szurke", "piros", "kek"]
assert tipp_kiszamolasa(felalas, tipp, szinek) == (4,0)
Binary file added snippets/1001_MastermindTdd/teszt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.