-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
193 lines (162 loc) · 7.6 KB
/
index.js
File metadata and controls
193 lines (162 loc) · 7.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 12000 });
const clients = new Map(); // 클라이언트가 추가될 때 마다 해당 자료구조에 추가된다.
let gameState = false; // 3명이 모이면 게임이 시작한다.
let words = [
['DHCP', '거짓말', 'DHCP'],
['키보드', '거짓말', '키보드'],
['백준', '거짓말', '백준'],
['TCP', '거짓말', 'TCP'],
['NetWork Layer', '거짓말', 'NetWork Layer'],
['ARP', '거짓말', 'ARP'],
['Link Layer', '거짓말', 'Link Layer'],
['VC', '거짓말', 'VC'],
['MPLS', '거짓말', 'MPLS'],
['MAC', '거짓말', 'MAC']
]; // 10개의 단어셋
let selectedWords = []; // 선택된 단어셋
let votes = []; // 투표 결과를 저장
let clientCounter = 1; // 클라이언트 ID를 부여하기 위한 카운터
let chatOrder = []; // 채팅의 순서
let currentChatIndex = 0; // 현재 순서를 확인
let chatCnt = 0; // 매 턴마다의 채팅 횟수
let totalCnt = 0; // 턴 수
let spectators = 0; // 관전자 수를 관리하는 변수
let spectatorCounter = 1; // 관전자 번호를 부여하기 위한 카운터
// 함수를 이용하여 메시지를 전체에게 전달
const broadcast = (data) => {
const message = JSON.stringify(data); // 모든 메시지를 문자열화된 JSON 형태로 변환
clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
};
// 상태를 업데이트하고 전체에게 전송
const updateStatus = () => {
const playerCount = Array.from(clients.values()).filter(client => client.isPlayer).length;
broadcast({
type: 'status',
players: playerCount,
spectators
});
};
const startGame = () => {
gameState = true;
// 10개의 단어셋 중 하나를 랜덤으로 선택
selectedWords = words[Math.floor(Math.random() * words.length)];
let RandomWords = selectedWords.sort(() => Math.random() - 0.5); // 단어를 랜덤으로 정렬한다.
chatOrder = Array.from(clients.keys()).filter(id => clients.get(id).isPlayer).sort(() => Math.random() - 0.5); // 채팅 순서를 랜덤으로 설정
currentChatIndex = 0; // 첫 번째 클라이언트부터 시작
let i = 0;
clients.forEach((client) => {
if (client.isPlayer && client.readyState === WebSocket.OPEN) { // 접속한 클라이언트에게 랜덤으로 단어를 제공한다.
client.send(JSON.stringify({ type: 'word', word: RandomWords[i++] }));
}
});
broadcast({ type: 'chat', message: `GAME START!!!\nChating order: ${chatOrder.map(id => `Client ${id}`).join(', ')}` }); // 해당 문구가 클라이언트 채팅에서 보이지 않는 문제 발생
broadcast({ type: 'chat', message: `It's now client ${chatOrder[currentChatIndex]}'s turn.` }); // 채팅 순서를 알려준다.
};
// 투표를 수행하고 결과를 채팅창에 보여준다.
const endGame = () => {
gameState = false;
let voteCounts = votes.reduce((acc, vote) => {
acc[vote] = (acc[vote] || 0) + 1;
return acc;
}, {});
let maxVotes = Math.max(...Object.values(voteCounts));
let mostVoted = Object.keys(voteCounts).find(key => voteCounts[key] === maxVotes);
let otherWordClientId = chatOrder[selectedWords.findIndex(word => word === '거짓말')];
let correct = parseInt(mostVoted) === otherWordClientId;
let result = `${mostVoted}`; // 다득표를 받은 클라이언트 아이디
broadcast({ type: 'result', correct, votes: result });
if (correct) broadcast({ type: 'chat', message: "Liar Lose!"}); // 지목된 사람이 라이어인 경우
else broadcast({ type: 'chat', message: "Liar Win!"}); // 지목된 사람이 라이어가 아닌 경우
console.log("Game ended!");
clients.forEach((client) => { // 게임이 종료되면 웹소켓을 닫는다.
if (client.readyState === WebSocket.OPEN) {
client.close();
}
});
};
wss.on('connection', (ws) => {
const clientId = clientCounter++;
clients.set(clientId, ws);
console.log(`${clientId} connected`);
if (clients.size <= 3 && !gameState) {
ws.isPlayer = true; // 플레이어로 표시
} else {
ws.isPlayer = false; // 관전자로 표시
ws.spectatorNumber = spectatorCounter++;
spectators++;
}
updateStatus(); // 상태 업데이트
if (clients.size === 3 && !gameState) {
startGame(); // 클라이언트 3명이 모이면 게임이 시작한다.
}
ws.on('message', (message) => {
const parsedMessage = JSON.parse(message);
console.log(`${clientId} : ${parsedMessage}`); // 사용자가 단어에 대한 설명을 채팅으로 보내면 이를 채팅창에 출력
if (parsedMessage.type === 'spectatorMessage') {
if (!ws.isPlayer) {
broadcast({ type: 'spectatorMessage', message: `Spectator ${ws.spectatorNumber}: ${parsedMessage.message}` });
} else {
ws.send(JSON.stringify({ type: 'error', message: 'Players cannot participate in spectator chat.' }));
}
return;
}
if (!gameState) {
ws.send(JSON.stringify({ type: 'error', message: 'Game not in progress.' }));
return;
}
if (!ws.isPlayer) {
ws.send(JSON.stringify({ type: 'error', message: 'Spectators cannot participate.' }));
return;
}
if (clientId !== chatOrder[currentChatIndex]) { // 현재 차례가 아니면 메시지를 무시하고 클라이언트에게 알림
ws.send(JSON.stringify({ type: 'error', message: 'Not your turn!' }));
return;
}
chatCnt++; // 각 순서를 지키기 위한 변수
if (totalCnt === 3) { // 모두 3번씩 설명을 진행하였을 때
votes.push(parsedMessage.message);
broadcast({ type: 'vote', message: `${clientId} : ${parsedMessage.message}` });
if (votes.length === 3) { // 모든 클라이언트가 투표를 완료했을 때 endGame을 호출
endGame();
}
}
else { // 아직 횟수가 남은 경우 채팅을 출력
broadcast({ type: 'chat', message: `${clientId} : ${parsedMessage.message}` });
}
currentChatIndex = (currentChatIndex + 1) % chatOrder.length; // 다음 차례로 넘어간다.
broadcast({ type: 'chat', message: `It's now client ${chatOrder[currentChatIndex]}'s turn.` }); // 다음 채팅 순서를 알림
if (chatCnt === 3 && totalCnt < 3) {
chatCnt = 0;
totalCnt++;
if (totalCnt <= 3) { // 매 턴이 종료됨을 알림
broadcast({ type: 'chat', message: `${totalCnt} Turn Over` });
}
if (totalCnt == 3) { // 3번의 채팅기회 이후 투표하라는 메세지를 전달
broadcast({ type: 'chat', message: `Vote now!` });
}
}
});
ws.on('close', () => {
clients.delete(clientId);
console.log(`${clientId} disconnected`);
if (ws.isPlayer && gameState && clients.size < 3) {
gameState = false;
broadcast({ type: 'chat', message: "Game ended due to a client disconnecting." });
}
if (!ws.isPlayer) {
spectators--;
}
updateStatus(); // 상태 업데이트
});
ws.on('error', ( error ) => {
console.error(error);
});
});
console.log('WebSocket server is running on ws://localhost:12000');