From d420664fdec85efde22b3039a1a02392b86a4174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Sat, 11 Jul 2026 16:16:39 +0200 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20upravena=20funkce=20eval=5Fscore()?= =?UTF-8?q?=20Do=C5=A1lo=20k=20=C3=BAprav=C4=9B=20funkce=20eval=5Fscore()?= =?UTF-8?q?=20tak,=20aby=20p=C5=99ij=C3=ADmala=20input=20s=20v=C3=ADce=20k?= =?UTF-8?q?ombinacemi=20najednou.=20V=20p=C5=99=C3=ADpad=C4=9B=20vstupu,?= =?UTF-8?q?=20kter=C3=BD=20krom=C4=9B=20platn=C3=BDch=20kombinac=C3=AD=20o?= =?UTF-8?q?bsahuje=20i=20hodnoty=20nav=C3=ADc,=20vr=C3=A1t=C3=AD=20False?= =?UTF-8?q?=20a=20u=C5=BEivatel=20m=C3=A1=20mo=C5=BEnost=20vybrat=20kostky?= =?UTF-8?q?=20k=20vyhodnocen=C3=AD=20znovu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kostky/kostky.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/kostky/kostky.py b/kostky/kostky.py index 3dcc268..e8d608d 100644 --- a/kostky/kostky.py +++ b/kostky/kostky.py @@ -56,12 +56,30 @@ def evaluate(inp: Any, count: int, throw: str) -> tuple[Any, ...]: global h_bool def eval_score(pick: str) -> bool: - if(pick in hodnoty): - global score - score += hodnoty[pick] - return True - else: - return False + global score + score_temp = 0 + pick_ok = False + pick_counter = Counter(pick) + while pick_counter: + bool_temp = False + for k in hodnoty: + k_counter = Counter(k) + if k_counter <= pick_counter: + pick_counter = pick_counter - k_counter + score_temp += hodnoty[k] + pick_ok = True + bool_temp = True + + if not bool_temp: + break + + print(pick_counter) + if pick_counter: + pick_ok = False + else: + score += score_temp + + return pick_ok def next_player() -> None: global pointer -- 2.47.3 From 26f53761a7c6db70bdd2585f1afb3f40842f4ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Sat, 11 Jul 2026 16:30:33 +0200 Subject: [PATCH 2/9] =?UTF-8?q?enhancement:=20=C5=99azen=C3=AD=20hodnot=20?= =?UTF-8?q?po=20na=C4=8Dten=C3=AD=20hodnot=20kombinac=C3=AD=20z=20csv=20do?= =?UTF-8?q?jde=20pro=20jistotu=20je=C5=A1t=C4=9B=20k=20se=C5=99azen=C3=AD?= =?UTF-8?q?=20podle=20hodnoty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kostky/kostky.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kostky/kostky.py b/kostky/kostky.py index e8d608d..ca31bcf 100644 --- a/kostky/kostky.py +++ b/kostky/kostky.py @@ -26,6 +26,8 @@ for row in csv_reader: hodnoty[key] = value +hodnoty = dict(sorted(hodnoty.items(), key=lambda x: x[1], reverse=True)) + def throw(count: int) -> str: count = int(count) new_throw: list[str] = [] -- 2.47.3 From caa743fcc97db0b3f0e1c853e523d10863e768f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Sat, 11 Jul 2026 22:46:25 +0200 Subject: [PATCH 3/9] update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 067e3b3..ecff981 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ __pycache__/ *.pyc dist/ build/ -*.egg-info/ \ No newline at end of file +*.egg-info/ +test.py \ No newline at end of file -- 2.47.3 From e9cf87519284ff6a798be06cceeb0ceaba2ca4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Sun, 12 Jul 2026 20:23:26 +0200 Subject: [PATCH 4/9] =?UTF-8?q?refactor:=20vyta=C5=BEen=C3=AD=20funkc?= =?UTF-8?q?=C3=AD=20z=20evaluate=20Funkce=20eval=5Fscore=20vyta=C5=BEena?= =?UTF-8?q?=20z=20evaluate;=20translate=5Fletters=5Fto=5Fnumbers,=20pick?= =?UTF-8?q?=5Fthrow=5Fproc=20a=20eval=5Fwrapper=20nov=C4=9B=20vytvo=C5=99e?= =?UTF-8?q?ny=20z=20fragment=C5=AF=20evaluate.=20Oproti=20d=C5=99=C3=ADv?= =?UTF-8?q?=C4=9Bj=C5=A1=C3=ADmu=20pokusu=20odstran=C4=9Bny=20i=20p=C5=99e?= =?UTF-8?q?sunut=C3=A9=20(redundantn=C3=AD)=20=C5=99=C3=A1dky.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kostky/kostky.py | 178 +++++++++++++++++++++++++++-------------------- 1 file changed, 102 insertions(+), 76 deletions(-) diff --git a/kostky/kostky.py b/kostky/kostky.py index ca31bcf..13cd539 100644 --- a/kostky/kostky.py +++ b/kostky/kostky.py @@ -53,36 +53,111 @@ def show_throw(throw: str) -> str: def clear() -> None: _ = system('cls') if name == 'nt' else system('clear') +def translate_letters_to_numbers(inp_hod: str, count: int) -> tuple[bool, str]: + inp_temp: str = "" + for x in inp_hod: + x_int: int = ord(x)-96 + if x_int > count: + ran = "1" if count == 1 else f"1–{count}" + return False, f"Zvolte prosím kostky v platném rozsahu ({ran}): " + else: + inp_temp += str(x_int) + + return True, inp_temp + +def pick_throw_proc(count: int, inp_hod: str, throw: str) -> tuple[str, str]: + old_throw: list[str] = [] + pick: list[str] = [] + for y in range(count): + if str(y+1) not in inp_hod: + old_throw.append(throw[y]) + if str(y+1) in inp_hod: + pick.append(throw[y]) + + old_throw_str: str = "".join(old_throw) + pick.sort() + pick_str: str = "".join(pick) + + return old_throw_str, pick_str + +def eval_score(pick: str) -> int: + score = 0 + pick_counter = Counter(pick) + while pick_counter: + bool_temp = False + for k in hodnoty: + k_counter = Counter(k) + if k_counter <= pick_counter: + pick_counter = pick_counter - k_counter + score += hodnoty[k] + bool_temp = True + + if not bool_temp: + break + + if pick_counter: + score = 0 + + return score + +def eval_wrapper(count: int, throw: str, inp_hod: str) -> tuple[bool, int, int, str]: + if not inp_hod: + data = ( + True, + 0, + count, + "", + ) + elif re.search(r"^[a-f]+$", inp_hod): + if len(inp_hod) > count: + data = ( + False, + 0, + count, + "Tolika kostkami nemůžete hodit. Zkuste to znovu: ", + ) + else: + tltn = translate_letters_to_numbers(inp_hod, count) + if tltn[0]: + inp_hod = tltn[1] + + old_throw_str, pick_str = pick_throw_proc(count, inp_hod, throw) + + new_count: int = len(old_throw_str) + + score = eval_score(pick_str) + + if not score: + new_count = count + old_throw_str = throw + + data = ( + True, + score, + new_count, + "", + ) + else: + data = ( + False, + 0, + count, + tltn[1] + ) + else: + data = ( + False, + 0, + count, + "Zadejte prosím platnou hodnotu: ", + ) + + return data + def evaluate(inp: Any, count: int, throw: str) -> tuple[Any, ...]: global h_bool - def eval_score(pick: str) -> bool: - global score - score_temp = 0 - pick_ok = False - pick_counter = Counter(pick) - while pick_counter: - bool_temp = False - for k in hodnoty: - k_counter = Counter(k) - if k_counter <= pick_counter: - pick_counter = pick_counter - k_counter - score_temp += hodnoty[k] - pick_ok = True - bool_temp = True - - if not bool_temp: - break - - print(pick_counter) - if pick_counter: - pick_ok = False - else: - score += score_temp - - return pick_ok - def next_player() -> None: global pointer @@ -95,57 +170,8 @@ def evaluate(inp: Any, count: int, throw: str) -> tuple[Any, ...]: pointer = nxt_key inp = str(inp) - inp_temp: str = "" - if re.search(r"^[a-f]+$", inp): - if len(inp) > count: - data: tuple[Any, ...] = ( - "msg", - "ER01", - "Tolika kostkami nemůžete hodit. Zkuste to znovu: ", - count, - throw - ) - else: - for x in inp: - x = ord(x)-96 - if x > count: - ran = "1" if count == 1 else f"1–{count}" - data = ( - "msg", - "ER02", - f"Zvolte prosím kostky v platném rozsahu ({ran}): ", - count, - throw - ) - return data - else: - inp_temp += str(x) - inp = inp_temp - - old_throw: list[str] = [] - pick: list[str] = [] - for y in range(count): - if str(y+1) not in inp: - old_throw.append(throw[y]) - if str(y+1) in inp: - pick.append(throw[y]) - - old_throw_str: str = "".join(old_throw) - pick.sort() - pick_str: str = "".join(pick) - - new_count: int = len(old_throw_str) - - if not eval_score(pick_str): - new_count = count - old_throw_str = throw - else: - h_bool = False - - data = ("count", new_count, old_throw_str) - - elif inp == "h": + if inp == "h": if h_bool: clear() input("Nemůžete házet znovu, dokud nevyhodnotíte některé kostky.") -- 2.47.3 From b070e22f3379314c34519e19787b623224fd6ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Sun, 12 Jul 2026 20:45:31 +0200 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20automatick=C3=A9=20vyhodnocen=C3=AD?= =?UTF-8?q?=20a=20nov=C3=A1=20dynamika=20kola?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Jedno vyhodnocení kostek = jeden hod; poté nový hod (h), ukončení tahu (k), nebo exit (x). Přepis game() a evaluate() na použití eval_wrapper, odstranění globálů score a h_bool. Zahrnuje správné chování smůly (ztráta bodů z tahu), potvrzení výběru a opravu zobrazení strikes. --- kostky/kostky.py | 102 ++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 55 deletions(-) diff --git a/kostky/kostky.py b/kostky/kostky.py index 13cd539..821b21a 100644 --- a/kostky/kostky.py +++ b/kostky/kostky.py @@ -8,12 +8,10 @@ from typing import Any from tabulate import tabulate -score: int = 0 hodnoty: dict[str, int] = {} players: dict[str, list[int]] = {} pointer: str = "" first: str = "" -h_bool: bool = True aggr: dict[str, int] = {} final_score: int = 10000 @@ -154,9 +152,7 @@ def eval_wrapper(count: int, throw: str, inp_hod: str) -> tuple[bool, int, int, return data -def evaluate(inp: Any, count: int, throw: str) -> tuple[Any, ...]: - - global h_bool +def evaluate(inp_akce: str, count: int, score: int) -> tuple[Any, ...]: def next_player() -> None: global pointer @@ -169,20 +165,10 @@ def evaluate(inp: Any, count: int, throw: str) -> tuple[Any, ...]: pointer = nxt_key - inp = str(inp) - - if inp == "h": - if h_bool: - clear() - input("Nemůžete házet znovu, dokud nevyhodnotíte některé kostky.") - data = ("count", count, throw) - else: - h_bool = True - data = ("count", count, "") - - elif inp == "k": - global score + if inp_akce == "h": + data = ("count", count, score) + elif inp_akce == "k" or not inp_akce: if score == 0: last_two = players[pointer][-2:] if len(last_two) > 1: @@ -194,21 +180,16 @@ def evaluate(inp: Any, count: int, throw: str) -> tuple[Any, ...]: players[pointer].append(score) aggr[pointer] = sum(players[pointer]) - score = 0 - h_bool = True next_player() - data = ("count", 6, "") + data = ("count", 6, 0) if pointer == first: winner: str = check_win() if winner: data = ("win", winner, aggr[winner]) - elif inp == "exit": + elif inp_akce == "x": data = ("exit",) - else: - data = ("msg", "ER03", "Zadejte prosím platnou hodnotu:", count, throw) - return data def check_value(throw: str) -> bool: @@ -310,54 +291,65 @@ def game(data: tuple) -> None: while True: if data[0] == "count": count: int = data[1] - th: str = data[2] - if(th == ""): - th = throw(count) + score: int = data[2] + if not count: + count = 6 + th = throw(count) clear() - # print(f"Vítězné skóre: {final_score}.") strikes: str = "" if len(players[pointer]) > 0: if players[pointer][-1:][0] == 0: strikes = "x" - if players[pointer][-2:][0] == 0: + if players[pointer][-2:][0] == 0 and len(players[pointer]) > 1: strikes += "x" else: strikes = "" print(f"Na tahu je {pointer} ({aggr[pointer]}{strikes}/{final_score}).") print(show_throw(th)) - if not check_value(th) and data[2] == "" and count != 0: - global score + if not check_value(th) and count != 0: score = 0 input("Oh no... anyway.") - data = evaluate("k", count, th) + data = evaluate("k", count, score) else: if count == 0: count = 6 - msg: str = ("Jakou akci chcete provést?\n" - " - Zadejte kombinaci kostek k ponechání (dojde k jejich vyhodnocení): " - "[pozice kostek] (např. a nebo cd nebo abcdef).\n" - " - Hodit znovu: [h].\n" - f" - Ukončit hod a ponechat si skóre z tohoto hodu ({score}): [k].\n" - " - Ukončit hru: [exit].\n" - ) - inp: str = input(msg) - data = evaluate(inp, count, th) + inp_hod: str = input("Vyberte kostky k vyhodnocení: ") + while True: + data = eval_wrapper(count, th, inp_hod) + if not data[0]: + inp_hod = input(data[3]) + continue + score_temp = data[1] + print("Hodnota hodu:", score_temp) + add = ("Hodnota je nulová. Ukončit kolo a přičíst " + f"{score} bodů? ") if not score_temp else "" + while True: + inp = input(f"Potvrdit výběr? {add}[a]no/[n]e: ") + if inp in ["a", "y", "n"]: + break + if inp in ["a", "y"]: + count = data[2] + score += score_temp + break + inp_hod = input("Vyberte kostky k vyhodnocení: ") + + while True: + if not score_temp: + inp_akce: str = "k" + else: + inp_akce = input( + f"[h]odit znovu\nu[k]ončit tah a přičíst {score} bodů\ne[x]it?\n" + ) + if inp_akce in ["h", "k", "x"]: + break + else: + print("Zadejte prosím platnou hodnotu [h/k/x]. ") + + data = evaluate(inp_akce, count, score) - elif data[0] == "msg": - if data[1] == "ER01" or data[1] == "ER02" or data[1] == "ER03": - msg = data[2] - count = data[3] - th = data[4] - inp = input(msg) - data = evaluate(inp, count, th) - else: - msg = data[1] - print(msg) - break - elif data[0] == "win": winner: str = data[1] score = data[2] @@ -375,7 +367,7 @@ def main() -> None: clear() print("Vítejte ve hře v kostky!") add_players() - data = ("count", 6, "") + data = ("count", 6, 0) game(data) if __name__ == "__main__": -- 2.47.3 From b3650b72437669b297d1827b224b4f546f8b426c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Sun, 12 Jul 2026 20:45:31 +0200 Subject: [PATCH 6/9] =?UTF-8?q?refactor:=20clear()=20p=C5=99es=20subproces?= =?UTF-8?q?s=20m=C3=ADsto=20os.system?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kostky/kostky.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kostky/kostky.py b/kostky/kostky.py index 821b21a..e6b471a 100644 --- a/kostky/kostky.py +++ b/kostky/kostky.py @@ -1,8 +1,9 @@ import csv import re +import subprocess from collections import Counter from importlib.resources import files -from os import name, system +from os import name from random import randint from typing import Any @@ -49,7 +50,7 @@ def show_throw(throw: str) -> str: return pretty_list def clear() -> None: - _ = system('cls') if name == 'nt' else system('clear') + _ = subprocess.call('cls', shell=True) if name == 'nt' else subprocess.call('clear', shell=True) def translate_letters_to_numbers(inp_hod: str, count: int) -> tuple[bool, str]: inp_temp: str = "" -- 2.47.3 From 21efddc1a01595e590d3456b708f017da369155c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Sun, 12 Jul 2026 20:45:31 +0200 Subject: [PATCH 7/9] =?UTF-8?q?style:=20drobn=C3=BD=20=C3=BAklid=20pro=20r?= =?UTF-8?q?uff=20a=20mypy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit key bez zbytečného str(), odstranění count = int(count) v throw(). --- kostky/kostky.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kostky/kostky.py b/kostky/kostky.py index e6b471a..8518b95 100644 --- a/kostky/kostky.py +++ b/kostky/kostky.py @@ -20,7 +20,7 @@ csv_text = files(__package__).joinpath("hodnoty.csv").read_text(encoding="utf-8" csv_reader = csv.reader(csv_text.splitlines()) for row in csv_reader: - key = str(row[0]) + key = row[0] value = int(row[1]) hodnoty[key] = value @@ -28,7 +28,6 @@ for row in csv_reader: hodnoty = dict(sorted(hodnoty.items(), key=lambda x: x[1], reverse=True)) def throw(count: int) -> str: - count = int(count) new_throw: list[str] = [] for _dice in range(count): new_throw.append(str(randint(1, 6))) -- 2.47.3 From 222df46c47833ed35d91d1672b49bf3415640c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Sun, 12 Jul 2026 20:45:53 +0200 Subject: [PATCH 8/9] =?UTF-8?q?docs:=20p=C5=99idat=20pravidlo=20o=20nep?= =?UTF-8?q?=C5=99edkl=C3=A1d=C3=A1n=C3=AD=20k=C3=B3du=20do=20CLAUDE.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index fb991a8..1089918 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,6 +2,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +## Working style + +- During code review and code discussions, do NOT present ready-made code + proposals or concrete snippets. Limit yourself to advice and recommendations + (what is wrong, why, and the direction of the fix). Only write concrete code + when the user explicitly asks for it. + ## Project `kostky` is a Czech-language terminal CLI game — a Farkle/"tisícovky" dice game variant for multiple players. Single runtime dependency: `tabulate` (for the final results table). -- 2.47.3 From c2bd4fd6ac05e152eae6c05c865180a26fd60e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sp=C3=A1=C4=8Dil?= Date: Sun, 12 Jul 2026 20:45:53 +0200 Subject: [PATCH 9/9] chore: nastavit mypy python_version na 3.10 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ce6429b..18543a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ source = "vcs" packages = ["kostky"] [tool.mypy] -python_version = "3.9" +python_version = "3.10" strict = true files = ["kostky"] -- 2.47.3