Уровень стека слишком глубокий в 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%
,
Чтобы использовать эту конкретную реализацию, необходимо изменить ее на цикл (просто повторять, а не повторять). Тем не менее, это все еще не очень эффективно и может зацикливаться долгое время, прежде чем найти одну из немногих оставшихся карт. Альтернативой может быть удаление пробелов из колоды при удалении карт, и тогда всегда будет попадание. Или, может быть, использовать алгоритм тасования заранее, а затем просто последовательно итерировать их.