흑염소처럼

카드 셔플 만들어보기 본문

JavaScript

카드 셔플 만들어보기

미니리틀타이니 2020. 9. 14. 15:45

업무 시 카드게임 개발이라는 업무가 있었습니다.

데이터를 받아 올 시 당첨 노출되지 않도록 어떤 식으로 DOM을 구성할지

카드 갯수를 고정이 아니고 유동적으로 대응할 수 있는지 테스트 (flex로 가변적이게 animation 사용 가능한지)

align-items: flex-start; justify-content: flex-start;는 animation이 적용이 안되는 요소로 확인이 되었습니다.

등등을 고려한 기록입니다.

카드 뒤집는 모션

svg width css3

https://css-tricks.com/svg-animation-on-css-transforms/

https://www.smashingmagazine.com/2020/02/magic-flip-cards-common-sizing-problem/

카드 셔플

https://medium.com/@pakastin/javascript-playing-cards-part-1-ranks-and-values-a9c2368aedbd

https://medium.com/@pakastin/javascript-playing-cards-part-2-graphics-cd65d331ad00

https://medium.com/@pakastin/javascript-playing-cards-part-3-animations-7099f9f5dea4

뒤집는 모션 따라하기

suits : 카드 모양 4개 (❤️,♦️,♠️,♣️)

values : 숫자 1 - 13

총카드의 개수 : 4 * 13 = 52

const cards = new Array(52);
for (let i = 0; i < cards.length; i++) {
  cards[i] = i;
}

const getRank = (i) => i % 13;
const getValue = (i) => getRank(i) + 1;
const getSuit = (i) => i / 13 | 0; // floor

cards.map(getRank) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
cards.map(getValue) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
cards.map(getSuit) // [0, 0, ..., 1, 1, ..., 2, 2, ..., 3, 3, ...]

| Bitwise OR

Bitwise ORing은 어떤 숫자라도 number | 0 이면 number를 출력한다.

var test = 5.99999 | 0;
console.log(test); // 5

Untitled

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_OR

논리 연산자

논리 연산자

Jokers

조커를 추가한다면!!! 조커는 흑, 백 두장이 있다.

인덱스 2개를 추가를 한다.

const cards = new Array(54);

for(let i = 0; i < cards.length; i++){
    cards[i] = i % 54;
}

console.log(cards.length) //54

Combine

위에서 만든 properies를 위해 general purpose 함수를 만들어 봅시다.

const getProperties = (i) => {
    const joker = i > 51;
    const rank = joker ? -1 : i % 13;
    const value = rank + 1;
    const suit = joker ? -1 : i / 13 | 0;

    return { rank,value,suit,joker};
};

Human-readable ranks and suits

rank와 suit를 어떻게 하면 우리가 이해할 수 있을까요??

배열의 이름을 만들어서 인덱스로써 rank/suits를 써 봅시다.

const ranks = 'A 2 3 4 5 6 7 8 9 10 J Q K'.split(' ');
const suits = '♠︎ ♥︎ ♣︎ ♦︎'.split(' ');

OK 우리는 ranks[rank]와 suits[suit]를 call할 수 있습니다. 그리고 사람이 읽을 수 있는 string으로 출력할 수 있습니다.

color

suit's remainder of two

0 ← false

1 ← ture

const color = suit % 2 ? 'red' : 'black';

Shuffling the deck(deck of ˈcards)

어떻게 카드를 섞을까요??? 당신은 sort를 사용할 수 있습니다.

sort

sort()

메서드는 배열의 요소를 적절한 위체에 정렬한 후 그 배열을 반환합니다. 정렬은 stable sort가 아닐 수 있습니다. 기본 정렬 순서는 문자열의 유니코드 코드 포인트를 따릅니다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

const months = ['March','Jan','Feb','Dec'];
months.sort();
console.log(months);//["Dec", "Feb", "Jan", "March"]

const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);//[1, 100000, 21, 30, 4]

sort를 사용하여 카드를 섞어보면?!!

cards.sort(() => {
    return Math.random() < 0.5;
};)

sort는 기본 정렬 순서가 있기 때문에 랜덤 한 값을 얻기 힘들다.

Fisher-Yates shuffle를 사용하여 랜덤 한 값을 가져오자.

이 부분 이해 안 감 일단 이런 게 랜덤 값 뽑는 함수다라고 이해만 할 뿐

const shuffle = (cards) => {
  for (let i = 0; i < cards.length; i++) {
    const rnd = Math.random() * i | 0;
    const tmp = cards[i];
    cards[i] = cards[rnd];
    cards[rnd] = tmp;
  }
  return cards;
};

Fisher–Yates starts from the end of an array. For every card, it’ll choose itself or another card before the iterating card to switch places with. So you’ll get equal amount of shuffles per card. That’s the key for a perfect randomness.

JSON.stringfy()

JSON.stringfy()메서드는 JavasScript값이나 객체를 JSON문자열로 변환합니다. 선택적으로, replacer를 함수로 전달할 경우 변환 전 값을 변형할 수 있고, 배열로 전달할 경우 지정한 속성만 결과에 포함합니다.

console.log(JSON.stringify({ x: 5, y: 6 }));
// expected output: "{"x":5,"y":6}"

