IT/React

[React] 가중치 랜덤 알고리즘(Weighted Random Picker)을 적용한 확률형 뽑기(룰렛) 만들기

카제인나트륨. 2023. 6. 16. 12:43
728x90
반응형
개요

가중치 랜덤 알고리즘(Weighted Random Picker)을 사용하여 확률형 룰렛을 만들어 봅시다.

데이터는 아래의 데이터로 예시를 들어보겠습니다.

 

가중치 랜덤 알고리즘 관련 내용은 아래 링크에서 설명이 잘 되어있으니 참고해주세요.

 

가중치 랜덤 알고리즘 - 누적확률값 방식

이번에 알아볼 알고리즘은 가중치가 주어진 경우의 랜덤 선택 알고리즘이다. 여러가지 방법이 있겠지만 가...

blog.naver.com

 

결과물

 

 

 

라이브러리 설치
$ npm install react-custom-roulette
or
$ yarn add react-custom-roulette

 

 

 

소스

먼저 다운받은 룰렛을 import해주고

룰렛 데이터와 회전여부와 당첨 인덱스를 추출할 state를 선언해줍니다.

import { Wheel } from 'react-custom-roulette' // 룰렛 import
import { useState } from 'react';

function App() {
  //룰렛 데이터
  const data = [
    { 
    	option: 'Apple Vision Pro'
    	, style: { backgroundColor: 'gray', textColor: 'white' }
        , percentage : 3 
    },
    { 
    	option: 'LG TV'
    	, style: { backgroundColor: 'red', textColor: 'white'  }
        , percentage : 7 
     },
    { 
    	option: 'SAMSUNG 에어컨'
        , style: { backgroundColor: 'blue', textColor: 'white'  }
        , percentage : 10
     },
    { 
    	option: '꽝' 
        , style: { backgroundColor: 'white', textColor: 'red'  }
        , percentage : 80 
    },
  ]

  //룰렛이 회전 애니메이션을 시작
  const [mustSpin, setMustSpin] = useState(false); 
  const [prizeNumber, setPrizeNumber] = useState(0);//당첨 인덱스

  return (
    <div className="App">
    
    </div>
  );
}

 

 

함수 추가

룰렛 애니메이션이 끝날 때의 이벤트 함수와 실행시킬 함수를 추가해줍니다.

그리고 가중치 랜덤 알고리즘(Weighted Random Picker)은 애니메이션을 실행 시킬 때 적용하도록 소스를 추가해줍니다.

// 룰렛 애니메이션을 실행시킬 함수
const handleSpinClick = () => {
    if (!mustSpin) {
      // 가중치 랜덤 알고리즘(Weighted Random Picker) 적용
      // 1. 랜덤 기준점 설정
      const pivot   = Math.floor((Math.random() * 99) +1);
      let   stack   = 0; // 가중치

      let percentage = data.map((row,idx)=>{  { return row.percentage } });

      let newPrizeNumber = null; //당첨 인덱스

      percentage.some((row,idx)=>{
        //2. 가중치 누적
        stack += row;

        // 3. 누적 가중치 값이 기준점 이상이면 종료
        if(pivot <= stack){
          newPrizeNumber  = idx;
          return true;
        }

      }) 
      // 당첨 인덱스를 가리킴
      setPrizeNumber(newPrizeNumber);
      setMustSpin(true);
    }
}

// 룰렛 애니메이션이 멈출 때 실행되는 함수
const StopSpinning = () => {
    setMustSpin(false);
    alert(data[prizeNumber].option+'이 당첨되셨습니다');
}

 

마무리로 wheel 태그를 추가해줍니다.

return (
    <div className="App">
     <Wheel
        spinDuration={0.2} // spin속도
        //디폴트 위치 랜덤으로
        startingOptionIndex={Math.floor(Math.random() * data.length)} 
        mustStartSpinning={mustSpin}
        prizeNumber={prizeNumber}
        data={data}
        onStopSpinning={StopSpinning}
      />
      <button onClick={handleSpinClick}>SPIN</button>
      <div>{prizeNumber}</div>
    </div>
  );

 

 

최종 소스

import { Wheel } from 'react-custom-roulette'
import { useState } from 'react';

function App() {
  //데이터
  const data = [
    { option: 'Apple Vision Pro', style: { backgroundColor: 'gray', textColor: 'white' }, percentage : 3 },
    { option: 'LG TV', style: { backgroundColor: 'red', textColor: 'white'  }, percentage : 7 },
    { option: 'SAMSUNG 에어컨', style: { backgroundColor: 'blue', textColor: 'white'  }, percentage : 10 },
    { option: '꽝' , style: { backgroundColor: 'white', textColor: 'red'  }, percentage : 80 },
  ]

  
  const [mustSpin, setMustSpin] = useState(false);  //룰렛이 회전 애니메이션을 시작
  const [prizeNumber, setPrizeNumber] = useState(0);//당첨 인덱스

  const handleSpinClick = () => {
    if (!mustSpin) {
      // 1. 랜덤 기준점 설정
      const pivot   = Math.floor((Math.random() * 99) +1);
      let   stack   = 0; // 가중치

      let percentage = data.map((row,idx)=>{  { return row.percentage } });

      let newPrizeNumber = null; //당첨 인덱스

      percentage.some((row,idx)=>{
        //2. 가중치 누적
        stack += row;

        // 3. 누적 가중치 값이 기준점 이상이면 종료
        if(pivot <= stack){
          newPrizeNumber  = idx;
          return true;
        }

      }) 
      setPrizeNumber(newPrizeNumber);
      setMustSpin(true);
    }
  }

  const StopSpinning = () => {
    setMustSpin(false);
    alert(data[prizeNumber].option+'이 당첨되셨습니다');
  }

  return (
    <div className="App">
     <Wheel
        spinDuration={0.2} // spin속도
        startingOptionIndex={Math.floor(Math.random() * data.length)} 
        mustStartSpinning={mustSpin}
        prizeNumber={prizeNumber}
        data={data}
        onStopSpinning={StopSpinning}
      />
      <button onClick={handleSpinClick}>SPIN</button>
      <div>{prizeNumber}</div>
    </div>
  );
}

 

 

룰렛에 관한 추가적인 기능을 참고하고 싶다면 아래 링크를 참고해주세요.

 

GitHub - effectussoftware/react-custom-roulette: Repository for the react-custom-roulette library

Repository for the react-custom-roulette library. Contribute to effectussoftware/react-custom-roulette development by creating an account on GitHub.

github.com

 

728x90
반응형