/
Dmitry_SH79
/
FeelWordGap
Обзор
Документация
Войти
/
Dmitry_SH79
/
FeelWordGap
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop
frontend/src/app/app.component.ts
195 строк
8 KB
Dmitry_SH79
оно работает
21 май 2026, 17:20
21 май 2026, 17:20
c2626e7
Код
Авторство
О чём код?
import { Component, OnInit, inject } from '@angular/core'; import { GameService, UserDto, CategoryDto, GameGridDto } from './services/game.service'; //import { RouterOutlet } from '@angular/router'; import { UpperCasePipe } from '@angular/common'; export interface GridCell { char: string; x: number; y: number; statusId: number; // 0 - обычная, 1 - выделена, 2 - угадана } @Component({ selector: 'app-root', imports: [UpperCasePipe], templateUrl: './app.component.html', styleUrl: './app.component.css' }) export class AppComponent implements OnInit { private gameService = inject(GameService); categories: CategoryDto[] = []; selectedCategoryId: number | null = null; users: UserDto[] = []; selectedUserId: number | null = null; title = 'frontend'; // Переменные для хранения состояния игры currentGame: GameGridDto | null = null; gridCells: GridCell[][] = []; // Двумерный массив для рендеринга сетки // Состояние выделения isDrawing: boolean = false; currentPath: GridCell[] = []; guessedWords: string[] = []; // Список найденных слов в текущей сессии selectedSize: number = 10; // Размер по умолчанию ngOnInit(): void { // Загрузка пользователя this.gameService.getUsers().subscribe({ next: (users) => this.users = users, error: (err) => console.error('Не удалось загрузить юзеров', err) }); // Загрузка категорий this.gameService.getCategories().subscribe({ next: (cats) => this.categories = cats, error: (err) => console.error('Не удалось загрузить категории', err) }); // Глобальный сброс выделения, если пользователь отпустил мышь за пределами сетки window.addEventListener('mouseup', () => this.endSelection()); } onCategoryChange(event: Event): void { const selectElement = event.target as HTMLSelectElement; this.selectedCategoryId = Number(selectElement.value) || null; this.loadGameGrid(); } onSizeChange(event: Event): void { const selectElement = event.target as HTMLSelectElement; this.selectedSize = Number(selectElement.value) || 10; this.loadGameGrid(); } private loadGameGrid(): void { if (this.selectedCategoryId) { this.gameService.generateGrid(this.selectedCategoryId, this.selectedSize).subscribe({ next: (gameData) => { this.currentGame = gameData; this.guessedWords = []; this.isSidebarVisible = false; // Закрываем подсказку для новой игры this.buildGrid(gameData); }, error: (err) => console.error('Ошибка генерации сетки', err) }); } else { this.currentGame = null; this.gridCells = []; } } // Превращаем массив строк ["abc...", "def..."] в двумерную сетку объектов клеток private buildGrid(gameData: GameGridDto): void { this.gridCells = []; for (let x = 0; x < gameData.size; x++) { const row: GridCell[] = []; const rowString = gameData.matrix[x]; for (let y = 0; y < gameData.size; y++) { row.push({ char: rowString[y], x: x, y: y, statusId: 0 // По умолчанию все клетки обычные }); } this.gridCells.push(row); } } // --- МЕХАНИКА ВЫДЕЛЕНИЯ МЫШЬЮ --- // 1. Нажатие мыши на клетку onCellMouseDown(cell: GridCell, event: MouseEvent): void { event.preventDefault(); // Отключаем стандартное выделение текста в браузере if (cell.statusId === 2) return; // Игнорируем уже угаданные буквы this.isDrawing = true; this.currentPath = [cell]; cell.statusId = 1; // Подсвечиваем синим } // 2. Движение мыши с зажатой кнопкой на другую клетку onCellMouseEnter(cell: GridCell): void { if (!this.isDrawing || cell.statusId === 2) return; const lastCell = this.currentPath[this.currentPath.length - 1]; // Проверяем, что клетка является соседом по горизонтали или вертикали (под 90 градусов) const isNeighbor = (Math.abs(lastCell.x - cell.x) === 1 && lastCell.y === cell.y) || (Math.abs(lastCell.y - cell.y) === 1 && lastCell.x === cell.x); if (!isNeighbor) return; // Если пользователь повел мышь назад по своему пути — удаляем последнюю клетку (отмена шага) if (this.currentPath.length > 1 && this.currentPath[this.currentPath.length - 2] === cell) { lastCell.statusId = 0; this.currentPath.pop(); return; } // Если клетка еще не в пути, добавляем ее if (!this.currentPath.includes(cell)) { this.currentPath.push(cell); cell.statusId = 1; } } // 3. Отпускание мыши — проверка слова endSelection(): void { if (!this.isDrawing) return; this.isDrawing = false; if (!this.currentGame || this.currentPath.length === 0) return; // Ищем, совпадает ли собранный путь с какой-либо выигрышной комбинацией от бэкенда const matchedWord = this.currentGame.words.find(w => { if (w.coords.length !== this.currentPath.length) return false; // Сверяем каждую координату по порядку return w.coords.every((coord, index) => { const p = this.currentPath[index]; // Учитываем наш фикс осей: в JSON от бэкенда X - это столбец, Y - это строка return coord.x === p.y && coord.y === p.x; }); }); if (matchedWord) { console.log(`Угадано слово: ${matchedWord.word}`); // Проверяем, не угадывал ли игрок это слово ранее (на случай пересечения букв) if (!this.guessedWords.includes(matchedWord.word)) { this.guessedWords.push(matchedWord.word); // Красим всю змейку в зеленый цвет и блокируем this.currentPath.forEach(c => c.statusId = 2); // Проверяем финал игры if (this.guessedWords.length === this.currentGame.words.length) { // Используем setTimeout, чтобы Angular сначала успел перекрасить клетки в зеленый цвет в HTML setTimeout(() => { alert(`🎉 Поздравляем! Вы нашли все ${this.guessedWords.length} слов(а) и успешно завершили игру!`); }, 100); } } } else { // Сбрасываем синее выделение, если слово не угадано this.currentPath.forEach(c => { if (c.statusId === 1) c.statusId = 0; }); } this.currentPath = []; } isSidebarVisible: boolean = false; // По умолчанию список скрыт // Добавим простой метод для переключения toggleSidebar(): void { this.isSidebarVisible = !this.isSidebarVisible; } }