console.log(JSON.stringify([new Number(3), new String('false'), new Boolean(false)]));
// expected output: "[3,"false",false]"

console.log(JSON.stringify({ x: [10, undefined, function(){}, Symbol('')] }));
// expected output: "{"x":[10,null,null,null]}"

console.log(JSON.stringify(new Date(2006, 0, 2, 15, 4, 5)));
// expected output: ""2006-01-02T15:04:05.000Z""

https://codepen.io/minimanymuch/full/QWywaom

step2 _ create card ui

document.createElement(tagName[,options]);

매개변수

tagName : 생성할 요소의 유형을 가리키는 문자열

options

is 속성 하나를 가진 ElementCreationOptions 객체. 속성의 값은 customElements.define()

을 사용해 정의한 사용자 정의 요소입니다.

반환 값

새로운 Element

<!DOCTYPE html>
<html>
<head>
  <title>||Working with elements||</title>
</head>
<body>
  <div id="div1">위의 텍스트는 동적으로 추가했습니다.</div>
</body>
</html>
document.body.onload = addElement;

function addElement () { 
  // create a new div element 
  var newDiv = document.createElement("div"); 
  // and give it some content 
  var newContent = document.createTextNode("환영합니다!"); 
  // add the text node to the newly created div
  newDiv.appendChild(newContent);  

  // add the newly created element and its content into the DOM 
  var currentDiv = document.getElementById("div1"); 
  document.body.insertBefore(newDiv, currentDiv); 
}

foreach 반복문

forEach반복문은 오직 Array 객체에서만 사용 가능한 메서드입니다.(ES6부터는 Map, Set 등에서도 지원됩니다.) 배열의 요소들을 반복하여 작업을 수행할 수 있습니다. foreach 구문의 인자로 callback함수를 등록할 수 있고, 배열의 각 요소들이 반복될 때 이 callback함수가 호출됩니다. callback 함수에서 배열 요소의 인덱스와 값에 접근할 수 있습니다.

var items = ['item1','item2','item3'];

items.forEach(function(item){
    console.log(item);
});

for in 반복문

for in 반복문은 객체의 속성들을 반복하여 작업을 수행할 수 있습니다. 모든 객체에서 사용이 가능합니다. for in 구문은 객체의 key값에 접근할 수 있지만, value값에 접근하는 방법은 제공하지 않습니다.

객체의 모든 내장 메서드를 비롯해 각종 프로퍼티 같은 비 열거형 속성은 반복되지 않습니다.

var obj = {
    a : 1,
    b : 2,
    c : 3
};
for (var prop in obj){
    console.log(prop,obj[prop]); // a 1,b 2,c 3
}

element.setAttribute(name,value);

매개변수

name

DOMString값 설정되는 속성의 이름을 지정. setAttribute()HTML 문서의 HTML 요소에서 호출될 때 속성 이름이 자동으로 모든 소문자로 변환됩니다.

value

DOMString값을 포함하는 속성에 할당합니다. 지정된 문자열이 아닌 값은 자동으로 문자열로 변환됩니다.

<button>Hello World</button>

var b = document.querySelector("button"); 

b.setAttribute("name", "helloButton");
b.setAttribute("disabled", "");
  • 위의 첫 번째 호출 setAttribute()name속성 값을 "helloButton"으로 변경하는 것을 보여줍니다.

  • 과 같은 부울 속성 값을 설정하려면 disabled실제 값에 관계없이

    임의의 값을 지정할 수 있습니다. 빈 문자열 또는 속성 이름이 권장되는 값입니다. 중요한 것은 속성이

    존재한다면 true 값으로 간주된다는 것입니다. 속성이 없으면 값이 false입니다.

https://codepen.io/minimanymuch/pen/OJMvRKv

step3_make card shuffle 애니메이션 만들기

해당 코드에서 사용하는 변수 선언 법

//Json 객체의 원소들을 개별 변수에 분할하여 할당하기
const json = {first:"hello",second:"world",third:"react"};

//원하는 원소만 개별 변수로 추출/
//단, json객체의 key와 변수 이름이 동일해야 함

const {first,second} = json;

console.log(first);//hello

console.log(second);//world

카드 뿌리는 애니메이션

https://codepen.io/jaehee/pen/RRperd

javascript-foreach-add-addeventlistener-on-all-buttons

https://stackoverflow.com/questions/27946703/javascript-foreach-add-addeventlistener-on-all-buttons

https://jsdev.kr/t/document-queryselectorall-addeventlistener/5170

document.getElementById는 단일 DOM 객체를 가져오지만, document.querySelectorAll은 NodeCollection을 가져오기 때문입니다. 또한 NodeCollection은 숫자 인덱스를 가지고 있고 length property를 가지고 있지만, 배열은 아니므로 forEach등의 Iterator Function을 호출할 수 없습니다.

아래와 같이 해 보세요.

for(var i = 0; i<selectall.length; i++) {selectall[i].addEventListener(…);}

최종 완성

https://codepen.io/minimanymuch/pen/qBbxyQw?editors=1111

내가 만든 것

https://codepen.io/minimanymuch/pen/yLeqXOd

Comments