250 lines
12 KiB
Markdown
250 lines
12 KiB
Markdown
[](https://github.com/markedjs/)
|
||
|
||
# 🎴 Чешский дурак
|
||
_(Вернее одна из его многочисленых вариаций в которую мы с друзьями играем большую часть жизни)_
|
||
#
|
||
Многопользовательская карточная игра на WebSocket с уникальными правилами и специальными картами.
|
||
|
||
## Правила игры
|
||
|
||
### Колода
|
||
- Стандартная колода из 52 карт (без джокеров)
|
||
- 4 классические масти: ♥️ Черви, ♦️ Бубны, ♣️ Трефы, ♠️ Пики
|
||
- 13 рангов: 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A
|
||
- Когда колода заканчивается, все карты из сброса (кроме верхней) перемешиваются и становятся новой колодой
|
||
|
||
### Начало игры
|
||
- Каждому игроку раздаётся по 5 карт
|
||
- Одна карта кладётся рубашкой вниз на поле (первый ход дилера)
|
||
- Колода кладётся рядом
|
||
- Ход делает игрок после дилера
|
||
- **Первая карта имеет эффект:**
|
||
- Если **6** или **7**: Следующий игрок берёт карты и пропускает ход
|
||
- Если **8**: Следующий игрок должен брать карты или положить двойку
|
||
- Если **A**: Следующий игрок пропускает ход
|
||
- Если **Q**: Дилер автоматически выбирает масть (случайную)
|
||
|
||
### Ходы
|
||
- Карты кладутся по принципу масть на масть или номинал на номинал
|
||
- **Взятие карт:**
|
||
- Можно взять карту из колоды даже если есть чем ходить (только 1 раз за ход)
|
||
- После взятия карты появляется кнопка "Пропустить ход"
|
||
- Вы можете:
|
||
- Сыграть любую подходящую карту из руки (включая только что взятую)
|
||
- Или нажать "Пропустить ход" чтобы передать ход следующему игроку
|
||
- Верхняя карта на поле остаётся лежать пока её не покроют следующей картой
|
||
|
||
### Специальные карты
|
||
|
||
**Шестёрка (6)**: Следующий игрок берёт 1 карту и пропускает ход
|
||
|
||
**Семёрка (7)**: Следующий игрок берёт 2 карты и пропускает ход
|
||
|
||
**Восьмёрка (8)**: Следующий игрок должен:
|
||
- **Из руки**: Может положить только любую двойку (2) любой масти
|
||
- **Из колоды**: Берёт карты пока не попадётся:
|
||
- Любая двойка (2)
|
||
- Любая дама (Q)
|
||
- Карта той же масти что и восьмёрка
|
||
|
||
**Туз (A)**: Следующий игрок пропускает ход
|
||
|
||
**Дама (Q)**:
|
||
- Можно положить на любую карту
|
||
- Игрок выбирает следующую масть
|
||
- Выбранная масть отображается над картой на поле в золотом бейдже
|
||
- Индикатор масти остаётся пока её не покроют другой картой
|
||
- Следующий игрок должен положить карту выбранной масти (или даму)
|
||
- **ВАЖНО**: Если дама - последняя карта, вычитается 20 очков (пиковая дама - 40 очков)
|
||
|
||
### Победа и подсчёт очков
|
||
|
||
Побеждает тот, кто первым сбросил все карты.
|
||
|
||
Остальным начисляются очки за оставшиеся карты:
|
||
- Цифры (2-10) = номинал карты
|
||
- Валет (J) = 2 очка
|
||
- Дама (Q) = 20 очков (пиковая дама = 40 очков)
|
||
- Король (K) = 4 очка
|
||
- Туз (A) = 11 очков
|
||
|
||
**Специальные правила:**
|
||
- **Победа дамой**: Вычитается 20 очков (пиковая дама - 40)
|
||
- **Ровно 101 очко**: Счёт обнуляется до 0
|
||
- **Больше 101 очка**: Игрок выбывает из игры
|
||
- **Дилер следующего раунда**: Проигравший предыдущего раунда
|
||
|
||
## Установка и запуск
|
||
|
||
### Требования
|
||
- Python 3.8+
|
||
|
||
### Установка зависимостей
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
### Запуск сервера
|
||
|
||
```bash
|
||
python server.py
|
||
```
|
||
|
||
Сервер запустится на:
|
||
- WebSocket: `ws://localhost:8765`
|
||
- HTTP: `http://localhost:8080`
|
||
|
||
### Игра
|
||
|
||
#### Локально:
|
||
1. Откройте браузер и перейдите на `http://localhost:8080`
|
||
2. Введите никнейм и создайте комнату или присоединитесь к существующей
|
||
3. Дождитесь минимум 2 игроков
|
||
4. Все игроки нажимают "Готов"
|
||
5. Игра начинается автоматически!
|
||
|
||
#### По сети:
|
||
1. **Хост:**
|
||
- Узнайте свой IP адрес:
|
||
- Linux/Mac: `ip addr` или `ifconfig`
|
||
- Windows: `ipconfig`
|
||
- Откройте `http://localhost:8080` или `http://ВАШ_IP:8080`
|
||
- Создайте комнату
|
||
|
||
2. **Другие игроки:**
|
||
- Откройте `http://IP_ХОСТА:8080` в браузере
|
||
- Присоединитесь к комнате
|
||
|
||
3. **Важно:** Убедитесь что порты 8080 и 8765 открыты в файрволе
|
||
|
||
**Примечание:** Каждый игрок видит только свои карты! Карты других игроков скрыты.
|
||
|
||
#### С reverse proxy (HTTPS/WSS):
|
||
Если вы используете reverse proxy (nginx, caddy и т.д.) с доменами:
|
||
|
||
1. **Настройте reverse proxy:**
|
||
- HTTP/HTTPS домен (например `domain.com`) → `localhost:8080`
|
||
- WebSocket домен (например `ws.domain.com`) → `localhost:8765`
|
||
|
||
2. **Раскомментируйте в `client/index.html`:**
|
||
```html
|
||
<meta name="ws-host" content="ws.domain.com">
|
||
```
|
||
Укажите ваш WebSocket домен без протокола (wss:// добавится автоматически)
|
||
|
||
3. **Пример конфигурации nginx:**
|
||
```nginx
|
||
# HTTP сервер
|
||
server {
|
||
listen 443 ssl;
|
||
server_name domain.com;
|
||
|
||
location / {
|
||
proxy_pass http://localhost:8080;
|
||
proxy_http_version 1.1;
|
||
}
|
||
}
|
||
|
||
# WebSocket сервер
|
||
server {
|
||
listen 443 ssl;
|
||
server_name ws.domain.com;
|
||
|
||
location / {
|
||
proxy_pass http://localhost:8765;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection "upgrade";
|
||
}
|
||
}
|
||
```
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
chekh/
|
||
├── server.py # Серверная часть на Python
|
||
├── requirements.txt # Зависимости Python
|
||
├── client/
|
||
│ ├── index.html # HTML интерфейс
|
||
│ ├── style.css # Стили
|
||
│ ├── game.js # Клиентская логика
|
||
│ ├── sw.js # Service Worker для PWA
|
||
│ ├── manifest.json # PWA манифест
|
||
│ ├── rules.md # Правила игры (Markdown)
|
||
│ ├── sounds/ # Звуковые эффекты (.aac/.ogg)
|
||
│ └── icons/ # Иконки для PWA
|
||
├── rules.md # Правила игры
|
||
└── README.md # Документация
|
||
```
|
||
|
||
## Технологии
|
||
|
||
- **Backend**: Python, websockets, aiohttp, PostgreSQL
|
||
- **Frontend**: Vanilla JavaScript, HTML5, CSS3
|
||
- **Протокол**: WebSocket для real-time коммуникации
|
||
- **База данных**: PostgreSQL для сохранения состояния игры
|
||
- **Хранилище**: localStorage для идентификации игроков
|
||
|
||
## Особенности
|
||
|
||
### 🎮 Игровой процесс
|
||
- ✅ Real-time многопользовательская игра (2-4 игрока)
|
||
- ✅ **Круговой игровой стол** с визуальным отображением
|
||
- ✅ **Карты противников отображаются рубашками** по количеству
|
||
- ✅ Полная реализация всех правил и специальных карт
|
||
- ✅ Система подсчёта очков с особыми правилами (101 очко)
|
||
- ✅ **Игра с ботами** (можно играть с 1, 2 или 3 ботами)
|
||
- ✅ **Умные боты** с приоритетом специальных карт и оценкой очков
|
||
|
||
### 💾 Сохранение и переподключение
|
||
- ✅ **Сохранение состояния игры в PostgreSQL**
|
||
- ✅ **URL для комнат**: `/room/{room_id}`
|
||
- ✅ **Продолжение игры после обновления страницы**
|
||
- ✅ **localStorage для идентификации игроков**
|
||
- ✅ Автоматическое переподключение при разрыве связи
|
||
- ✅ **Page Visibility API** - игра останавливается в фоне
|
||
|
||
### 🎨 Интерфейс
|
||
- ✅ Современный и красивый UI с градиентами
|
||
- ✅ Адаптивный дизайн (десктоп + мобильные)
|
||
- ✅ **Анимации** карт и действий
|
||
- ✅ **Звуковые эффекты** для всех игровых событий (.aac)
|
||
- ✅ **Лог игры** (последние 10 событий)
|
||
- ✅ **Чат** для общения между игроками
|
||
- ✅ **Правила игры** встроены в интерфейс (Markdown)
|
||
|
||
### ⌨️ Управление
|
||
- ✅ **Горячие клавиши**:
|
||
- `T` / `Е` - открыть чат
|
||
- `Enter` - отправить сообщение
|
||
- `Пробел` - взять карту / пропустить ход
|
||
- ✅ Кнопки управления звуком, полноэкранным режимом
|
||
|
||
### 📱 PWA (Progressive Web App)
|
||
- ✅ **Установка как приложение** на телефон/десктоп
|
||
- ✅ **Service Worker** для оффлайн-кэширования
|
||
- ✅ **Манифест** с иконками и настройками
|
||
- ✅ Работает без интернета (после первой загрузки)
|
||
|
||
### Игровой интерфейс:
|
||
|
||
**Круговое расположение игроков:**
|
||
- **Центр**: Текущая карта на поле + колода справа
|
||
- **Внизу**: Ваши карты (повёрнуты к вам)
|
||
- **Сверху**: Противник (2 игрока) - карты рубашками
|
||
- **Слева**: Противник (3+ игрока) - карты сгруппированы
|
||
- **Справа**: Противник (4 игрока) - карты сгруппированы
|
||
- **Подсветка**: Текущий игрок подсвечивается жёлтым с анимацией
|
||
|
||
### Как работает сохранение:
|
||
|
||
1. При создании/присоединении к комнате URL меняется на `/room/{room_id}`
|
||
2. Ваш `player_id` сохраняется в localStorage
|
||
3. При обновлении страницы игра автоматически восстанавливается
|
||
4. При выходе из комнаты localStorage очищается
|
||
5. Все состояние игры хранится в PostgreSQL базе данных
|
||
|
||
Приятной игры! 🎮
|