import React, { useState, useCallback, useEffect } from ‘react’;
import { RotateCw, Play, RotateCcw, Home, Droplets, Settings, Zap } from ‘lucide-react’;
const PipeMazeGame = () => {
const [currentLevel, setCurrentLevel] = useState(1);
const [gameState, setGameState] = useState(‘playing’); // playing, success, failed
const [grid, setGrid] = useState([]);
const [availablePieces, setAvailablePieces] = useState({});
const [selectedPiece, setSelectedPiece] = useState(null);
const [waterFlow, setWaterFlow] = useState([]);
const [showInstructions, setShowInstructions] = useState(true);
// Типы труб и элементов
const PIPE_TYPES = {
empty: { symbol: ”, connections: [] },
straight_h: { symbol: ‘━’, connections: [‘left’, ‘right’] },
straight_v: { symbol: ‘┃’, connections: [‘top’, ‘bottom’] },
corner_tl: { symbol: ‘┗’, connections: [‘top’, ‘right’] },
corner_tr: { symbol: ‘┛’, connections: [‘top’, ‘left’] },
corner_bl: { symbol: ‘┏’, connections: [‘bottom’, ‘right’] },
corner_br: { symbol: ‘┓’, connections: [‘bottom’, ‘left’] },
cross: { symbol: ‘┼’, connections: [‘top’, ‘bottom’, ‘left’, ‘right’] },
tee_up: { symbol: ‘┻’, connections: [‘top’, ‘left’, ‘right’] },
tee_down: { symbol: ‘┳’, connections: [‘bottom’, ‘left’, ‘right’] },
tee_left: { symbol: ‘┫’, connections: [‘top’, ‘bottom’, ‘left’] },
tee_right: { symbol: ‘┣’, connections: [‘top’, ‘bottom’, ‘right’] },
source: { symbol: ‘?’, connections: [‘bottom’], fixed: true },
sink: { symbol: ‘?’, connections: [‘top’], fixed: true },
pump: { symbol: ‘⚡’, connections: [‘top’, ‘bottom’] },
filter: { symbol: ‘?’, connections: [‘left’, ‘right’] }
};
// Уровни игры
const LEVELS = {
1: {
name: “Первые шаги”,
description: “Подведите воду от дома к душу”,
grid: [
[‘source’, ’empty’, ’empty’, ’empty’],
[’empty’, ’empty’, ’empty’, ’empty’],
[’empty’, ’empty’, ’empty’, ’empty’],
[’empty’, ’empty’, ’empty’, ‘sink’]
],
pieces: {
straight_h: 3,
straight_v: 3,
corner_tl: 1,
corner_tr: 1,
corner_bl: 1,
corner_br: 1
},
maxMoves: 10
},
2: {
name: “Поворот за поворотом”,
description: “Используйте углы для обхода препятствий”,
grid: [
[‘source’, ’empty’, ‘wall’, ’empty’],
[’empty’, ’empty’, ‘wall’, ’empty’],
[’empty’, ’empty’, ’empty’, ’empty’],
[’empty’, ‘wall’, ’empty’, ‘sink’]
],
pieces: {
straight_h: 2,
straight_v: 2,
corner_tl: 2,
corner_tr: 2,
corner_bl: 2,
corner_br: 2
},
maxMoves: 12
},
3: {
name: “Фильтрация”,
description: “Вода должна пройти через фильтр”,
grid: [
[‘source’, ’empty’, ’empty’, ’empty’, ’empty’],
[’empty’, ’empty’, ’empty’, ’empty’, ’empty’],
[’empty’, ’empty’, ‘filter’, ’empty’, ’empty’],
[’empty’, ’empty’, ’empty’, ’empty’, ’empty’],
[’empty’, ’empty’, ’empty’, ’empty’, ‘sink’]
],
pieces: {
straight_h: 4,
straight_v: 4,
corner_tl: 2,
corner_tr: 2,
corner_bl: 2,
corner_br: 2
},
maxMoves: 15
}
};
// Инициализация уровня
const initializeLevel = useCallback((levelNum) => {
const level = LEVELS[levelNum];
if (!level) return;
setGrid(level.grid.map(row => row.map(cell => ({ type: cell, rotation: 0 }))));
setAvailablePieces(level.pieces);
setSelectedPiece(null);
setWaterFlow([]);
setGameState(‘playing’);
}, []);
useEffect(() => {
initializeLevel(currentLevel);
}, [currentLevel, initializeLevel]);
// Проверка соединений
const getConnections = (piece, rotation = 0) => {
const connections = PIPE_TYPES[piece.type]?.connections || [];
const rotations = [‘top’, ‘right’, ‘bottom’, ‘left’];
return connections.map(conn => {
const index = rotations.indexOf(conn);
return rotations[(index + rotation) % 4];
});
};
// Проверка потока воды
const checkWaterFlow = useCallback(() => {
const rows = grid.length;
const cols = grid[0]?.length || 0;
// Найти источник
let sourcePos = null;
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
if (grid[r][c].type === 'source') {
sourcePos = [r, c];
break;
}
}
if (sourcePos) break;
}
if (!sourcePos) return [];
const visited = new Set();
const queue = [sourcePos];
const flow = [sourcePos];
while (queue.length > 0) {
const [r, c] = queue.shift();
const key = `${r},${c}`;
if (visited.has(key)) continue;
visited.add(key);
const currentPiece = grid[r][c];
const connections = getConnections(currentPiece, currentPiece.rotation);
const directions = {
top: [-1, 0],
right: [0, 1],
bottom: [1, 0],
left: [0, -1]
};
connections.forEach(direction => {
const [dr, dc] = directions[direction];
const newR = r + dr;
const newC = c + dc;
if (newR >= 0 && newR < rows && newC >= 0 && newC < cols) {
const neighborPiece = grid[newR][newC];
if (neighborPiece.type !== 'empty' && neighborPiece.type !== 'wall') {
const neighborConnections = getConnections(neighborPiece, neighborPiece.rotation);
const oppositeDirection = {
top: 'bottom',
right: 'left',
bottom: 'top',
left: 'right'
}[direction];
if (neighborConnections.includes(oppositeDirection)) {
const neighborKey = `${newR},${newC}`;
if (!visited.has(neighborKey)) {
queue.push([newR, newC]);
flow.push([newR, newC]);
}
}
}
}
});
}
return flow;
}, [grid]);
// Размещение элемента на поле
const placePiece = (row, col) => {
if (!selectedPiece || gameState !== ‘playing’) return;
const currentCell = grid[row][col];
if (currentCell.type !== ’empty’) return;
if (availablePieces[selectedPiece] <= 0) return;
const newGrid = [...grid];
newGrid[row][col] = { type: selectedPiece, rotation: 0 };
setGrid(newGrid);
setAvailablePieces(prev => ({
…prev,
[selectedPiece]: prev[selectedPiece] – 1
}));
};
// Поворот элемента
const rotatePiece = (row, col, direction = 1) => {
const piece = grid[row][col];
if (piece.type === ’empty’ || PIPE_TYPES[piece.type]?.fixed) return;
const newGrid = […grid];
newGrid[row][col] = {
…piece,
rotation: (piece.rotation + direction + 4) % 4
};
setGrid(newGrid);
};
// Запуск воды
const startWaterFlow = () => {
const flow = checkWaterFlow();
setWaterFlow(flow);
// Проверить, достигла ли вода всех потребителей
const sinks = [];
grid.forEach((row, r) => {
row.forEach((cell, c) => {
if (cell.type === ‘sink’) {
sinks.push([r, c]);
}
});
});
const allSinksReached = sinks.every(sink =>
flow.some(([fr, fc]) => fr === sink[0] && fc === sink[1])
);
if (allSinksReached && sinks.length > 0) {
setGameState(‘success’);
} else if (flow.length > 1) {
setGameState(‘failed’);
}
};
// Сброс уровня
const resetLevel = () => {
initializeLevel(currentLevel);
};
// Следующий уровень
const nextLevel = () => {
if (LEVELS[currentLevel + 1]) {
setCurrentLevel(currentLevel + 1);
}
};
// Рендер ячейки сетки
const renderCell = (cell, row, col) => {
const isWaterFlowing = waterFlow.some(([r, c]) => r === row && c === col);
const piece = PIPE_TYPES[cell.type];
let symbol = piece?.symbol || ”;
let bgColor = ‘bg-gray-100’;
if (cell.type === ‘wall’) {
bgColor = ‘bg-gray-800’;
symbol = ‘■’;
} else if (isWaterFlowing) {
bgColor = ‘bg-blue-200′;
} else if (cell.type !== ’empty’) {
bgColor = ‘bg-gray-200’;
}
return (
onContextMenu={(e) => {
e.preventDefault();
rotatePiece(row, col);
}}
style={{
transform: `rotate(${cell.rotation * 90}deg)`
}}
>
{symbol}
);
};
if (showInstructions) {
return (
? Водопроводные лабиринты
Добро пожаловать в игру-головоломку про сантехника! Ваша задача – проложить трубы от источника воды до потребителей.
Как играть:
- • Выберите деталь из панели инструментов
- • Кликните на пустую ячейку, чтобы установить деталь
- • Правый клик или кнопка поворота – поворот детали
- • Нажмите “Пустить воду” для проверки
- • Вода должна дойти до всех потребителей
Символы:
);
}
return (
? Водопроводные лабиринты
{/* Игровое поле */}
row.map((cell, colIndex) => renderCell(cell, rowIndex, colIndex))
)}
{/* Кнопки управления */}
{/* Статус игры */}
{gameState === ‘success’ && (
)}
{gameState === ‘failed’ && (
)}
{/* Панель инструментов */}
Доступные детали
))}
{selectedPiece && (
)}
{/* Дополнительные кнопки */}
);
};
export default PipeMazeGame;