private IEnumerator PlayCardRoutine(int cardSlotindex, RulePassingState[] rulePassingStates)
    {
        float   startDate     = Time.timeSinceLevelLoad;
        float   timer         = 0;
        Vector3 startPosition = this.IntermediateCardAnchor.transform.position;
        Vector3 endPosition   = this.playSlots[cardSlotindex].transform.position;

        endPosition.z   = this.translationLayerAnchor.position.z;
        startPosition.z = endPosition.z;
        this.nextPlayedCard.transform.position = startPosition;

        if (this.playSlots[cardSlotindex].Card != null)
        {
            Vector3 previousCardPosition = this.playSlots[cardSlotindex].Card.transform.position;
            previousCardPosition.z += 1;
            this.playSlots[cardSlotindex].Card.transform.position = previousCardPosition;
        }

        Tween cardTransitionTween = this.nextPlayedCard.transform.DOMove(endPosition, this.playCardAnimDuration).SetEase(this.playCardCurve).OnComplete(() => this.nextPlayedCard.transform.position = this.playSlots[cardSlotindex].transform.position);

        this.nextPlayedCard.transform.DOScale(new Vector3(2, 2, 1), this.playCardAnimDuration).SetEase(playCardScaleCurve);

        yield return(cardTransitionTween.WaitForCompletion());

        for (int ruleIndex = 0; ruleIndex < this.playRuleSlots.Length; ++ruleIndex)
        {
            RulePassingState passingState = rulePassingStates[ruleIndex];
            if (passingState == RulePassingState.None)
            {
                continue;
            }

            if (passingState == RulePassingState.Success)
            {
                this.playRuleSlots[ruleIndex].FlashGreen();
                this.playRuleSlots[ruleIndex].PlayCheckMark();
            }
            else
            {
                this.playRuleSlots[ruleIndex].FlashRed();
                this.playRuleSlots[ruleIndex].PlayCrossMark();
            }

            yield return(new WaitForSeconds(.5f));
        }

        timer = 0;
        float translationDuration = .5f;

        this.showRulesTween = this.RuleHandTransform.DOMove(this.VisibleRuleHandPosition.position, translationDuration);
        this.showRulesTween.SetEase(Ease.OutCubic);

        startDate = Time.timeSinceLevelLoad;
        Vector3 handStartPosition = this.HiddenHandPosition.position;
        Vector3 handEndPosition   = this.VisibleHandPosition.position;

        this.leftPanel.FadeIn();

        while (timer < translationDuration)
        {
            timer = Time.timeSinceLevelLoad - startDate;

            float handProgression = this.HandAnimationCurve.Evaluate(timer / translationDuration);
            this.HandTransform.transform.position = handStartPosition + (handEndPosition - handStartPosition) * handProgression;

            yield return(null);
        }

        this.HandTransform.transform.position = handEndPosition;
        this.RefreshPlayerStatus();

        if (this.playSlots[cardSlotindex].Card != null)
        {
            this.DeleteCard(this.playSlots[cardSlotindex].Card);
        }

        Color noBorder = Color.black;

        noBorder.a = 0f;
        Color backColor = Color.white;

        backColor.a = .5f;

        this.nextPlayedCard.FadeBorderToColor(noBorder, backColor, .5f);

        this.playSlots[cardSlotindex].Card = this.nextPlayedCard;
        this.playSlots[cardSlotindex].Card.transform.position = this.playSlots[cardSlotindex].transform.position;
        this.nextPlayedCard = null;

        if (this.lifeCount < 1)
        {
            this.currentState = State.Lost;
            StartCoroutine(this.EndGameRoutine());
            yield break;
        }

        float ruleAnimationDuration = .5f;
        Rule  ruleToRemove          = this.ruleToPhaseOut;

        if (ruleToRemove != null)
        {
            Tween ruleExitTween = ruleToRemove.transform.DOMove(this.RuleExitAnchor.position, ruleAnimationDuration);
            ruleExitTween.SetEase(Ease.InCubic);
            ruleExitTween.onComplete += () =>
            {
                this.DeleteRule(ruleToRemove);
            };
        }

        for (int index = 0; index < this.playRuleSlots.Length; ++index)
        {
            if (this.playRuleSlots[index].Rule == null)
            {
                continue;
            }

            this.playRuleSlots[index].Rule.transform.DOLocalMove(Vector3.zero, ruleAnimationDuration);
        }

        this.currentState = State.CardRuleChoice;
    }
    private void PlayCard(int slotIndex)
    {
        if (this.nextPlayedCard == null)
        {
            return;
        }

        int numberOfFailures = 0;

        RulePassingState[] rulePassingStates = new RulePassingState[this.playRuleSlots.Length];

        for (int ruleIndex = 0; ruleIndex < this.playRuleSlots.Length; ++ruleIndex)
        {
            RuleDefinition ruleDefinition = this.playRuleSlots[ruleIndex].Rule?.Data;
            if (ruleDefinition == null)
            {
                rulePassingStates[ruleIndex] = RulePassingState.None;
                continue;
            }

            int  x         = slotIndex % 3;
            int  y         = slotIndex / 3;
            bool isAllowed = ruleDefinition.IsSlotAllowed(ref this.nextPlayedCard.Data, this.playSlots, x, y);
            rulePassingStates[ruleIndex] = isAllowed ? RulePassingState.Success : RulePassingState.Failed;
            if (!isAllowed)
            {
                numberOfFailures++;
            }
            else
            {
                this.TransferOneCombinedRule();
            }
        }

        if (numberOfFailures > 0)
        {
            this.lifeCount--;
        }
        else
        {
            this.GivePoints(slotIndex, this.nextPlayedCard);
        }

        if (this.playRuleSlots[this.playRuleSlots.Length - 1].Rule != null)
        {
            this.ruleToPhaseOut = this.playRuleSlots[this.playRuleSlots.Length - 1].Rule;
        }

        for (int index = this.playRuleSlots.Length - 1; index > 0; --index)
        {
            if (this.playRuleSlots[index - 1].Rule == null)
            {
                continue;
            }

            this.playRuleSlots[index].Rule = this.playRuleSlots[index - 1].Rule;
            this.playRuleSlots[index].Rule.transform.SetParent(this.playRuleSlots[index].transform);
        }

        this.RefreshPlayerStatus();
        this.currentState = State.TransitionToPlacement;
        StartCoroutine(this.PlayCardRoutine(slotIndex, rulePassingStates));
    }