javascript - 卡牌游戏的数组对象过滤和不同序列

标签 javascript

游戏规则:

这副牌包含 54*2 = 108 张卡片

注意:游戏中有两种类型的 clown 。

  • 普通 clown
  • 动态生成的 clown ,可以是任何牌值。

提交卡片时,正确提交将被视为

  1. 共有 4 组,总共 13 张牌(已处理)
  2. 只有 1 组可以包含 4 张卡片。休息,每人 3 张牌(已处理)
  3. 1 个组必须具有纯序列示例:Ace、2、3 或 J、Q、K、Ace 或 3、4、5(相同花色)

  4. 另一个组必须有一个序列。它可以是纯的或不纯的示例(不纯):Ace,2,Joker,4 或 5,6,Joker,8

  5. 其余 2 组可以包含序列(纯或不纯),或者可以包含不同花色的相同值(value)牌(有或没有 clown )

示例:2(黑桃)、2(梅花)、 clown 、2(红桃)或 3(梅花)、3(红桃)、3(黑桃)

这是迄今为止已经做出的尝试。

var joker = 3; // dynamic joker card value

function getSummary(cards){
	const isJoker = c => c.value===joker || c.suit ==="joker";
	const getSortVal = c=> isJoker(c) ? 100 : c.value;
	cards.sort((c1,c2)=> getSortVal(c1)-getSortVal(c2)); //sort cards by their value  
  let jokerCount = 0,jokersUsed =0, res;  
  for(let i = cards.length -1; i >= 0 ; i--) //start from end to handle jokers first (note this is assuming they will also have the larger value of 20)
  {  		
      if(isJoker(cards[i])){
      	jokerCount++; //handle jokers separately
       // console.log("used joker");
			} else	{
      	let {suit,value:val} = cards[i]; //destructure suit and value properties into variables
      	if(res===undefined){ //first non joker card -> init values
        	res = {uniqueSuit: suit, startOfSequence: val}; 
          if(jokerCount) res.jokersUsed =true;          
        }
        else {
        	if(suit !== res.uniqueSuit) //check if there are more suits
        		delete res.uniqueSuit; //no unique suit -> remove the property (alternative: set the prop to 'none')

          if(res.startOfSequence && --res.startOfSequence != val){ //check if the sequence is intact          	
          	if(val === 1 && i === 0 && res.startOfSequence ===10) //Ace
            	res.startOfSequence++; //Ace is used as 14
          	else {
            	let gap = res.startOfSequence - val;              
              if(gap > 0 &&jokerCount >= gap){ //if enough jokers remaining, use them (sequence still intact)
                jokerCount-=gap;
                jokersUsed+=gap;
                res.startOfSequence=val;
              }
              else
                delete res.startOfSequence; //no sequence -> remove property from res
            }
          }
       }
     }
  }
  
  if(res === undefined){
  	  //only jokers (is this possible?) -> create sequence or matching values
    	res={};
      //loop through suits or do what's needed to create best score
      return res;
  }
  
  if(res.startOfSequence) //Sequence found => all cards handled => return result
  	return res;
  
  if(jokersUsed) 		//jokers were used for sequence, but sequence was not complete
     	jokerCount += jokersUsed; //reclaim jokers
      
      const addSameValue = (suit,val)=>{ //helper function to add cards of same value to collection
		if(!res.sameValues)res.sameValues = {};    
    res.sameValues[val] = (res.sameValues[val] | 1) +1; //offset always 1 because adding is done from prev. value
  };
  
  //search for same values
  let prev, cnt =cards.length - jokerCount;
  for(let i=0 ; i < cnt ; i++){
  		let val = cards[i].value;
      if(prev == val)
      	addSameValue(cards[i].suit,val);
      else
      	prev = val;
  }

  if(jokerCount){
    	//use for highest value or add to existing sequences?
      //for example, add to highest value: (might want to check for unused suits)
      addSameValue('joker', cards[cards.length-jokerCount].value);    
  }  
	

  return JSON.stringify(res);
}



