<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>เกมหมากล้อม - Go Game</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.game-container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
padding: 30px;
}
.game-header {
text-align: center;
margin-bottom: 30px;
}
.game-header h1 {
color: #333;
margin: 0 0 10px 0;
font-size: 2.5em;
}
.game-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 15px;
background: #f8f9fa;
border-radius: 10px;
}
.player-info {
display: flex;
align-items: center;
gap: 10px;
}
.stone-indicator {
width: 30px;
height: 30px;
border-radius: 50%;
border: 2px solid #333;
}
.black-stone {
background: #333;
}
.white-stone {
background: #fff;
}
.current-turn {
box-shadow: 0 0 10px rgba(0, 123, 255, 0.5);
}
.board-container {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
.go-board {
background: #deb887;
border: 3px solid #8b4513;
border-radius: 10px;
padding: 20px;
box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.1);
}
.board-grid {
display: inline-block;
position: relative;
}
.grid-line {
position: absolute;
background: #333;
}
.grid-line.horizontal {
height: 1px;
width: 100%;
left: 0;
}
.grid-line.vertical {
width: 1px;
height: 100%;
top: 0;
}
.intersection {
position: absolute;
width: 40px;
height: 40px;
border-radius: 50%;
cursor: pointer;
transform: translate(-50%, -50%);
transition: all 0.2s ease;
}
.intersection:hover {
background: rgba(0, 123, 255, 0.3);
}
.stone {
width: 36px;
height: 36px;
border-radius: 50%;
border: 2px solid #333;
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.stone.black {
background: linear-gradient(135deg, #333 0%, #000 100%);
}
.stone.white {
background: linear-gradient(135deg, #fff 0%, #f0f0f0 100%);
}
.controls {
text-align: center;
margin-top: 20px;
}
.btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 12px 24px;
border-radius: 25px;
cursor: pointer;
font-size: 16px;
margin: 0 10px;
transition: all 0.3s ease;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.difficulty-selector {
margin: 20px 0;
text-align: center;
}
.difficulty-selector select {
padding: 8px 16px;
border: 2px solid #ddd;
border-radius: 5px;
font-size: 16px;
}
.status-message {
text-align: center;
margin-top: 20px;
padding: 10px;
border-radius: 5px;
font-weight: bold;
}
.status-message.info {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #b8daff;
}
.status-message.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.status-message.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.loading {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid #f3f3f3;
border-top: 3px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div class="game-container">
<div class="game-header">
<h1>🔵⚪ เกมหมากล้อม</h1>
<p>เล่นกับคอมพิวเตอร์ด้วย Monte Carlo Tree Search AI</p>
</div>
<div class="game-info">
<div class="player-info">
<div class="stone-indicator black-stone" id="black-indicator"></div>
<div>
<div>ผู้เล่น (ดำ)</div>
<div>จับได้: <span id="black-captures">0</span> ตัว</div>
</div>
</div>
<div class="current-player">
ตาของ: <span id="current-player-text">ผู้เล่น (ดำ)</span>
</div>
<div class="player-info">
<div class="stone-indicator white-stone" id="white-indicator"></div>
<div>
<div>คอมพิวเตอร์ (ขาว)</div>
<div>จับได้: <span id="white-captures">0</span> ตัว</div>
</div>
</div>
</div>
<div class="difficulty-selector">
<label for="difficulty">ระดับความยาก: </label>
<select id="difficulty">
<option value="500">ง่าย (500 simulations)</option>
<option value="1000" selected>ปานกลาง (1000 simulations)</option>
<option value="2000">ยาก (2000 simulations)</option>
<option value="5000">ยากมาก (5000 simulations)</option>
</select>
</div>
<div class="board-container">
<div class="go-board">
<div class="board-grid" id="board-grid">
<!-- Grid lines จะถูกสร้างด้วย JavaScript -->
</div>
</div>
</div>
<div class="controls">
<button class="btn" onclick="newGame()">เกมใหม่</button>
<button class="btn" onclick="undoMove()" id="undo-btn">ย้อนกลับ</button>
<button class="btn" onclick="pass()" id="pass-btn">ผ่าน</button>
<button class="btn" onclick="surrender()" id="surrender-btn">ยอมแพ้</button>
</div>
<div id="status-message" class="status-message info">
คลิกที่จุดบนกระดานเพื่อวางหิน
</div>
</div>
<script>
class GoGameClient {
constructor() {
this.boardSize = 13; // ใช้ขนาด 13x13 เพื่อความเร็ว (19x19 สำหรับมืออาชีพ)
this.gameState = null;
this.isPlayerTurn = true;
this.isAIThinking = false;
this.gameHistory = [];
this.cellSize = 40;
this.apiUrl = 'api/game.php';
this.initializeBoard();
this.newGame();
}
initializeBoard() {
const boardGrid = document.getElementById('board-grid');
const boardWidth = (this.boardSize - 1) * this.cellSize;
const boardHeight = (this.boardSize - 1) * this.cellSize;
boardGrid.style.width = boardWidth + 'px';
boardGrid.style.height = boardHeight + 'px';
// สร้าง grid lines
this.createGridLines(boardGrid);
// สร้าง intersections
this.createIntersections(boardGrid);
}
createGridLines(container) {
// Horizontal lines
for (let i = 0; i < this.boardSize; i++) {
const line = document.createElement('div');
line.className = 'grid-line horizontal';
line.style.top = (i * this.cellSize) + 'px';
container.appendChild(line);
}
// Vertical lines
for (let i = 0; i < this.boardSize; i++) {
const line = document.createElement('div');
line.className = 'grid-line vertical';
line.style.left = (i * this.cellSize) + 'px';
container.appendChild(line);
}
}
createIntersections(container) {
for (let x = 0; x < this.boardSize; x++) {
for (let y = 0; y < this.boardSize; y++) {
const intersection = document.createElement('div');
intersection.className = 'intersection';
intersection.style.left = (x * this.cellSize) + 'px';
intersection.style.top = (y * this.cellSize) + 'px';
intersection.setAttribute('data-x', x);
intersection.setAttribute('data-y', y);
intersection.addEventListener('click', (e) => {
this.handleIntersectionClick(x, y);
});
container.appendChild(intersection);
}
}
}
async newGame() {
try {
const response = await fetch(this.apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'new_game',
size: this.boardSize
})
});
this.gameState = await response.json();
this.gameHistory = [JSON.parse(JSON.stringify(this.gameState))];
this.isPlayerTurn = true;
this.isAIThinking = false;
this.updateDisplay();
this.showMessage('เกมใหม่เริ่มต้นแล้ว! คุณเป็นฝ่ายดำ', 'info');
} catch (error) {
console.error('Error starting new game:', error);
this.showMessage('เกิดข้อผิดพลาดในการเริ่มเกมใหม่', 'error');
}
}
async handleIntersectionClick(x, y) {
if (!this.isPlayerTurn || this.isAIThinking ||
this.gameState.board[x][y] !== 0) {
return;
}
try {
const response = await fetch(this.apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'make_move',
gameState: this.gameState,
x: x,
y: y,
player: 1, // ผู้เล่นเป็นฝ่ายดำ (1)
size: this.boardSize
})
});
const result = await response.json();
if (result.success) {
this.gameState = result.gameState;
this.gameHistory.push(JSON.parse(JSON.stringify(this.gameState)));
this.isPlayerTurn = false;
this.updateDisplay();
this.showMessage('รอ AI คิด...', 'info');
// ให้ AI เล่น
setTimeout(() => this.makeAIMove(), 500);
} else {
this.showMessage(result.message || 'การเดินไม่ถูกต้อง', 'error');
}
} catch (error) {
console.error('Error making move:', error);
this.showMessage('เกิดข้อผิดพลาดในการเดิน', 'error');
}
}
async makeAIMove() {
if (this.isAIThinking) return;
this.isAIThinking = true;
this.showMessage('<div class="loading"></div> AI กำลังคิด...', 'info');
try {
const difficulty = document.getElementById('difficulty').value;
const response = await fetch(this.apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'ai_move',
gameState: this.gameState,
difficulty: parseInt(difficulty),
size: this.boardSize
})
});
const result = await response.json();
if (result.success) {
this.gameState = result.gameState;
this.gameHistory.push(JSON.parse(JSON.stringify(this.gameState)));
this.isPlayerTurn = true;
this.isAIThinking = false;
this.updateDisplay();
this.showMessage(`AI เดินที่ (${result.move.x}, ${result.move.y})`, 'success');
} else {
this.isAIThinking = false;
this.showMessage(result.message || 'AI ไม่สามารถเดินได้', 'error');
}
} catch (error) {
console.error('Error making AI move:', error);
this.isAIThinking = false;
this.showMessage('เกิดข้อผิดพลาดในการคิดของ AI', 'error');
}
}
updateDisplay() {
this.updateBoard();
this.updateGameInfo();
this.updateControls();
}
updateBoard() {
// ลบหินเก่าทั้งหมด
const stones = document.querySelectorAll('.stone');
stones.forEach(stone => stone.remove());
// วางหินใหม่ตามสถานะปัจจุบัน
for (let x = 0; x < this.boardSize; x++) {
for (let y = 0; y < this.boardSize; y++) {
const cellValue = this.gameState.board[x][y];
if (cellValue !== 0) {
this.placeStone(x, y, cellValue);
}
}
}
}
placeStone(x, y, player) {
const intersection = document.querySelector(
`[data-x="${x}"][data-y="${y}"]`
);
if (intersection) {
const stone = document.createElement('div');
stone.className = `stone ${player === 1 ? 'black' : 'white'}`;
intersection.appendChild(stone);
}
}
updateGameInfo() {
document.getElementById('black-captures').textContent =
this.gameState.blackCaptures;
document.getElementById('white-captures').textContent =
this.gameState.whiteCaptures;
const currentPlayerText = document.getElementById('current-player-text');
const blackIndicator = document.getElementById('black-indicator');
const whiteIndicator = document.getElementById('white-indicator');
// ลบ class current-turn ทั้งหมด
blackIndicator.classList.remove('current-turn');
whiteIndicator.classList.remove('current-turn');
if (this.isPlayerTurn && !this.isAIThinking) {
currentPlayerText.textContent = 'ผู้เล่น (ดำ)';
blackIndicator.classList.add('current-turn');
} else {
currentPlayerText.textContent = 'คอมพิวเตอร์ (ขาว)';
whiteIndicator.classList.add('current-turn');
}
}
updateControls() {
const undoBtn = document.getElementById('undo-btn');
const passBtn = document.getElementById('pass-btn');
const surrenderBtn = document.getElementById('surrender-btn');
const canInteract = this.isPlayerTurn && !this.isAIThinking;
undoBtn.disabled = !canInteract || this.gameHistory.length <= 1;
passBtn.disabled = !canInteract;
surrenderBtn.disabled = !canInteract;
}
showMessage(message, type = 'info') {
const statusElement = document.getElementById('status-message');
statusElement.innerHTML = message;
statusElement.className = `status-message ${type}`;
}
undoMove() {
if (this.gameHistory.length > 1 && this.isPlayerTurn && !this.isAIThinking) {
// ย้อนกลับ 2 ตา (ผู้เล่นและ AI)
if (this.gameHistory.length >= 3) {
this.gameHistory.pop(); // ลบตาของ AI
this.gameHistory.pop(); // ลบตาของผู้เล่น
} else {
this.gameHistory.pop(); // ลบตาแรกของผู้เล่น
}
this.gameState = JSON.parse(JSON.stringify(
this.gameHistory[this.gameHistory.length - 1]
));
this.isPlayerTurn = true;
this.updateDisplay();
this.showMessage('ย้อนกลับแล้ว', 'info');
}
}
pass() {
if (this.isPlayerTurn && !this.isAIThinking) {
this.showMessage('คุณผ่านตา', 'info');
this.isPlayerTurn = false;
// ให้ AI เล่นต่อ
setTimeout(() => this.makeAIMove(), 1000);
}
}
surrender() {
if (this.isPlayerTurn && !this.isAIThinking) {
this.showMessage('คุณยอมแพ้! คอมพิวเตอร์ชนะ', 'error');
this.isPlayerTurn = false;
}
}
}
// Global functions สำหรับปุ่มต่างๆ
let gameClient;
function newGame() {
gameClient.newGame();
}
function undoMove() {
gameClient.undoMove();
}
function pass() {
gameClient.pass();
}
function surrender() {
gameClient.surrender();
}
// เริ่มต้นเกมเมื่อหน้าเว็บโหลดเสร็จ
document.addEventListener('DOMContentLoaded', function() {
gameClient = new GoGameClient();
});
</script>
</body>
</html>