Уровень стека слишком глубокий в Ruby, пытающемся вытянуть случайную карту

Я получаю сообщение об ошибке "Уровень стека слишком глубокий" при выполнении кода ниже. Если выбранная случайная карта отсутствует, она выбирает другую случайную карту. Я полагаю, что мне следует как-то изменить код, но я не уверен, как это сделать. Какие-либо предложения?

   def hit 
    choice_of_card = rand($deck.length); #choose a random card out of the deck
    drawn_card = $deck[choice_of_card]; #draw that random card from the deck
    if drawn_card != 0 #if there is a card there 
     $deck[choice_of_card] = 0; #remove that card from the deck by making the space blank
     if drawn_card == 11 #if you draw an ace
      self.ace_count += 1;
     end 
     self.hand_value += drawn_card ;
    else hit; #if there is no card at that space then redraw (recursion)
    end
  end

2 ответа

Решение

Я думаю, можно с уверенностью сказать, что рекурсия вызывает ошибку. Мне кажется, вам не нужна рекурсия, вы можете просто зацикливаться, пока не получите draw_card!= 0, например,

drawn_card = 0
while drawn_card == 0
  choice_of_card = rand($deck.length); #choose a random card out of the deck
  drawn_card = $deck[choice_of_card]; #draw that random card from the deck
end

Как написано, глубина рекурсии "неограничена" на основе генератора случайных чисел. Рассмотрим, когда в колоде осталась только одна карта. Он будет продолжать выбирать случайные числа и повторяться до тех пор, пока не выберет одну оставшуюся карту; потенциально очень глубокий стек Если в колоде из 52 карт осталась одна карта, вероятность того, что она не выберется однажды, равна 51/52=98%. Чтобы получить 50% шансов на его выбор, вам потребуется около 35 итераций / рекурсий. Чтобы достичь вероятности выбора 99%, необходимо около 237 итераций: (1.0 - (51/52)^237)=99%,

Чтобы использовать эту конкретную реализацию, необходимо изменить ее на цикл (просто повторять, а не повторять). Тем не менее, это все еще не очень эффективно и может зацикливаться долгое время, прежде чем найти одну из немногих оставшихся карт. Альтернативой может быть удаление пробелов из колоды при удалении карт, и тогда всегда будет попадание. Или, может быть, использовать алгоритм тасования заранее, а затем просто последовательно итерировать их.

Другие вопросы по тегам