var arr4 = [{"value":2,"suit":"hearts"},{"value":5,"suit":"hearts"},{"value":3,"suit":"hearts"},{"value":4,"suit":"hearts"}];
var arr5 = [{"value":5,"suit":"hearts"},{"value":5,"suit":"diams"},{"value":3,"suit":"diams"},{"value":5,"suit":"spades"}];
var arr6 = [{"value":1,"suit":"hearts"},{"value":2,"suit":"hearts"},{"value":4,"suit":"hearts"},{"value":3,"suit":"hearts"}];
var arr7 = [{"value":4,"suit":"diams"},{"value":4,"suit":"hearts"},{"value":4,"suit":"hearts"},{"value":20,"suit":"joker"}];
 


for(let arr of [arr4,arr5,arr6,arr7])	
  console.log(getSummary(arr)); //test output

它根据卡组的排列方式返回对象并添加属性。

正确的分组是

纯序列(3或4张牌) - 纯序列或不纯序列(3或4张牌) - 纯序列或不纯序列或相同值卡(3或4张牌) - 纯序列或不纯序列或相同储值卡(3 或 4 张卡)

不一定要按这个顺序。只需寻找他们的存在即可。

纯序列不能包含任何类型的 clown 。

但是,上面的代码几乎没有问题。

对于序列卡 - 示例:[2(黑桃),3(黑桃),4(黑桃)]

  1. 对于arr4,它表示jokersUsed: true将3(动态设置为joker)视为joker,即使数组已经是纯序列。稍后在识别哪个是纯序列或不纯序列时会产生问题。如果 3 有不同的花色或者不是序列的一部分,则 3 可以被视为 clown 。

因此,对于像 [ 2(黑桃), 5(黑桃), 3 (黑桃), 4(黑桃) ] 这样的牌,即使 3 是一个,它也应该始终被视为纯序列 clown 动态生成。这里将 3 视为 clown 并添加 jokerUsed 属性。

如果它是 [ 2(黑桃), 5(黑桃), 3 (梅花), 4(黑桃)][ 7(黑桃),它可能会被认为是 clown , 8(黑桃),3(黑桃或梅花或其他),10(黑桃)]

