※この部分は HTML 内に書いてあるだけで、実際には server.js にコピーして使います。
/* ===== server.js ===== */
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = new Server(server, { cors: { origin: '*' } });
app.use(express.static('public'));
const rooms = {};
function createRoomIfNotExists(roomCode) {
if (!rooms[roomCode]) {
rooms[roomCode] = {
players: {},
deck: [],
discard: [],
turnOrder: [],
currentTurnIndex: 0,
started: false,
};
}
}
function generateRoomCode() {
return Math.floor(1000 + Math.random() * 9000).toString();
}
function createSimpleDeck() {
const cards = [];
cards.push({ type: '犯人' });
for (let i = 0; i < 4; i++) cards.push({ type: '探偵' });
for (let i = 0; i < 5; i++) cards.push({ type: 'アリバイ' });
for (let i = 0; i < 10; i++) cards.push({ type: '一般人' });
for (let i = cards.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[cards[i], cards[j]] = [cards[j], cards[i]];
}
return cards;
}
function dealCards(room, cardsPerPlayer = 4) {
const ids = Object.keys(room.players);
ids.forEach(id => room.players[id].hand = []);
for (let i = 0; i < cardsPerPlayer; i++) {
ids.forEach(id => {
const card = room.deck.pop();
if (card) room.players[id].hand.push(card);
});
}
}
function getPublicState(roomCode) {
const room = rooms[roomCode];
return {
players: Object.values(room.players).map(p => ({
name: p.name,
handCount: p.hand.length,
})),
discard: room.discard,
turnPlayerName:
room.turnOrder.length > 0
? room.players[room.turnOrder[room.currentTurnIndex]].name
: null,
started: room.started,
};
}
io.on('connection', socket => {
socket.on('createRoom', ({ name }, callback) => {
const roomCode = generateRoomCode();
createRoomIfNotExists(roomCode);
const room = rooms[roomCode];
room.players[socket.id] = { name, hand: [] };
room.turnOrder.push(socket.id);
socket.join(roomCode);
callback({ roomCode, state: getPublicState(roomCode) });
io.to(roomCode).emit('stateUpdate', getPublicState(roomCode));
});
socket.on('joinRoom', ({ roomCode, name }, callback) => {
createRoomIfNotExists(roomCode);
const room = rooms[roomCode];
room.players[socket.id] = { name, hand: [] };
room.turnOrder.push(socket.id);
socket.join(roomCode);
callback({ ok: true, state: getPublicState(roomCode) });
io.to(roomCode).emit('stateUpdate', getPublicState(roomCode));
});
socket.on('startGame', ({ roomCode }) => {
const room = rooms[roomCode];
room.deck = createSimpleDeck();
room.discard = [];
room.currentTurnIndex = 0;
room.started = true;
dealCards(room);
Object.keys(room.players).forEach(id => {
io.to(id).emit('handUpdate', room.players[id].hand);
});
io.to(roomCode).emit('stateUpdate', getPublicState(roomCode));
});
socket.on('playCard', ({ roomCode, cardIndex }) => {
const room = rooms[roomCode];
const currentId = room.turnOrder[room.currentTurnIndex];
if (socket.id !== currentId) return;
const player = room.players[socket.id];
const [card] = player.hand.splice(cardIndex, 1);
room.discard.push({ ...card, playedBy: player.name });
io.to(socket.id).emit('handUpdate', player.hand);
room.currentTurnIndex =
(room.currentTurnIndex + 1) % room.turnOrder.length;
io.to(roomCode).emit('stateUpdate', getPublicState(roomCode));
});
});
server.listen(3000, () => {
console.log("http://localhost:3000");
});