dice

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

양쪽 이전 판 이전 판
dice [2025/07/29 19:48] – 제거됨 - 바깥 편집 (Unknown date) 127.0.0.1dice [2025/07/29 19:48] (현재) – ↷ 문서 이름이 주사위에서 dice(으)로 바뀌었습니다 dndkr
줄 1: 줄 1:
 +====== 주사위 굴리기! ======
 +<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>