对于相同值(value)的牌 - 示例:[2(黑桃),2(梅花),2(红心)]

  • 在代码中,它只寻找相同值(value)的牌,无论它们的花色如何。这意味着,所有的牌都应该是不同花色的。

  • 对于相同值(value)的卡片搜索,如果有 3 张相同值(value)的卡片,则计数将变为 4(而不是 3),而对于 4 张相同值(value)的卡片,计数将变为 6(而不是 4)。因此,计数应等于同值卡的数量。

  • 此处不考虑 clown (正常和动态)。 [ 2(黑桃)、2(梅花)、 clown (静态或动态)、2(直径) ]。我们可以将 clown 视为2(hearts),但这并没有发生。

  • 如何在我的代码中实现上述 4 个条件?希望我说清楚了,否则我会再次解释。

    这是一个fiddle如果你想从事..

    最佳答案

    好的,here's what I have 。它可能并不完全完整(多个组的聚合不在这里),但它使大量检查到位,并且可能为您提供更好的结构想法。它还期望没有多余的卡片:不要为 3 张卡片组提交 4 张卡片。

    主要涉及将规则分解为他们想要的特定结构,为每个结构构建功能。然后我们将其包装在规则聚合函数 getSummary() 中。

    // Ace spades: {"value":1, suit:"spades"}
    // King diamonds: {"value":12, suit:"diams"}
    // Joker: {"suit":"joker"}
    
    // In addition to the regular jokers, cards with a certain value can also behave as jokers.
    // Purity of the group is only removed if a card in the group was used as a joker
    var jokerValue;
    
    // check that values match and suits are unique
    function isSameValue(cards){
      var suits = ["clubs","hearts","spades","diams"];
      var jokers = [];
      var remainder = [];
      cards.forEach(function(card){
        (card.suit === "joker" ? jokers : remainder).push(card);
      });
      var pure = jokers.length === 0;
      var value;
      var matched = remainder.every(function(card){
        if(value) {
          if(value != card.value) {
            return false;
          }
          var suit = suits.indexOf(card.suit);
          if(suit < 0) {
            return false;
          }
          suits.splice(suit,1);
          return true;
        }
        value = card.value;
        return true;
      });
      // if the non-wildcards matched, just assume any wildcards are also matches,
      // otherwise, pull the fake jokers and try again
      if(matched) {
        return {isPure: pure, isSameValue: matched};
      }
    
      // move the fake jokers to the joker pile
      remainder = remainder.filter(function(card){
        if(card.value == jokerValue) {
          jokers.push(card);
          return false;
        }
            return true;
      });
      // reset 
      suits = ["clubs","hearts","spades","diams"];
      pure = jokers.length === 0;
      value = undefined;
      matched = remainder.every(function(card){
        if(value) {
          if(value != card.value) {
            return false;
          }
          var suit = suits.indexOf(card.suit);
          if(suit < 0) {
            return false;
          }
          suits.splice(suit,1);
          return true;
        }
        value = card.value;
        return true;
      });
    
      return {isPure: pure, isSameValue: matched};
    }
    
    // check that suits match; values are unchecked
    function isSameSuit(cards){
      var jokers = [];
      var remainder = [];
      cards.forEach(function(card){
        (card.suit === "joker" ? jokers : remainder).push(card);
      });
      var pure = jokers.length === 0;
      var suit;
      var sameSuit = remainder.every(function(card){
        if(!suit){
          suit = card.suit;
          return true;
        }
        return card.suit == suit;
      });
    
        if(sameSuit) {
        return {isPure: pure, isSameSuit: sameSuit};
      }
    
      // pull the fake jokers and try again
      remainder = remainder.filter(function(card){
        if(card.value == jokerValue) {
          jokers.push(card);
          return false;
        }
      });
    
      pure = jokers.length === 0;
      suit = undefined;
      sameSuit = remainder.every(function(card){
        if(!suit){
          suit = card.suit;
          return true;
        }
        return card.suit == suit;
      });
    
      return {isPure: pure, isSameSuit: sameSuit};
    }
    
    // check for sequence; suits must match
    function isSequence(cards){
      var sameSuit = isSameSuit(cards);
      if(!sameSuit.isSameSuit) {
        return false;
      }
    
      var jokers = [];
      var sequence = cards.filter(function(card){
        if(card.suit === "joker") {
          jokers.push(card);
          return false;
        }
        return true;
      });
      var pure = jokers.length === 0;
    
      // Sort the non-jokers
      sequence = sequence.sort(function(a, b){
        return a.value - b.value;
      });
    
      // skip this step is isSameSuit() reported !isPure because we know we had to 
      // use jokers so we can assume fake jokers are okay to use
      if(pure && sameSuit.isPure){
        // find a sequence
        // rotate through each card to start and count through them, filling in with available jokers as necessary
        for(var i = 0; i < sequence.length; i++){
          var jokerCount = jokers.length;
          var lastValue = sequence[0].value;
          var fail = false;
          for(var j = 1; j < sequence.length; j++){
            if(lastValue + 1 == sequence[j].value) {
              ++lastValue;
              continue;
            }
            if(lastValue == 12 && sequence[j].value == 1) {
              lastValue = 1;
              continue;
            }
            if(jokerCount > 0) {
              jokerCount--;
              j--;
              lastValue++;
              if(lastValue > 12) {
                lastValue = 1;
              }
              continue;
            }
            fail = true;
            break;
          }
          // Did we make it through a complete sequence?
          if(!fail){
            return {isPure: pure, isSequence: !fail };
          }
          // move bottom card to top and try again
          sequence.unshift(sequence.pop());
        }
      }
    
      var sequence = sequence.filter(function(card){
        if(card.value == jokerValue) {
          jokers.push(card);
          return false;
        }
        return true;
      });
      pure = jokers.length === 0;
    
      // already sorted from earlier; try again
      for(var i = 0; i < sequence.length; i++){
        var jokerCount = jokers.length;
        var lastValue = sequence[0].value;
        var fail = false;
        for(var j = 1; j < sequence.length; j++){
          if(lastValue + 1 == sequence[j].value) {
            ++lastValue;
            continue;
          }
          if(lastValue == 12 && sequence[j].value == 1) {
            lastValue = 1;
            continue;
          }
          if(jokerCount > 0) {
            jokerCount--;
            j--;
            lastValue++;
            if(lastValue > 12) {
              lastValue = 1;
            }
            continue;
          }
          fail = true;
          break;
        }
        if(!fail) {
          return {isPure: pure, isSequence: !fail};
        }
      }
    
      return {isPure: undefined, isSequence: false};
    }
    
    function getSummary(cards){
      if(cards.length != 3 && cards.length != 4) {
        // invalid number of cards, return undefined
        return;
      }
    
      var long = cards.length == 4;
      var sameValue = isSameValue(cards);
      var sequence = isSequence(cards);
      var pure = (sameValue.isSameValue && sameValue.isPure) || (sequence.isSequence && sequence.isPure);
    
      return JSON.stringify({
        "isLong": long, 
        "isPure": pure, 
        "isSameValue": sameValue.isSameValue, 
        "isSequence": sequence.isSequence
      });
    }
    
    function toString(cards) {
        var results = [];
      cards.forEach(function(card){
        if(card.suit === "joker") {
          results.push("JK");
        }
        else {
          var value;
          switch (card.value) {
            case  1: value = "A"; break;
            case 10: value = "J"; break;
            case 11: value = "Q"; break;
            case 12: value = "K"; break;
            default:
              value = card.value;
              break;
          }
          results.push(value+card.suit.charAt(0));
        }
      });
      return results.join(' ');
    }
    
    jokerValue = 3;
    for(var arr of [
      [{"value":5,"suit":"hearts"},{"value":5,"suit":"diams"},{"value":5,"suit":"clubs"},{"value":5,"suit":"spades"}],
      [{"value":2,"suit":"hearts"},{"suit":"joker"},{"value":3,"suit":"hearts"},{"value":4,"suit":"hearts"}],
      [{"value":5,"suit":"hearts"},{"value":5,"suit":"diams"},{"value":3,"suit":"diams"},{"value":5,"suit":"spades"}],
      [{"value":5,"suit":"hearts"},{"value":5,"suit":"diams"},{"value":5,"suit":"spades"}],
      [{"value":5,"suit":"hearts"},{"value":5,"suit":"diams"},{"value":10,"suit":"spades"}],
      [{"value":1,"suit":"hearts"},{"value":3,"suit":"diams"},{"value":2,"suit":"hearts"}],
      [{"value":1,"suit":"hearts"},{"value":3,"suit":"hearts"},{"value":3,"suit":"diams"}]
    ]) {
      console.log(toString(arr) + " " + getSummary(arr)); //test output
    }
    

    关于javascript - 卡牌游戏的数组对象过滤和不同序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40958221/

    相关文章:

    javascript - 2 个带有响应滚动的固定图像的 div

    html 中的 JavaScript 问题

    javascript - 在 ExtJS 中加载 hasMany 数据

    javascript - 在 VueJS 中将一个输入框单向绑定(bind)到另一个输入框

    javascript - googleapis npm 模块和 webpack bundle 错误

    javascript - 在我的例子中如何将参数传递到函数中

    javascript - TypeError : $(. ..).live 不是 MVC 中的函数

    javascript - 如何仅替换方括号中的键重合?

    javascript - 如何使用 ajax 将文本输入字段附加到表单而不丢失表单上的用户输入?

    javascript - 为什么empty() 不适用于搜索栏中的输入?