10 Commits
3 changed files with 70 additions and 51 deletions

No files matched your search

+28 -22
View File
@@ -1,25 +1,28 @@
# kostky # kostky
Textová (CLI) hra v kostky pro více hráčů – varianta klasického *Farkle* Textová (CLI) hra v kostky pro více hráčů – varianta klasického *Farkle*
(„tisícovky“). Běží celá v terminálu a je napsaná v čistém Pythonu bez („tisícovky“). Běží celá v terminálu, v Pythonu, s jedinou závislostí
externích závislostí. (`tabulate` pro závěrečnou výsledkovou tabulku).
## Požadavky ## Požadavky
- Python 3.7+ (hra se spoléhá na zachování pořadí klíčů ve slovníku) - Python 3.9+
- Žádné externí balíčky – používá se jen standardní knihovna - Závislost `tabulate` (doinstaluje se automaticky při instalaci)
(`random`, `os`, `re`, `csv`, `collections`, `typing`)
## Spuštění ## Instalace a spuštění
```bash ```bash
git clone https://gitea.spacilovi.eu/david/kostky.git git clone https://gitea.spacilovi.eu/david/kostky.git
cd kostky cd kostky
python main.py pip install .
kostky
``` ```
> Hru spouštěj z adresáře projektu – soubor `hodnoty.csv` (bodovací tabulka) Případně bez instalace (s nainstalovaným `tabulate`) přes `python -m kostky`,
> se načítá relativní cestou vůči aktuálnímu adresáři. nebo izolovaně jako CLI nástroj přes `pipx install .`.
> Pro vývoj: `pip install -e ".[dev]"` – editovatelná instalace včetně `mypy`
> a `ruff`.
## Jak se hraje ## Jak se hraje
@@ -31,42 +34,45 @@ python main.py
### Průběh tahu ### Průběh tahu
Na začátku tahu uvidíš cílové skóre, kdo je na tahu (a jeho celkové skóre) Na začátku tahu uvidíš, kdo je na tahu (s jeho skóre a cílem), a hod šesti
a hod šesti kostkami s očíslovanými pozicemi: kostkami s písmennými pozicemi:
``` ```
Vítězné skóre: 10000. Na tahu je Anna (0/10000).
Na tahu je Anna (0).
1, 5, 3, 2, 6, 4 1, 5, 3, 2, 6, 4
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
1 2 3 4 5 6 a b c d e f
``` ```
Pak zvolíš jednu z akcí: Pak zvolíš jednu z akcí:
| Vstup | Akce | | Vstup | Akce |
| --- | --- | | --- | --- |
| `pozice kostek` | Odložíš vybrané kostky k vyhodnocení (např. `1`, `34`, `123456`). Hodnoty na zvolených pozicích musí dohromady tvořit některou kombinaci z bodovací tabulky. | | `pozice kostek` | Odložíš vybrané kostky k vyhodnocení – písmeny (např. `a`, `cd`, `abcdef`). Hodnoty na zvolených pozicích musí dohromady tvořit některou kombinaci z bodovací tabulky. |
| `h` | Hodíš znovu zbývajícími kostkami. Povoleno až poté, co v tomto tahu odložíš aspoň jednu bodující kombinaci. | | `h` | Hodíš znovu zbývajícími kostkami. Povoleno až poté, co v tomto tahu odložíš aspoň jednu bodující kombinaci. |
| `k` | Ukončíš tah, připíšeš si nasbírané skóre a předáš tah dalšímu hráči. | | `k` | Ukončíš tah, připíšeš si nasbírané skóre a předáš tah dalšímu hráči. |
| `exit` | Předčasně ukončíš celou hru. |
Odkládat můžeš i víc kombinací po sobě – po každém vyhodnocení pokračuješ se Odkládat můžeš i víc kombinací po sobě – po každém vyhodnocení pokračuješ se
zbývajícími kostkami a body se v rámci tahu sčítají. zbývajícími kostkami a body se v rámci tahu sčítají.
### Smůla, hot dice a výhra ### Smůla, hot dice, vynulování a výhra
- **Smůla (bust):** když čerstvý hod neobsahuje žádnou bodující kombinaci, - **Smůla (bust):** když čerstvý hod neobsahuje žádnou bodující kombinaci,
o body z tohoto tahu přijdeš a tah přechází na dalšího hráče. o body z tohoto tahu přijdeš a tah přechází na dalšího hráče.
- **Hot dice:** když se ti podaří odložit všech šest kostek, dostaneš čerstvý - **Hot dice:** když se ti podaří odložit všech šest kostek, dostaneš čerstvý
hod šesti kostkami a pokračuješ ve stejném tahu. hod šesti kostkami a pokračuješ ve stejném tahu.
- **Výhra:** po dokončení každého kola se kontroluje, jestli někdo dosáhl - **Vynulování:** tři po sobě jdoucí nulové tahy vynulují tvé celkové skóre.
cílového skóre. Vyhrává osamocený lídr nad limitem; při shodě na první Počet aktuálních nul se vedle skóre ukazuje jako `x` / `xx`.
příčce se hraje dál. - **Výhra:** po dokončení každého kola vyhrává osamocený lídr nad cílovým
skóre; při shodě na první příčce se hraje dál. Na konci se vypíše výsledková
tabulka s pořadím všech hráčů.
## Bodování ## Bodování
Kompletní tabulka je v souboru [`hodnoty.csv`](hodnoty.csv). Kombinace se Kompletní tabulka je v souboru [`kostky/hodnoty.csv`](kostky/hodnoty.csv).
vyhodnocuje podle hodnot odložených kostek – na jejich pořadí nezáleží. Kombinace se vyhodnocuje podle hodnot odložených kostek – na jejich pořadí
nezáleží.
### Stejné kostky ### Stejné kostky
@@ -76,7 +82,7 @@ vyhodnocuje podle hodnot odložených kostek – na jejich pořadí nezáleží.
| **2** | – | – | 200 | 400 | 800 | 1600 | | **2** | – | – | 200 | 400 | 800 | 1600 |
| **3** | – | – | 300 | 600 | 1200 | 2400 | | **3** | – | – | 300 | 600 | 1200 | 2400 |
| **4** | – | – | 400 | 800 | 1600 | 3200 | | **4** | – | – | 400 | 800 | 1600 | 3200 |
| **5** | 50 | – | 500 | 1000 | 2000 | 4000 | | **5** | 50 | 100 | 500 | 1000 | 2000 | 4000 |
| **6** | – | – | 600 | 1200 | 2400 | 4800 | | **6** | – | – | 600 | 1200 | 2400 | 4800 |
(„–“ = daná kombinace samostatně neboduje.) („–“ = daná kombinace samostatně neboduje.)
-1
View File
@@ -24,7 +24,6 @@
444,400 444,400
2222,400 2222,400
333,300 333,300
11,200
222,200 222,200
1,100 1,100
5,50 5,50
1 111111 8000
24 444 400
25 2222 400
26 333 300
11 200
27 222 200
28 1 100
29 5 50
+42 -28
View File
@@ -1,10 +1,11 @@
from typing import Any
from random import randint
from os import system, name
import re
from importlib.resources import files
import csv import csv
import re
from collections import Counter from collections import Counter
from importlib.resources import files
from os import name, system
from random import randint
from typing import Any
from tabulate import tabulate from tabulate import tabulate
score: int = 0 score: int = 0
@@ -16,11 +17,10 @@ h_bool: bool = True
aggr: dict[str, int] = {} aggr: dict[str, int] = {}
final_score: int = 10000 final_score: int = 10000
with open("hodnoty.csv", "r") as csv_file: csv_text = files(__package__).joinpath("hodnoty.csv").read_text(encoding="utf-8")
csv_text = files(__package__).joinpath("hodnoty.csv").read_text(encoding="utf-8") csv_reader = csv.reader(csv_text.splitlines())
csv_reader = csv.reader(csv_text.splitlines())
for row in csv_reader: for row in csv_reader:
key = str(row[0]) key = str(row[0])
value = int(row[1]) value = int(row[1])
@@ -29,7 +29,7 @@ with open("hodnoty.csv", "r") as csv_file:
def throw(count: int) -> str: def throw(count: int) -> str:
count = int(count) count = int(count)
new_throw: list[str] = [] new_throw: list[str] = []
for dice in range(count): for _dice in range(count):
new_throw.append(str(randint(1, 6))) new_throw.append(str(randint(1, 6)))
new_throw_str: str = "".join(new_throw) new_throw_str: str = "".join(new_throw)
return new_throw_str return new_throw_str
@@ -41,18 +41,15 @@ def show_throw(throw: str) -> str:
pretty_list: str = ", ".join(throw_temp) pretty_list: str = ", ".join(throw_temp)
pretty_list += "\n" pretty_list += "\n"
for i in range(1, len(throw_temp) + 1): for _i in range(1, len(throw_temp) + 1):
pretty_list += "^ " pretty_list += "^ "
pretty_list += "\n" pretty_list += "\n"
for i in range(1, len(throw_temp) + 1): for i in range(len(throw_temp)):
pretty_list += f"{i} " pretty_list += f"{chr(97+i)} "
return pretty_list return pretty_list
def clear() -> None: def clear() -> None:
if name == 'nt': _ = system('cls') if name == 'nt' else system('clear')
_ = system('cls')
else:
_ = system('clear')
def evaluate(inp: Any, count: int, throw: str) -> tuple[Any, ...]: def evaluate(inp: Any, count: int, throw: str) -> tuple[Any, ...]:
@@ -78,19 +75,34 @@ def evaluate(inp: Any, count: int, throw: str) -> tuple[Any, ...]:
pointer = nxt_key pointer = nxt_key
inp = str(inp) inp = str(inp)
if re.search(r"^\d+$", inp): inp_temp: str = ""
if re.search(r"^[a-f]+$", inp):
if len(inp) > count: if len(inp) > count:
data: tuple[Any, ...] = ("msg", "ER01", "Tolika kostkami nemůžete hodit. Zkuste to znovu: ", count, throw) data: tuple[Any, ...] = (
"msg",
"ER01",
"Tolika kostkami nemůžete hodit. Zkuste to znovu: ",
count,
throw
)
else: else:
for x in inp: for x in inp:
x = int(x) x = ord(x)-96
if x > count: if x > count:
if count == 1: ran = "1" if count == 1 else f"1–{count}"
ran = "1" data = (
else: "msg",
ran = f"1–{count}" "ER02",
data = ("msg", "ER02", f"Zvolte prosím kostky v platném rozsahu ({ran}): ", count, throw) f"Zvolte prosím kostky v platném rozsahu ({ran}): ",
count,
throw
)
return data return data
else:
inp_temp += str(x)
inp = inp_temp
old_throw: list[str] = [] old_throw: list[str] = []
pick: list[str] = [] pick: list[str] = []
for y in range(count): for y in range(count):
@@ -205,8 +217,9 @@ def add_players() -> None:
else: else:
break break
def to_sorted_tuple(d: dict[str, int], s: bool = True) -> tuple[list[tuple[int, str, int]], dict[str, int]]: def to_sorted_tuple(d: dict[str, int], s: bool = True) -> tuple[list[tuple[int, str, int]],
L: list[tuple[str, int]] = [] dict[str, int]]:
L: list[tuple[int, str, int]] = []
if s: if s:
d = dict(sorted(d.items(), key=lambda x: x[1], reverse=True)) d = dict(sorted(d.items(), key=lambda x: x[1], reverse=True))
@@ -278,7 +291,8 @@ def game(data: tuple) -> None:
if count == 0: if count == 0:
count = 6 count = 6
msg: str = ("Jakou akci chcete provést?\n" msg: str = ("Jakou akci chcete provést?\n"
" - Zadejte kombinaci kostek k ponechání (dojde k jejich vyhodnocení): [pozice kostek] (např. 1 nebo 34 nebo 123456).\n" " - Zadejte kombinaci kostek k ponechání (dojde k jejich vyhodnocení): "
"[pozice kostek] (např. a nebo cd nebo abcdef).\n"
" - Hodit znovu: [h].\n" " - Hodit znovu: [h].\n"
f" - Ukončit hod a ponechat si skóre z tohoto hodu ({score}): [k].\n" f" - Ukončit hod a ponechat si skóre z tohoto hodu ({score}): [k].\n"
" - Ukončit hru: [exit].\n" " - Ukončit hru: [exit].\n"