Skip to content

Instantly share code, notes, and snippets.

/blackjack.f08 Secret

Created July 22, 2016 20:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/b6dc29b0dbade7f5c46b8fd127a1b2b9 to your computer and use it in GitHub Desktop.
Save anonymous/b6dc29b0dbade7f5c46b8fd127a1b2b9 to your computer and use it in GitHub Desktop.
A humble Blackjack helper written in the greatest of programming languages
! A modern Fortran solution to the Coder Radio Blackjack Helper Project
! We're using Fortran because it's still cool, like the Beach Boys
! If you disagree, you're a communist
module blackjack_helper
implicit none
! A hand type representing the cards in play - passing 3 parameters around isn't hard, but derrived types are fun
type BlackjackHand
integer*1 :: player_card_1, player_card_2, dealer_card
end type BlackjackHand
! Parameters (compile-time constants) defining the possible actions to be suggested
! These are 1 byte integers, because it really affects the performance...
integer*1, parameter, private :: hit = 1, stand = 2, double = 3, d_stand = 4, split = 5, x_hit = 6, x_split = 7, x_stand = 8
integer*1, parameter, private :: ace = 11
! Next we break the lookup table into 3 different tables, like the United States is broken into 48 states,
! as this allows indexing them correspond to physical values of the cards when we take advantage of Fortran's array indexing
! Matrix mapping your card total and the dealer's card to a suggested action (general case)
! Note the order parameter to the reshape function - this tells the code to parse this matrix row first, because
! Fortran is naturally column major. Without this parameter, the resulting matrix would be the transpose of the desired one.
integer*1, dimension(9:17,2:11), parameter, private :: standard_key = reshape( &
[hit, double, double, double, double, hit, hit, hit, hit, hit, &
double, double, double, double, double, double, double, double, hit, hit, &
double, double, double, double, double, double, double, double, double, double, &
hit, hit, stand, stand, stand, hit, hit, hit, hit, hit, &
stand, stand, stand, stand, stand, hit, hit, hit, hit, hit, &
stand, stand, stand, stand, stand, hit, hit, hit, hit, hit, &
stand, stand, stand, stand, stand, hit, hit, hit, x_hit, x_hit, &
stand, stand, stand, stand, stand, hit, hit, x_hit, x_hit, x_hit, &
stand, stand, stand, stand, stand, stand, stand, stand, stand, x_stand], &
shape(standard_key), order = [2,1])
! Matrix mapping your card and the dealer's card to a suggested action when one of your cards is an ace
integer*1, dimension(2:7,2:11), parameter, private :: ace_key = reshape( &
[hit, hit, hit, double, double, hit, hit, hit, hit, hit, &
hit, hit, hit, double, double, hit, hit, hit, hit, hit, &
hit, hit, double, double, double, hit, hit, hit, hit, hit, &
hit, hit, double, double, double, hit, hit, hit, hit, hit, &
hit, double, double, double, double, hit, hit, hit, hit, hit, &
stand, d_stand, d_stand, d_stand, d_stand, stand, stand, hit, hit, hit], &
shape(ace_key), order = [2,1])
! Matrix mapping your cards and the dealer's card to a suggested action when you have doubles
integer*1, dimension(2:11,2:11), parameter, private :: double_key = reshape( &
[split, split, split, split, split, split, hit, hit, hit, hit, &
split, split, split, split, split, split, hit, hit, hit, hit, &
hit, hit, hit, split, split, hit, hit, hit, hit, hit, &
double, double, double, double, double, double, double, double, hit, hit, &
split, split, split, split, split, hit, hit, hit, hit, hit, &
split, split, split, split, split, split, hit, hit, hit, hit, &
split, split, split, split, split, split, split, split, split, x_split, &
split, split, split, split, split, stand, split, split, stand, stand, &
stand, stand, stand, stand, stand, stand, stand, stand, stand, stand, &
split, split, split, split, split, split, split, split, split, split], &
shape(double_key), order = [2,1])
contains
! Command line interface for you to input your cards and the dealer's card
function get_hand() result(hand)
type(BlackjackHand) :: hand
write (*,*) "Input cards using the value on the card. For face cards, input 10, for an ace, input 11"
write (*,*) "Your first card: "
read (*,*) hand%player_card_1
if (hand%player_card_1 < 2 .or. hand%player_card_1 > 11) then
stop "This card is invalid, please follow the instructions, they aren't that hard"
end if
write (*,*) "Your second card: "
read (*,*) hand%player_card_2
if (hand%player_card_2 < 2 .or. hand%player_card_2 > 11) then
stop "This card is invalid, please follow the instructions, they aren't that hard"
end if
write (*,*) "The dealer's card: "
read (*,*) hand%dealer_card
if (hand%dealer_card < 2 .or. hand%dealer_card > 11) then
stop "This card is invalid, please follow the instructions, they aren't that hard"
end if
end function get_hand
! Function to look up suggested play if your hand is not a special case
function lookup_general(hand_total, dealer_card) result(suggestion)
integer*1, intent(in) :: hand_total, dealer_card
integer*1 :: suggestion
select case(hand_total)
case(:8)
suggestion = hit
case(9:17)
suggestion = standard_key(hand_total, dealer_card)
case(18:)
suggestion = stand
end select
end function lookup_general
! Function to look up suggested play if you have a single ace in your hand
function lookup_ace(hand_card, dealer_card) result(suggestion)
integer*1, intent(in) :: hand_card, dealer_card
integer*1 :: suggestion
select case(hand_card)
case(:7)
suggestion = ace_key(hand_card, dealer_card)
case(8:)
suggestion = stand
end select
end function lookup_ace
! Function to look up a suggested play if you have doubles, although a real man would split regardless
function lookup_double(hand_card, dealer_card) result(suggestion)
integer*1, intent(in) :: hand_card, dealer_card
integer*1 :: suggestion
suggestion = double_key(hand_card, dealer_card)
end function lookup_double
! Determines if your hand is a special case or not, then returns the suggested play
function determine_play(hand) result(suggestion)
type(BlackjackHand), intent(in) :: hand
integer*1 :: suggestion
if (hand%player_card_1 == hand%player_card_2) then
suggestion = lookup_double(hand%player_card_1, hand%dealer_card)
else if (hand%player_card_1 == ace) then
suggestion = lookup_ace(hand%player_card_2, hand%dealer_card)
else if (hand%player_card_2 == ace) then
suggestion = lookup_ace(hand%player_card_1, hand%dealer_card)
else
suggestion = lookup_general(hand%player_card_1 + hand%player_card_2, hand%dealer_card)
end if
end function determine_play
! Writes the suggested play in a human readable format
subroutine write_play(suggestion)
integer*1, intent(in) :: suggestion
select case (suggestion)
case(1)
write(*,*) "The suggested play is to hit."
case(2)
write(*,*) "The suggested play is to stand."
case(3)
write(*,*) "Double down this play!"
case(4)
write(*,*) "Double down if possible, otherwise stand this time."
case(5)
write(*,*) "Split your hand!"
case(6)
write(*,*) "Surrender if you're allowed to, otherwise go for it and hit (good luck...)."
case(7)
write(*,*) "Surrender if you're allowed to, otherwise split your hand - I guess you can't make it worse."
case(8)
write(*,*) "Surrender if you're allowed to, otherwise stand - you're screwed, don't waste anybody's time."
case default
stop "The only way to win is not to play!"
end select
end subroutine write_play
! The main subroutine to help you with your blackjack play
subroutine play_blackjack()
call write_play(determine_play(get_hand()))
end subroutine play_blackjack
end module blackjack_helper
! The program. Just calls the single subroutine above. I'm not sure what more you were expecting.
program blackjack
use blackjack_helper
implicit none
call play_blackjack()
end program blackjack
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment