웹사이트 링크:

https://codepen.io/pen?template=dPMMNVa

image.png

image.png


<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>주식 트레이드 시뮬레이터</title>
  <script src="<https://cdn.jsdelivr.net/npm/chart.js>"></script>
  <style>
    body { font-family: Arial; background:#111; color:white; padding:20px; }
    .container { display:flex; gap:20px; }
    .left { width:700px; }
    .right { width:300px; background:#222; padding:15px; border-radius:10px; }
    button { width:100%; padding:10px; margin:5px 0; border:none; cursor:pointer; font-size:16px; border-radius:8px; }
    .buy { background:#28a745; }
    .sell { background:#dc3545; }
    .short { background:#ff7700; }
    .cover { background:#007bff; }
    #history { height:200px; overflow-y:auto; background:#000; padding:10px; margin-top:10px; border-radius:8px; font-size:14px; }
  </style>
</head>
<body>
  <h1>📈 국내주식 50일 + 실시간 확장형 트레이드 시뮬레이터</h1>

  <div class="container">

    <div class="left">
      <canvas id="stockChart" width="700" height="350"></canvas>
    </div>

    <div class="right">
      <h2>거래 패널</h2>
      <p id="dayText">Day: -</p>
      <p id="priceText">현재가: -</p>
      <p id="assetText">총자산: -</p>

      <button class="buy" id="buyBtn">📈 매수(Buy)</button>
      <button class="sell" id="sellBtn">📉 매도(Sell)</button>
      <button class="short" id="shortSellBtn">🔻 공매도(Short)</button>
      <button class="cover" id="shortCoverBtn">🔺 공매도 청산(Cover)</button>
      <button id="nextDayBtn">➡ 다음날</button>

      <h3>AI 예측</h3>
      <button id="aiBtn">AI 예측 사용 (3회 남음)</button>

      <h3>기록</h3>
      <div id="history"></div>
    </div>

  </div>

<script>
let chart;
let day = 0;
let aiChance = 3;

let cash = 10000000;
let shares = 0;
let shortShares = 0;
let currentPrice = 0;
let priceData = [];
const FEE = 0.001;

function generate50Days(){
  let base = 10000 + Math.random()*15000;
  const arr = [];
  for(let i=0;i<50;i++){
    const r = (Math.random()*4 - 2);
    base *= (1 + r/100);
    arr.push(Math.round(base));
  }
  return arr;
}

function extendByOneDay(){
  const last = priceData[priceData.length-1];
  const r = (Math.random()*4 - 2);
  const newPrice = Math.round(last * (1 + r/100));
  priceData.push(newPrice);
}

function startGame(){
  priceData = generate50Days();
  day = 0;
  cash = 10000000;
  shares = 0;
  shortShares = 0;
  aiChance = 3;
  updateTexts();
  drawChart();
}

function nextDay(){
  day++;
  extendByOneDay();
  updateTexts();
  drawChart();
  addHistory(`📅 Day ${day+1} 진행됨`);
}

function buy(){
  currentPrice = priceData[day];
  const qty = Math.floor(cash / (currentPrice * (1 + FEE)));
  if(qty <= 0) return;
  cash -= qty * currentPrice * (1 + FEE);
  shares += qty;
  addHistory(`매수 ${qty}주`);
  updateTexts();
}

function sell(){
  if(shares <= 0) return;
  currentPrice = priceData[day];
  cash += shares * currentPrice * (1 - FEE);
  addHistory(`매도 ${shares}주`);
  shares = 0;
  updateTexts();
}

function shortSell(){
  currentPrice = priceData[day];
  const qty = Math.floor(cash / (currentPrice * (1 + FEE)));
  if(qty <= 0) return;

  shortShares += qty;
  cash += qty * currentPrice * (1 - FEE);
  addHistory(`공매도 ${qty}주`);
  updateTexts();
}

function shortCover(){
  if(shortShares <= 0) return;
  currentPrice = priceData[day];

  const cost = shortShares * currentPrice * (1 + FEE);
  cash -= cost;

  addHistory(`공매도 청산 ${shortShares}주`);
  shortShares = 0;
  updateTexts();
}

function useAI(){
  if(aiChance <= 0) return alert("AI 사용 불가");
  aiChance--;
  const today = priceData[day];
  const future = priceData[Math.max(0, day+1)];
  const diff = future - today;
  const rate = ((diff/today)*100).toFixed(2);
  const msg = diff>0 ? `상승 +${rate}%` : `하락 ${rate}%`;
  alert(`AI 예측 결과:\\n내일 변동: ${msg}`);
  document.getElementById("aiBtn").textContent = `AI 예측 사용 (${aiChance}회 남음)`;
}

function updateTexts(){
  currentPrice = priceData[day];
  const value = shares * currentPrice - shortShares * currentPrice;
  const total = cash + value;

  document.getElementById("dayText").textContent = `Day: ${day+1}`;
  document.getElementById("priceText").textContent = `현재가: ${currentPrice.toLocaleString()}원`;
  document.getElementById("assetText").textContent = `총자산: ${total.toLocaleString()}원`;
}

function drawChart(){
  const ctx = document.getElementById("stockChart").getContext('2d');
  if(chart) chart.destroy();

  chart = new Chart(ctx, {
    type:'line',
    data:{
      labels: priceData.map((_,i)=>i+1),
      datasets:[{
        label:'주가', data:priceData, borderColor:'cyan', pointRadius:0
      }]
    },
    options:{ responsive:false }
  });
}

function addHistory(text){
  const box = document.getElementById("history");
  box.innerHTML += `<div>${text}</div>`;
  box.scrollTop = box.scrollHeight;
}

// 버튼 연결
document.getElementById("buyBtn").onclick = buy;
document.getElementById("sellBtn").onclick = sell;
document.getElementById("shortSellBtn").onclick = shortSell;
document.getElementById("shortCoverBtn").onclick = shortCover;
document.getElementById("nextDayBtn").onclick = nextDay;
document.getElementById("aiBtn").onclick = useAI;

startGame();
</script>

</body>
</html>

2. ai를 활용한 인식 관련된 웹사이트 코드펜 작업

https://codepen.io/pen?template=LENNxwK

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>손가락 퀴즈 게임 (Hands Control)</title>
<style>
  body { font-family: Arial; text-align: center; background: #f0f0f0; margin:0; padding:0;}
  h1 { margin-top: 20px; }
  #quiz-container { margin: 20px auto; padding: 20px; background: #fff; border-radius: 10px; width: 90%; max-width: 700px; box-shadow: 0 0 10px rgba(0,0,0,0.2);}
  #feedback { font-size: 1.2em; margin: 10px;}
  #videoElement { display:none; }
  #canvas { border:1px solid black; border-radius:10px; margin-top:10px; }
  #categorySelect { margin-bottom: 15px; padding: 5px; font-size: 1em;}
  ul { text-align: left; list-style: none; padding-left: 0;}
  li { margin: 5px 0; padding: 5px; background: #eee; border-radius: 5px;}
  #fingerCount { font-size: 1.5em; margin: 10px; }
  button { padding: 10px 20px; font-size: 1em; margin-top: 10px; cursor: pointer;}
</style>
</head>
<body>
<h1>손가락 퀴즈 게임</h1>
<div id="quiz-container">
  <select id="categorySelect">
    <option value="all">전체</option>
    <option value="nonsense">넌센스</option>
    <option value="korean_history">한국사</option>
    <option value="world_history">세계사</option>
    <option value="general">일반상식</option>
  </select>

  <div id="question">퀴즈 준비중...</div>
  <ul id="options"></ul>
  <div id="fingerCount">손가락: 0개</div>
  <button id="submitBtn">정답 제출</button>
  <div id="feedback"></div>

  <video class="input_video" autoplay playsinline></video>
  <canvas class="output_canvas" width="640" height="480"></canvas>
</div>

<script src="<https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.min.js>"></script>
<script src="<https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js>"></script>
<script src="<https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js>"></script>

<script>
  // --- 퀴즈 문제 ---
  const quizData = [
    {category:'nonsense', q:"달이 뜨면 안 보이는 것은?", options:["달","해","별","구름","바람"], a:2},
    {category:'nonsense', q:"먹으면 살이 안 찌는 음식은?", options:["사탕","과자","물","빵","밥"], a:3},
    {category:'korean_history', q:"조선을 건국한 왕은?", options:["세종","태조","광해군","고려","정조"], a:2},
    {category:'world_history', q:"피라미드가 있는 나라는?", options:["이집트","멕시코","인도","중국","그리스"], a:1},
    {category:'general', q:"한국의 수도는?", options:["부산","서울","인천","대전","광주"], a:2},
  ];

  let currentQuiz = 0;
  let selectedCategory = "all";
  let currentFingerCount = 0;

  const questionEl = document.getElementById('question');
  const optionsEl = document.getElementById('options');
  const feedbackEl = document.getElementById('feedback');
  const categorySelect = document.getElementById('categorySelect');
  const fingerCountEl = document.getElementById('fingerCount');
  const submitBtn = document.getElementById('submitBtn');

  function getFilteredQuiz() {
    return selectedCategory === "all" ? quizData : quizData.filter(q=>q.category===selectedCategory);
  }

  function showQuiz() {
    const filteredQuiz = getFilteredQuiz();
    if(filteredQuiz.length===0){
      questionEl.innerText = "선택된 카테고리에 문제가 없습니다.";
      optionsEl.innerHTML = "";
      return;
    }
    if(currentQuiz >= filteredQuiz.length) currentQuiz = 0;
    let quiz = filteredQuiz[currentQuiz];
    questionEl.innerText = quiz.q;
    optionsEl.innerHTML = "";
    quiz.options.forEach((opt, idx) => {
      let li = document.createElement('li');
      li.innerText = `${idx+1}. ${opt}`;
      optionsEl.appendChild(li);
    });
    feedbackEl.innerText = "";
  }

  // 손가락에 따른 옵션 하이라이트
  function updateFingerSelection() {
    fingerCountEl.innerText = `손가락: ${currentFingerCount}개`;
    const filteredQuiz = getFilteredQuiz();
    if(filteredQuiz.length===0) return;
    const quiz = filteredQuiz[currentQuiz];

    Array.from(optionsEl.children).forEach((li, idx)=>{
      li.style.background = (currentFingerCount===idx+1) ? '#a0e0a0' : '#eee';
    });
  }

  // 정답 제출
  submitBtn.addEventListener('click',()=>{
    const filteredQuiz = getFilteredQuiz();
    if(filteredQuiz.length===0) return;
    let quiz = filteredQuiz[currentQuiz];
    if(currentFingerCount===quiz.a){
      feedbackEl.style.color='green';
      feedbackEl.innerText=`정답! 손가락 ${currentFingerCount}개`;
      currentQuiz++;
      setTimeout(showQuiz,1500);
    } else {
      feedbackEl.style.color='red';
      feedbackEl.innerText=`오답! 손가락 ${currentFingerCount}개`;
    }
  });

  categorySelect.addEventListener('change',()=>{
    selectedCategory = categorySelect.value;
    currentQuiz=0;
    showQuiz();
  });

  showQuiz();

  // ===== MediaPipe Hands =====
  const videoElement = document.querySelector('.input_video');
  const canvasElement = document.querySelector('.output_canvas');
  const ctx = canvasElement.getContext('2d');

  const hands = new Hands({
    locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${file}`
  });
  hands.setOptions({
    maxNumHands:1,
    modelComplexity:1,
    minDetectionConfidence:0.6,
    minTrackingConfidence:0.6
  });
  hands.onResults(onResults);

  const camera = new Camera(videoElement,{
    onFrame: async()=>{ await hands.send({image:videoElement}); },
    width:640, height:480
  });
  camera.start();

  let lastStable = 0, lastTime = 0;

  function onResults(results){
    ctx.save();
    ctx.clearRect(0,0,canvasElement.width,canvasElement.height);
    ctx.drawImage(results.image,0,0,canvasElement.width,canvasElement.height);

    if(results.multiHandLandmarks && results.multiHandLandmarks.length>0){
      const lm = results.multiHandLandmarks[0];
      drawConnectors(ctx,lm,HAND_CONNECTIONS,{color:'#00FF00',lineWidth:3});
      drawLandmarks(ctx,lm,{color:'#FF0000',lineWidth:2});

      const fingers = countFingers(lm);

      // 안정화: 0.3초 유지 시만 확정
      const now = performance.now();
      if(fingers === lastStable){
        lastTime = now;
      } else if(now - lastTime > 300){
        lastStable = fingers;
        lastTime = now;
        currentFingerCount = fingers;
        updateFingerSelection();
      }

      ctx.font="bold 36px Arial";
      ctx.fillStyle="#000";
      ctx.fillText(`손가락: ${fingers}`,10,40);
    }
    ctx.restore();
  }

  function countFingers(lm){
    let c=0;
    if(lm[4].x < lm[3].x) c++; // 엄지
    if(lm[8].y < lm[6].y) c++; // 검지
    if(lm[12].y < lm[10].y) c++; // 중지
    if(lm[16].y < lm[14].y) c++; // 약지
    if(lm[20].y < lm[18].y) c++; // 새끼
    return c;
  }
</script>
</body>
</html>

image.png