UNPKG

steemkr

Version:

스팀잇 기반 CLI 툴 : CLI(Command Line Interface) Tool for steemit.

434 lines (377 loc) 11 kB
const {init:arrInit} = require('./warray'); let fn = {}; // 프랑스식(한국) 스>다>하>클, 미국은 스>하>다>클 // see : http://koreabettingnews.com/casino/%ED%8F%AC%EC%BB%A4-%EC%A1%B1%EB%B3%B4%EC%99%80-%EC%9A%A9%EC%96%B4-%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90/ /* * 카드 타입 정보 */ fn.CARD_TYPE = { CLOVER : 0, HEART : 1, DIAMOND : 2, SPADE : 3 }; /* * 카드 족보 */ fn.JOKBO = { NO_PAIR : 0, ONE_PAIR : 1, TWO_PAIR : 2, TRIPPLE : 3, STRAIGHT : 4, BACK_STRAIGHT : 5, MOUNTAIN : 6, FLUSH : 7, FULL_HOUSE : 8, FOUR_CARD : 9, STRAIGHT_FLASH : 10, BACK_STRAIGHT_FLASH : 11, ROYAL_STRAIGHT_FLASH : 12, } const CARD_TYPE = {... fn.CARD_TYPE}; const JOKBO = {... fn.JOKBO}; const JOKBO_ENG = [ 'NO_PAIR', 'ONE_PAIR', 'TWO_PAIR', 'TRIPPLE', 'STRAIGHT', 'BACK_STRAIGHT', 'MOUNTAIN', 'FLUSH', 'FULL_HOUSE', 'FOUR_CARD', 'STRAIGHT_FLASH', 'BACK_STRAIGHT_FLASH', 'ROYAL_STRAIGHT_FLASH', ]; const CARD_T = ['♣️','♥️','♦️','♠️']; const CARD_N = [2,3,4,5,6,7,8,9,10,'J','Q','K','A']; const BLACKJACK = 21; const CARD_NUM_START = 2; const CARD_NUM_A = 14; let fnIsBackStraight = (clone)=>{ // 계산을 손쉽게 하기 위하여 복제카드는 정렬 한다(숫자기준으로) fn.sortCards(clone, false); for(let i=0;i<clone.length;i++){ if(i<4){ if(clone[i]._number != i+CARD_NUM_START){ return false; } }else{ if(clone[i]._number != CARD_NUM_A){ return false; } } } return true; } let fnIsStraight = (clone)=>{ // 계산을 손쉽게 하기 위하여 복제카드는 정렬 한다(숫자기준으로) fn.sortCards(clone, false); // 스트레이트 return clone.every((el,idx,arr)=>{ if(idx>0){ // 숫자기준 정렬 후 작업이 이뤄져야 됨 if(el._number==arr[idx-1]._number+1){ return true; }else{ return false; } } return true; }); } let fnToString = (ori, lastAt) =>{ let cards = []; if(!lastAt){ lastAt = ori.length; } for(let i=ori.length-lastAt;i<ori.length;i++){ cards.push(`${ori[i].type} ${ori[i].number}`); } return cards.join(','); } let fnNumbers = (clone) =>{ let nums = arrInit(13, 0); for(let c of clone){ let now = nums[c._number-2] + 1; nums[c._number-2]=now; } let notempty = []; for(let n of nums){ if(n!=0){ notempty.push(n); } } return notempty; } let fnMaxSameNumber = (clone) =>{ let nums = arrInit(13, 0); let max = 0; for(let c of clone){ let now = nums[c._number-2] + 1; nums[c._number-2]=now; max = Math.max(now, max); } return max; } let fnMaxSameType = (clone) =>{ let types = arrInit(4, 0); let max = 0; for(let c of clone){ let now = types[c._type] + 1; types[c._type]=now; max = Math.max(now, max); } return max; } let fnMaxNum = (clone) =>{ let max = 0; for(let c of clone){ max = Math.max(c._number, max); } return max; } let fnMaxType = (clone) =>{ let max = 0; for(let c of clone){ max = Math.max(c._type, max); } return max; } fn.sortFilterWhenSame = (a, b)=>{ // 족보가 동일한 항목에 대해 확인 let gn1 = a.groupNumbers; let gn2 = b.groupNumbers; // 예외상황 if(!gn1 || !gn2 || gn1.length!=gn2.length){ // 말도 안되는 경우임 throw Error(`is not same length ( ${gn1.length}, ${gn2.length} )`); } // 숫자 쌍으로 먼저 검증 if([JOKBO.TWO_PAIR,JOKBO.FULL_HOUSE].includes(a.jokbo)){ for(let i=0;i<gn1.length;i++){ if(gn1[i].num!=gn2[i].num){ // 숫자 return gn2[i].num - gn1[i].num; } } } // 숫자 > 타입 // 카운트는 항시 동일 for(let i=0;i<gn1.length;i++){ if(gn1[i].num!=gn2[i].num){ // 숫자 return gn2[i].num - gn1[i].num; }else{ // 타입, 카드는 4장이 최고임, 4장 비교는 무의미 let t0 = gn2[i].types[0] - gn1[i].types[0]; if(t0!=0){ return t0; } if(gn1[i].length>1){ let t1 = gn2[i].types[1] - gn1[i].types[1]; if(t1!=0){ return t1; } } if(gn1[i].length>2){ let t2 = gn2[i].types[2] - gn1[i].types[2]; if(t2!=0){ return t2; } } } } // 완전 동일한 카드 목록임, idx가 낮은걸로 구분하자 -_-; 먼저 카드 뽑은 사람임 return 0; } let fnGroupNumbers = (clone) =>{ let ocByNum = []; let nums = arrInit(13, 0); for(let c of clone){ nums[c._number-2] = nums[c._number-2] + 1; } for(let i=0;i<nums.length;i++){ if(nums[i]!=0){ ocByNum.push({num:i+2, cnt:nums[i]}); } } // 나온횟수, 큰숫자 순서로 정렬 ocByNum.sort((a,b)=>{ if(b.cnt==a.cnt){ return b.num-a.num; }else{ return b.cnt-a.cnt; } }); // 카드무늬 정보 추가 for(let oc of ocByNum){ oc.types = []; for(let c of clone){ if(c._number==oc.num){ oc.types.push(c._type); } } // 타입이 큰 숫자가 앞으로 오도록 처리 oc.types.sort((a,b)=>b-a); } return ocByNum; } fn.jokboCards = (cards, name, idx) =>{ /* [ '0', { type: '♣️', _type: 0, number: 10, _number: 10 } ] [ '1', { type: '♦️', _type: 2, number: 10, _number: 10 } ] [ '2', { type: '♥️', _type: 1, number: 'J', _number: 11 } ] [ '3', { type: '♥️', _type: 1, number: 7, _number: 7 } ] [ '4', { type: '♣️', _type: 0, number: 'Q', _number: 12 } ] */ // 로얄스트레이트 플러쉬 : 5장이 같은 무늬 10, J, Q, K, A 무늬는 상관없이 통일된 무늬만 있으면 된다. 숫자는 10,J,Q,K,A가 고정으로 있어여 한다. // 백 스트레이트 플러쉬 : 5장이 같은 무늬 A,2,3,4,5 무늬는 상관없이 통일된 무늬만 있으면 된다. 숫자는 A,2,3,4,5 고정이어야 한다. // 스트레이트 플러쉬 : 5장이 같은 무늬 연속되는 숫자 5장이 되야 한다. 무늬는 상관없이 통일된 무늬만 있으면 되고 시작하는 숫자 상관없이 연달아 있으면 된다. // 포카드 : 같은 숫자 4개 – 숫자 4개가 필요한대 각 무늬별로 1개씩 같은 숫자를 얻어야 한다. 로플티 같은 경우는 뽑을 일이 희박하지만 포카드는 확률이 있어 실질적인 가장 강력한 패라고 볼수 있다. // 풀하우스 : 같은숫자 3개 + 2개 – 트리플 (같은숫자3개) +원페어 (같은숫자 2개) // 플러쉬 : 5장 같은 무늬 – 5장 무늬만 같으면 나온다 이상태에서 스트레이트가 나오면 스티플, 로티플, 백스트가 나오는 축이라고 볼수 있다. 스트레이트가 없으면 일반적인 플러쉬라고 보면 된다. // 마운틴 : 10, J,Q,K,A – 무늬가 같으면 상위 족보로 간다 // 백스트레이트 : A,2,3,4,5 – 무늬가 같으면 상위 족보로 간다 // 스트레이트 : 연속 되는 숫자 5장 – 무늬가 같으면 상위 족보로 간다 // 트리플 : 같은 숫자 3개 // 투페어 : 같은숫자 2개 +2개 // 원페어 : 같은 숫자 2개 // 노페어 : 5장 모두 어디에도 해당 되지 않는 패 // 일부가 .. some // 모두가 .. every // let clone = cards.slice(0); let clone = JSON.parse( JSON.stringify( cards ) ); let isFlush = fnMaxSameType(clone)==5; let isBackStraight = fnIsBackStraight(clone); let isStraight = fnIsStraight(clone); let maxSameNumber = fnMaxSameNumber(clone); let maxSameType = fnMaxSameType(clone); let maxNum = fnMaxNum(clone); let maxType = fnMaxType(clone); let groupNumbers = fnGroupNumbers(clone); let isMountain = isStraight && maxNum==14; let isRoyalStraightFlash = isMountain && isFlush; let isBackStraightFlash = isBackStraight && isFlush; let isStraightFlash = isStraight && isFlush; let numbers = fnNumbers(clone); let isFourCard = numbers.includes(4); // 4,1 let isTripple = numbers.includes(3); // 3,2 or 3,1,1 let isFullHouse = isTripple && numbers.length==2; // 3,2 let isTwoPair = numbers.length==3; // 2,2,1 let isOnePair = numbers.length==4; // 2,1,1,1 let isNoPair = !isStraight&&!isBackStraight&&numbers.length==5; // 1,1,1,1,1 let jokbo = JOKBO.NO_PAIR; jokbo = Math.max(isRoyalStraightFlash?JOKBO.ROYAL_STRAIGHT_FLASH:0,jokbo); jokbo = Math.max(isBackStraightFlash?JOKBO.BACK_STRAIGHT_FLASH:0,jokbo); jokbo = Math.max(isStraightFlash?JOKBO.STRAIGHT_FLASH:0,jokbo); jokbo = Math.max(isFourCard?JOKBO.FOUR_CARD:0,jokbo); jokbo = Math.max(isFullHouse?JOKBO.FULL_HOUSE:0,jokbo); jokbo = Math.max(isFlush?JOKBO.FLUSH:0,jokbo); jokbo = Math.max(isMountain?JOKBO.MOUNTAIN:0,jokbo); jokbo = Math.max(isBackStraight?JOKBO.BACK_STRAIGHT:0,jokbo); jokbo = Math.max(isStraight?JOKBO.STRAIGHT:0,jokbo); jokbo = Math.max(isTripple?JOKBO.TRIPPLE:0,jokbo); jokbo = Math.max(isTwoPair?JOKBO.TWO_PAIR:0,jokbo); jokbo = Math.max(isOnePair?JOKBO.ONE_PAIR:0,jokbo); let output = { maxSameNumber:maxSameNumber, maxSameType:maxSameType, maxNum:maxNum, maxType:maxType, groupNumbers:groupNumbers, jokbo:jokbo, jokboe:JOKBO_ENG[jokbo], ori : cards, valuec : fnToString(clone), value : fnToString(cards), value2 : fnToString(cards, 2), name : name, idx : idx, }; // 동률 비교하는 방법 // 카드 랭크, 동일카드 제거(홀덤이기 때문에) 후 => maxType, maxNum 비교 return output; } /* * 카드에서 num 만큼의 카드를 뽑아낸다 * 입력 받은 카드는 자동적으로 num 만큼 숫자가 감소 * @param cards 카드목록 * @param num 넘겨줄 카드 수 * @return 넘겨진 카드 목록 */ fn.drawCards = (cards, num) => { let out = []; for(let i=0;i<num;i++){ out.push(cards.shift()); } return out; }; /* * 신규 카드 댁을(52장) 생성한다 * @return 52장의 카드 */ fn.makeDeck = () =>{ let cards = []; for(var i=0;i<CARD_T.length;i++){ for(var j=0;j<CARD_N.length;j++){ cards.push({ type : CARD_T[i], _type : i, number : CARD_N[j], _number : j+2, value : `${CARD_T[i]} ${CARD_N[j]}`, }); } } return cards; } /* * 입력받은 카드를 섞어준다 * @param cards 카드 목록 */ fn.shuffleCards = (cards) =>{ for(let i=0;i<cards.length;i++){ let rnd = Math.floor(Math.random()*cards.length); cards.splice(rnd, 0, cards.shift()); } } /* * 카드 댁의 정보 기준으로 정렬한다 * @param cards 카드 목록 * @param isType 타입 우선으로 정렬할지 여부 (아니라면 숫자로 정렬) * @param isAsc 오름차순 여부 * @return 정렬된 카드 목록 */ fn.sortCards = (cards, isType=true, isAsc=true) =>{ return cards.sort((c1,c2)=>{ let s1 = isAsc?c1._type-c2._type:c2._type-c1._type; let s2 = isAsc?c1._number-c2._number:c2._number-c1._number; if(isType){ if(s1==0){ return s2; }else{ return s1; } }else{ if(s2==0){ return s1; }else{ return s2; } } }); } /* * 입력받은 카트 타입으로 카드 덱을 필터링 한다 * @param cards 카드 목록 * @param cardTypes 카드 타입 배열(CARD_TYPE.SPADE ...) * @return 필터링된 카드목록 */ fn.filterCardsByType = (cards, cardTypes=[]) =>{ return cards.filter(c=>cardTypes.includes(c._type)); } module.exports = fn;