# Copyright 2006 Michael Lewis # Distributed under the terms of the GNU General Public License v2 require "PlayerHand" class RecursiveStats def initialize @indent = [" "] @cards = [2,3,4,5,6,7,8,9,10,10,10,10,11] @testHands = [[3,5],[3,6],[3,7],[3,8],[3,9],[3,10],[4,10],[5,10],[6,10],[7,10],[8,10],[9,10],[10,3,7],[11,10,10], #13 [11,2],[11,3],[11,4],[11,5],[11,6],[11,7],[11,8],[11,9],[11,10], #22 [2,2],[3,3],[4,4],[5,5],[6,6],[7,7],[8,8],[9,9],[10,10],[11,11]] #32 @moveTable = Array.new 10.times { @moveTable << Array.new } @moveTable.each { |i| i.fill( nil, 0, 27 ) } end def testHand( i ) PlayerHand.new.replace( @testHands[i] ) end def hand2n( hand ) total = hand.hand_value my_hand = 0 return nil if hand.bust? if hand.length == 2 and hand[0] == hand[1] c = hand[0] my_hand = 21 + c elsif hand.soft? my_hand = total + 1 else if total <= 8 my_hand = 0 else my_hand = total - 8 end end my_hand end #Set splitting rules here def canSplit( hand ) return false if hand.splits >= 4 return false if hand.length !=2 return false if hand[0] != hand[1] return true end #Set doubling rules here def canDouble( hand ) return hand.length == 2 end #Set hitting rules here def canHit( hand ) return !hand.locked? end def possibleMoves( hand ) moves = ["s"] if hand.hand_value < 21 moves << "h" if canHit hand moves << "l" if canSplit hand # moves << "d" if canDouble hand end return moves end def dealerMove( dealerHand, playerHand ) if playerHand.bust? or dealerHand.blackjack? return -1.0 end if dealerHand.hand_value < 17 sum = 0.0 @cards.each do |card| sum += dealerMove( Hand.new.copy( dealerHand ) << card, playerHand ) / @cards.length end return sum else return 1.5 if playerHand.blackjack? return 2.0 if playerHand.doubled? and ( playerHand.hand_value > dealerHand.hand_value or dealerHand.bust? ) return 1.0 if playerHand.hand_value > dealerHand.hand_value or dealerHand.bust? return 0.0 if playerHand.hand_value == dealerHand.hand_value return -1.0 end end def testMove( dealerCard, playerHand, testMove = nil ) suma = [] handN = hand2n playerHand # puts "\n" + handN.to_s + '==' + playerHand.hand_value.to_s mmove = @moveTable[dealerCard][handN][0] if !playerHand.bust? # if we already have this value filled in we can return it # otherwise we have to figure if !playerHand.bust? and !@moveTable[dealerCard][handN].nil? and !@moveTable[dealerCard][handN][1].nil? return @moveTable[dealerCard][handN] else pMoves = testMove.nil? ? possibleMoves( playerHand ) : [ testMove ] pMoves.each do |move| sum = 0.0 if move == "s" sum += dealerMove( Hand.new << ( dealerCard + 2 ), playerHand ) else @cards.each do |card| ph = PlayerHand.new ph.copy playerHand ph.add_card card ( sum += testMove( dealerCard, ph )[1] / @cards.length ) if move == "h" if move == "l" h1 = PlayerHand.new h1.copy( ph ) h1.split h1[1] = card sum += 2 * testMove( dealerCard, h1 )[1] / @cards.length end end end suma << sum end return [ mmove, suma.max ] end end def testPosition( dealerCard, playerHandN ) moveVals = [] pHand = testHand playerHandN possibleMoves( pHand ).each do |move| @moveTable[dealerCard][playerHandN] = [move, nil] moveVals << testMove( dealerCard, pHand, move ) end fin = moveVals.collect { |a| a.reverse }.max.reverse fin[0] = "d" if fin[0] == "h" and fin[1] > 0.0 @moveTable[dealerCard][playerHandN] = fin fin end def ahhTest (23..32).collect.reverse.each do |y| print y.to_s + " " (0..9).each do |x| print testPosition( x, y )[0] + " " end puts end (3..13).collect.reverse.each do |y| print y.to_s + " " (0..9).each do |x| print testPosition( x, y )[0] + " " end puts end puts "--" (14..22).collect.reverse.each do |y| print y.to_s + " " (0..9).each do |x| print testPosition( x, y )[0] + " " end puts end puts "--" (0..2).collect.reverse.each do |y| print y.to_s + " " (0..9).each do |x| print testPosition( x, y )[0] + " " end puts end end end