문서 보기토론이전 판역링크Fold/unfold all맨 위로 이 문서는 읽기 전용입니다. 원본을 볼 수는 있지만 바꿀 수는 없습니다. 문제가 있다고 생각하면 관리자에게 문의하세요. ====== 주사위 굴리기! ====== <html> <div class="dice-simulator"> <style> .dice-simulator { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; max-width: 900px; margin: 20px auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px; background-color: #f9f9f9; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .dice-container { display: flex; justify-content: center; gap: 20px; /* 버튼 사이 간격 확장 */ margin-bottom: 30px; /* 하단 마진 확장 */ flex-wrap: wrap; } .dice-button { width: 90px; /* 버튼 너비 확장 */ height: 90px; /* 버튼 높이 확장 */ background-color: #4CAF50; color: white; border: none; border-radius: 12px; /* 모서리 더 둥글게 */ font-size: 32px; /* 버튼 텍스트 크기 확장 */ font-weight: bold; cursor: pointer; transition: background-color 0.2s ease, transform 0.1s ease; box-shadow: 0 5px 8px rgba(0,0,0,0.15); /* 그림자 더 강조 */ display: flex; justify-content: center; align-items: center; } .dice-button:hover { background-color: #45a049; transform: translateY(-3px); /* 호버 시 더 크게 움직이게 */ } .dice-button:active { background-color: #3e8e41; transform: translateY(0); } .result-display { background-color: #e0e0e0; padding: 15px 20px; /* 패딩 확장 */ border-radius: 8px; /* 모서리 더 둥글게 */ text-align: center; margin-bottom: 25px; /* 마진 확장 */ min-height: 70px; /* 최소 높이 확장 */ display: flex; flex-direction: column; align-items: center; justify-content: center; color: #333; font-weight: bold; } .main-result-value { font-size: 60px; /* 결과값 숫자 훨씬 더 크게 확장 */ line-height: 1; margin-bottom: 8px; /* 수식과의 간격 확장 */ } .result-expression-text { font-size: 18px; /* 수식 텍스트도 약간 확장 */ font-weight: normal; color: #555; } .expression-section { display: flex; flex-direction: column; gap: 10px; margin-bottom: 20px; } .expression-input { padding: 12px; /* 입력창 패딩 확장 */ border: 1px solid #ccc; border-radius: 5px; font-size: 18px; /* 입력창 글씨 크기 확장 */ width: calc(100% - 24px); /* 패딩 고려하여 너비 조정 */ } .expression-button { padding: 12px 18px; /* 버튼 패딩 확장 */ background-color: #008CBA; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 18px; /* 버튼 글씨 크기 확장 */ transition: background-color 0.2s ease; } .expression-button:hover { background-color: #007ba7; } .error-message { color: #d32f2f; font-size: 15px; /* 오류 메시지 글씨 크기 확장 */ margin-top: 5px; } .history-section { margin-top: 25px; /* 내역 섹션 상단 마진 확장 */ border-top: 1px solid #eee; padding-top: 18px; /* 내역 섹션 패딩 확장 */ } .history-list { list-style: none; padding: 0; margin: 0; max-height: 250px; /* 내역 목록 최대 높이 확장 */ overflow-y: auto; border: 1px solid #eee; border-radius: 5px; background-color: #fff; } .history-list li { padding: 10px 12px; /* 내역 항목 패딩 확장 */ border-bottom: 1px solid #eee; font-size: 15px; /* 내역 항목 글씨 크기 확장 */ color: #555; } .history-list li:last-child { border-bottom: none; } </style> <div class="dice-container"> <button class="dice-button" data-sides="4">d4</button> <button class="dice-button" data-sides="6">d6</button> <button class="dice-button" data-sides="8">d8</button> <button class="dice-button" data-sides="10">d10</button> <button class="dice-button" data-sides="12">d12</button> <button class="dice-button" data-sides="20">d20</button> <button class="dice-button" data-sides="100">d100</button> </div> <div class="result-display" id="diceResult"> <div class="main-result-value" id="mainResultValue"></div> <div class="result-expression-text" id="resultExpressionText">주사위 굴리기</div> </div> <hr> <div class="expression-section"> <h3>수식 입력</h3> <input type="text" id="expressionInput" class="expression-input" placeholder="예: 1d20+3"> <button id="calculateExpression" class="expression-button">굴리기</button> <div id="expressionError" class="error-message"></div> </div> <div class="history-section"> <h3>굴림 내역 (최근 20개)</h3> <ul id="rollHistory" class="history-list"> </ul> </div> </div> <script> document.addEventListener('DOMContentLoaded', () => { const diceButtons = document.querySelectorAll('.dice-button'); const mainResultValue = document.getElementById('mainResultValue'); const resultExpressionText = document.getElementById('resultExpressionText'); const expressionInput = document.getElementById('expressionInput'); const calculateExpressionButton = document.getElementById('calculateExpression'); const expressionError = document.getElementById('expressionError'); const rollHistoryList = document.getElementById('rollHistory'); const MAX_HISTORY_ITEMS = 20; let history = []; // 초기 화면 설정 mainResultValue.textContent = ''; resultExpressionText.textContent = '...'; function formatKST(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${year}년 ${month}월 ${day}일 ${hours}시 ${minutes}분 ${seconds}초`; } function updateHistoryDisplay() { rollHistoryList.innerHTML = ''; history.forEach(item => { const listItem = document.createElement('li'); listItem.textContent = item; rollHistoryList.prepend(listItem); }); } function addRollToHistory(resultText) { const now = new Date(); const formattedDateTime = formatKST(now); history.push(`${resultText} (${formattedDateTime})`); if (history.length > MAX_HISTORY_ITEMS) { history.shift(); } updateHistoryDisplay(); } // 개별 주사위 굴리기 기능 diceButtons.forEach(button => { button.addEventListener('click', () => { const sides = parseInt(button.dataset.sides); const result = Math.floor(Math.random() * sides) + 1; mainResultValue.textContent = result; resultExpressionText.textContent = `d${sides}`; expressionError.textContent = ''; addRollToHistory(`${result}(d${sides})`); }); }); // 수식 계산 기능 calculateExpressionButton.addEventListener('click', () => { const expression = expressionInput.value.trim().toLowerCase(); expressionError.textContent = ''; if (!expression) { mainResultValue.textContent = ''; resultExpressionText.textContent = '수식을 입력해주세요.'; return; } try { const evaluatedResult = evaluateDiceExpression(expression); const finalValue = evaluatedResult.split(' ')[0]; // 결과 값만 추출 const fullExpressionWithRolls = evaluatedResult; // (굴림: ...) 포함된 문자열 mainResultValue.textContent = finalValue; resultExpressionText.textContent = expression; addRollToHistory(`${finalValue}(${expression})`); // 이 부분에서 fullExpressionWithRolls 대신 expression을 사용하여 원본 수식을 표시 } catch (e) { expressionError.textContent = e.message; mainResultValue.textContent = '오류!'; resultExpressionText.textContent = '수식 오류!'; } }); // 주사위 수식 파싱 및 계산 함수 function evaluateDiceExpression(expression) { const diceRegex = /(\d+)d(\d+)/g; let calculatedExpression = expression; const rollDetails = []; calculatedExpression = calculatedExpression.replace(diceRegex, (match, numDiceStr, numSidesStr) => { const numDice = parseInt(numDiceStr); const numSides = parseInt(numSidesStr); if (numSides <= 0) { throw new Error(`주사위 면 수는 0보다 커야 합니다. (${match})`); } let sumOfRolls = 0; let currentRolls = []; for (let i = 0; i < numDice; i++) { const roll = Math.floor(Math.random() * numSides) + 1; sumOfRolls += roll; currentRolls.push(roll); } rollDetails.push(`${numDice}d${numSides} (${currentRolls.join(', ')})`); return sumOfRolls; }); const singleDiceRegex = /(?<!\d)d(\d+)/g; calculatedExpression = calculatedExpression.replace(singleDiceRegex, (match, numSidesStr) => { const numSides = parseInt(numSidesStr); if (numSides <= 0) { throw new Error(`주사위 면 수는 0보다 커야 합니다. (${match})`); } const roll = Math.floor(Math.random() * numSides) + 1; rollDetails.push(`d${numSides} (${roll})`); return roll; }); let finalResult; try { if (/[^0-9+\-*/\s()]/.test(calculatedExpression)) { throw new Error('허용되지 않는 문자가 포함된 수식입니다.'); } finalResult = eval(calculatedExpression); } catch (e) { throw new Error('수식 계산 중 오류가 발생했습니다. 올바른 형식인지 확인해주세요.'); } if (rollDetails.length > 0) { return `${finalResult} (굴림: ${rollDetails.join(', ')})`; } else { return finalResult.toString(); } } }); </script> </html> dice.txt 마지막으로 수정됨: 2025/07/29 19:48저자 dndkr