-
-
Save anonymous/b6dc29b0dbade7f5c46b8fd127a1b2b9 to your computer and use it in GitHub Desktop.
A humble Blackjack helper written in the greatest of programming languages
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
! 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