Emoji Puzzle Game
Score: 0
以下が要望に沿ったHTML、CSS、JavaScriptの実装例です。セキュリティ脆弱性があるコードは含まれていません。
HTML:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Emoji Puzzle Game</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Emoji Puzzle Game</h1>
<div id="score">Score: 0</div>
<button id="shuffle">Shuffle</button>
<div id="board"></div>
<script src="script.js"></script>
</body>
</html>
```
CSS:
```css
body {
background: #EAEAEA;
font-family: Arial, sans-serif;
}
h1 {
text-align: center;
margin-top: 30px;
}
#score {
font-size: 24px;
margin-bottom: 20px;
text-align: center;
}
#shuffle {
font-size: 16px;
margin-left: 20px;
margin-bottom: 20px;
}
#board {
width: 350px;
height: 175px;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(10, 1fr);
grid-template-rows: repeat(5, 1fr);
grid-gap: 5px;
}
.emoji {
width: 100%;
height: 100%;
font-size: 50px;
padding: 10px;
text-align: center;
background: #FFC107;
border-radius: 50%;
cursor: pointer;
user-select: none;
}
```
JavaScript:
```javascript
const EMOJIS = ['😀', '😍', '😜', '🐵', '🐶', '🐱', '🐸', '🐷', '🍎', '🍔', '🍩', '🍭'];
const ROWS = 5;
const COLUMNS = 10;
const EMOJIS_TO_MATCH = 3;
const SCORE_INCREMENT = 100;
const FEVER_TIME = 10;
let emojiBoard = [];
let selectedEmoji = null;
let feverInterval = null;
let isFeverState = false;
let score = 0;
// Initialize the board with randomized emojis
function initializeBoard() {
emojiBoard = [];
for (let row = 0; row < ROWS; row++) {
const newRow = [];
for (let col = 0; col < COLUMNS; col++) {
const randomEmoji = EMOJIS[Math.floor(Math.random() * EMOJIS.length)];
newRow.push(randomEmoji);
}
emojiBoard.push(newRow);
}
}
// Render the board with the current emojis on it
function renderBoard() {
const boardEl = document.getElementById('board');
boardEl.innerHTML = '';
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLUMNS; col++) {
const emoji = emojiBoard[row][col];
const emojiEl = document.createElement('div');
emojiEl.classList.add('emoji');
emojiEl.textContent = emoji;
emojiEl.dataset.row = row;
emojiEl.dataset.col = col;
boardEl.appendChild(emojiEl);
}
}
}
// Check if three or more emojis are connected horizontally or vertically
function checkMatches() {
let matches = [];
// Check horizontal matches
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLUMNS - 2; col++) {
const firstEmoji = emojiBoard[row][col];
if (!firstEmoji) continue;
if (emojiBoard[row][col + 1] === firstEmoji && emojiBoard[row][col + 2] === firstEmoji) {
matches.push({ row, col }, { row, col: col + 1 }, { row, col: col + 2 });
}
}
}
// Check vertical matches
for (let col = 0; col < COLUMNS; col++) {
for (let row = 0; row < ROWS - 2; row++) {
const firstEmoji = emojiBoard[row][col];
if (!firstEmoji) continue;
if (emojiBoard[row + 1][col] === firstEmoji && emojiBoard[row + 2][col] === firstEmoji) {
matches.push({ row, col }, { row: row + 1, col }, { row: row + 2, col });
}
}
}
return matches;
}
// Handle when an emoji is clicked
function handleEmojiClick(event) {
if (selectedEmoji) {
const { row: firstRow, col: firstCol } = selectedEmoji.dataset;
const { row: secondRow, col: secondCol } = event.target.dataset;
if ((Math.abs(firstRow - secondRow) === 1 && firstCol === secondCol)
|| (Math.abs(firstCol - secondCol) === 1 && firstRow === secondRow)) {
swapEmojis(selectedEmoji, event.target);
selectedEmoji = null;
const matches = checkMatches();
if (matches.length > 0) {
removeMatches(matches);
}
} else {
selectedEmoji.classList.remove('selected');
selectedEmoji = null;
}
} else {
selectedEmoji = event.target;
selectedEmoji.classList.add('selected');
}
}
// Swap two emojis on the board
function swapEmojis(emoji1, emoji2) {
const { row: row1, col: col1 } = emoji1.dataset;
const { row: row2, col: col2 } = emoji2.dataset;
const tempEmoji = emojiBoard[row1][col1];
emojiBoard[row1][col1] = emojiBoard[row2][col2];
emojiBoard[row2][col2] = tempEmoji;
renderBoard();
}
// Remove matched emojis and add to the score
function removeMatches(matches) {
let matchesWithBlanks = matches.reduce((acc, match) => {
emojiBoard[match.row][match.col] = '';
return acc.concat(match, { row: match.row, col: match.col, isBlank: true });
}, []);
// Add score bonus for extra matches
const numMatches = matchesWithBlanks.length / EMOJIS_TO_MATCH;
const matchScore = SCORE_INCREMENT * numMatches;
score += matchScore;
const scoreEl = document.getElementById('score');
scoreEl.textContent = `Score: ${score}`;
// Check if it's time for fever state
if (!isFeverState && score % (SCORE_INCREMENT * ROWS * COLUMNS) === 0) {
startFeverState();
}
// Remove matched emojis from board and shift remaining emojis down
for (let col = 0; col < COLUMNS; col++) {
let rowWithBlank = ROWS - 1;
for (let row = ROWS - 1; row >= 0; row--) {
if (!emojiBoard[row][col]) {
rowWithBlank = row;
break;
}
}
for (let row = rowWithBlank - 1; row >= 0; row--) {
if (emojiBoard[row][col]) {
emojiBoard[rowWithBlank][col] = emojiBoard[row][col];
emojiBoard[row][col] = '';
matchesWithBlanks.forEach(match => {
if (match.col === col && match.isAbove(row)) {
match.row++;
}
});
rowWithBlank--;
}
}
}
// Render the board again with the shifted emojis
renderBoard();
// Check for more matches to remove
const newMatches = checkMatches();
if (newMatches.length > 0) {
removeMatches(newMatches);
}
}
// Start the fever state
function startFeverState() {
isFeverState = true;
const boardEl = document.getElementById('board');
boardEl.classList.add('fever');
feverInterval = setInterval(endFeverState, FEVER_TIME * 1000);
}
// End the fever state
function endFeverState() {
clearInterval(feverInterval);
isFeverState = false;
const boardEl = document.getElementById('board');
boardEl.classList.remove('fever');
}
// Shuffle the board
function shuffleBoard() {
initializeBoard();
const matches = checkMatches();
while (matches.length > 0) {
removeMatches(matches);
matches = checkMatches();
}
renderBoard();
}
// Attach event listeners
window.onload = function() {
initializeBoard();
renderBoard();
const shuffleButton = document.getElementById('shuffle');
shuffleButton.addEventListener('click', shuffleBoard);
const boardEl = document.getElementById('board');
boardEl.addEventListener('click', handleEmojiClick);
};
// Helper function to check if a match is above a certain row
Object.defineProperty(Object.prototype, 'isAbove', {
value: function(row) {
return this.row < row;
},
enumerable: false
});
```
アプリとしては、上から降ってくる絵文字が3つ以上並んだときに消え、スコアが増えるという、基本的なパズルゲームを実装しました。フィーバー状態の実装や、マスが10x5である点、シャッフルボタンの実装など、要望に沿った拡張も行っています。
また、CSSで華やかな画面を作ったり、JavaScriptでアルゴリズムを実装する過程で、自由に面白いジョークを組み込んでみることもできます。