Blackjack

made by cuso



Intro

Buonpubblicazione mondo!

Dopo una settimana basata sul gioco d’azzardo non potevo di certo non parlarvi del mio script python per giocare a blackjack!

Se non capite di che settimana parlo vuol dire che non mi seguite su insta :/

Rimedia subito!

Ho infatti creato un nuovo format su insta, perciò ogni settimana vi saranno post di vario genere, tutti correlati.

Detto ciò, direi di iniziare con qust’analisi del codice :)

Disclaimer

Vi ricordo che potete scaricare il codice sorgente dal mio profilo github

guardiamo il codice

Al contrario di Scopa? oggi non saranno 500 le linee di codice, in quanto questo progetto è rimasto alla fase 0.9, vi dovrete accontentare di 282 linee stavolta….

Questo perchè manca tutto il sistema di puntate tipico del blackjack.

Come mai?

Sappiate che io ho iniziato Scopa? e questo progetto simultaneamente e quando mi sono accorto che fare tutto in object oriented avrebbe reso la stesura più chiara e veloce, ho deciso di evitare di creare 6 funzioni per le puntate. Funzioni che poi avrei dovuto riconvertire tutte nuovamente.

Quindi finchè non imparerò la obj-oriented di python, sia Scopa? che blackjack non saranno mai al loro massimo splendore….

Un po’ triste lo so, ma preferisco imparare prima typescript e swift, per due motivi: con typescript potrei dare molta più “vita” al sito, con swift potrei creare delle app per iOS (cosa che voglio fare da tempo) quindi comprenderete che python non sia il mio primo pensiero appena sveglio.

Dai, mo vi faccio vedere il codice, che sennò finiamo domani.

Import



import os
import random
import time

Come sempre ho messo degli import basici, giusto per rendere migliore la UX: os e time li useremo per “abbellire” il terminale, random giusto per mischiare il mazzo ahaha.

Variabili globali



mazzo=[
                "a♥", "a♦", "a♣", "a♠",
                "2♥", "2♦", "2♣", "2♠",
                "3♥", "3♦", "3♣", "3♠",
                "4♥", "4♦", "4♣", "4♠",
                "5♥", "5♦", "5♣", "5♠",
                "6♥", "6♦", "6♣", "6♠",
                "7♥", "7♦", "7♣", "7♠",
                "j♥", "j♦", "j♣", "j♠",
                "q♥", "q♦", "q♣", "q♠",
                "k♥", "k♦", "k♣", "k♠"
            ]

mazzo_reset=[
                "a♥", "a♦", "a♣", "a♠",
                "2♥", "2♦", "2♣", "2♠",
                "3♥", "3♦", "3♣", "3♠",
                "4♥", "4♦", "4♣", "4♠",
                "5♥", "5♦", "5♣", "5♠",
                "6♥", "6♦", "6♣", "6♠",
                "7♥", "7♦", "7♣", "7♠",
                "j♥", "j♦", "j♣", "j♠",
                "q♥", "q♦", "q♣", "q♠",
                "k♥", "k♦", "k♣", "k♠"
            ]

carte_valori={
                "a"     :   11,
                "2"     :   2,
                "3"     :   3,
                "4"     :   4,
                "5"     :   5,
                "6"     :   6,
                "7"     :   7,
                "8"     :   8,
                "9"     :   9,
                "j"     :   10,
                "q"     :   10,
                "k"     :   10
}

banco=[]

p1, p1_1 = [] , []

rad=false
splitted=false

Come potrete notare, abbiamo una situa molto simile a quella di Scopa? (infatti ho copiato le variabili da lì, lol)

Poi però ho aggiunto delle variabili consone al blackjack; mi riferisco a “rad” e “splitted”. Che sono essenzialmente il verificarsi del “raddoppio” e dello “split”

load()



def load():
    for i in range(6):
        os.system('cls' if os.name == 'nt' else 'clear')
        print("\n")
        print("caricamento")
        print("° "*(i+1))
        time.sleep(0.5)

    time.sleep(1)

    os.system('cls' if os.name == 'nt' else 'clear')
    print("\n\n")
    print(" _______  __                   __                                  __     ")  
    print("|       \|  \                 |  \                                |  \      ")
    print("| ▓▓▓▓▓▓▓\ ▓▓ ______   _______| ▓▓   __       __  ______   _______| ▓▓   __ ")
    print("| ▓▓__/ ▓▓ ▓▓|      \ /       \ ▓▓  /  \     |  \|      \ /       \ ▓▓  /  \ ")
    print("| ▓▓    ▓▓ ▓▓ \▓▓▓▓▓▓\  ▓▓▓▓▓▓▓ ▓▓_/  ▓▓      \▓▓ \▓▓▓▓▓▓\  ▓▓▓▓▓▓▓ ▓▓_/  ▓▓")
    print("| ▓▓▓▓▓▓▓\ ▓▓/      ▓▓ ▓▓     | ▓▓   ▓▓      |  \/      ▓▓ ▓▓     | ▓▓   ▓▓ ")
    print("| ▓▓__/ ▓▓ ▓▓  ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓\      | ▓▓  ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓\ ")
    print("| ▓▓    ▓▓ ▓▓\▓▓    ▓▓\▓▓     \ ▓▓  \▓▓\     | ▓▓\▓▓    ▓▓\▓▓     \ ▓▓  \▓▓\ ")
    print(" \▓▓▓▓▓▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓   \▓▓__   | ▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓   \▓▓")
    print("                                       |  \__/ ▓▓              ")             
    print("                                        \▓▓    ▓▓                    ")       
    print("                                         \▓▓▓▓▓▓           ")                 

    print("-------------------")
    print("╔═══╗    ╔═══╗╔═══╗")
    print("║╔═╗║    ║╔═╗║║╔═╗║")
    print("║║ ╚╝╔╗╔╗║╚══╗║║ ║║")
    print("║║ ╔╗║║║║╚══╗║║║ ║║")
    print("║╚═╝║║╚╝║║╚═╝║║╚═╝║")
    print("╚═══╝╚══╝╚═══╝╚═══╝")
    print("-------------------")

    os.system('cls' if os.name == 'nt' else 'clear')
        
    

Come prassi, sapete benissimo che mi piace aggiungere un loading screen per i miei progetti, ecco quello per blackjack :)

Situazione iniziale


def shuffle():
    random.shuffle(mazzo)

def distro():
    for i in range (2):
        p1.append(mazzo[0])
        del mazzo[0]
        banco.append(mazzo[0])
        del mazzo[0]

Due funzioni mega semplici per distruibuire le carte dopo averle mischiate, nulla di eclatante

splitCheck() e firstAction()



def splitcheck():
    if p1[0][0]==p1[1][0]:
        return(true)
    else:
        return(false)

def firstaction():
    if splitcheck():
        risp=0
        while not 1<=risp<=4:
            risp=int(input("1- stai\n2- chiama carta\n3- raddoppia\n4- split\n->"))
            if risp==1:
                tbanco()
                break
            elif risp==2:
                call(p1)
            elif risp==3:
                raddoppio()
            elif risp==4:
                split()
    else:
        risp=0
        while not 1<=risp<=4:
            risp=int(input("1- stai\n2- chiama carta\n3- raddoppia\n->"))
            if risp==1:
                tbanco()
                break
            elif risp==2:
                call(p1)
            elif risp==3:
                raddoppio()

splitcheck() è un controllo basilare che serve per mostrare anche l’opzione per splittare le carte.

D’altro canto, firsyAction() crea un menu da cui scegliere cosa fare una volta visionate le proprie carte. Da qui si potrà scegliere se “stare”, “chiamare”, “raddoppiare” (non molto utile vista la mancanza delle puntate ma lho inserito ugualmente…) o “splittare” (sempre se possibile).

Lo script poi richiamerà le funzioni apposite per continuare la partita.

ValueCheck()



def valuecheck(g):
    val=0
    acepresent=0
    for ele in g:
        val+=carte_valori[ele[0]]
        if ele[0]=="a":
            acepresent+=1
    if val >=22  and acepresent:
        while val>=22 and acepresent!=0:
            val-=10
            acepresent-=1
    return(val)

Questa funzione controlla il valore delle carte della propria mano, ed evita che si “sballi” dopo aver pescato un asso: carta che può assumere valore 1 o 11, in base alla situazione.

call()



def call(g):
    os.system('cls' if os.name == 'nt' else 'clear')
    g.append(mazzo[0])
    del mazzo[0]
    table(g)
    if valuecheck(g)==21 and splitted==false:
        print("blackjack!")
        tbanco()
    elif valuecheck(g)< 22 and splitted==false:
        risp=0
        while not 1<= risp <=2:
            risp=int(input("1-stai\n2-chiama carta\n->"))
            if risp==1:
                tbanco()
                break
            elif risp==2:
                call(g)
    elif valuecheck(g)==21 and splitted==true:
        print("blackjack!")
    elif  valuecheck(g)< 22 and splitted==true:
        risp=0
        while not 1<= risp <=2:
            risp=int(input("1-stai\n2-chiama carta\n->"))
            if risp==1:
                break
            elif risp==2:
                call(g)
    elif valuecheck(g)>=22 and splitted==true:
        print("hai sballato")
    elif valuecheck(g)>=22 and splitted==false:
        print("hai sballato")
        askforreplay()

Questa è la funzione principale del programma, infatti serve a “chiamare” carta e controllare, tramite valueCheck(), che non si sballi pescando.

Altro fattore importante è il notare se è avvenuto lo “split”, quindi dare le carte in maniera differente rispetto alla norma.

A questo punto potremo decidere se pescare ancora oppure “stare”; se pescando “sballeremo” il programma ce lo notificherà e ci chiederà se vogliamo giocare di nuovo tramite la funzione askForReplay(), che analizzeremo pià tardi.

raddoppio() e split()



def raddoppio():
    rad=true
    p1.append(mazzo[0])
    del mazzo[0]
    print(p1,"->" ,valuecheck(p1))
    if valuecheck(p1)==21:
        print("blackjack!")
        tbanco()
    elif valuecheck(p1)>21:
        print("hai sballato")
    else:
        tbanco()

def split():
    splitted=true
    p1_1.append(p1[1])
    del p1[1]
    p1.append(mazzo[0])
    del mazzo[0]
    p1_1.append(mazzo[0])
    del mazzo[0]
    print("\n\n ecco la prima parte dello split")
    call(p1)
    print("\n\n ecco la seconda parte dello split")
    call(p1_1)

Prima ho annunciato la possiilità di “raddoppiare” o “splittare”, queste sono le due funzioni che permettono ciò.

La prima ci darà una carta, controllerà che non abbiamo sballato e tramite tBanco() passerà il turno.

La seconda crea un’altra mano, come vi fosse un secondo giocatore; esattamente come quando “splittiamo” in una partita normale :)

tBanco()



def tbanco():
    os.system('cls' if os.name == 'nt' else 'clear')
    print("tocca al banco!")
    print("le carte del banco: ", banco, "-->",valuecheck(banco),end="\n\n")
    print("la tua mano: ", p1, "-->",valuecheck(p1), end="\n\n")
    while valuecheck(banco)<=16:
        banco.append(mazzo[0])
        print("il banco pesca...")
        del mazzo[0]
        print("le carte del banco: ", banco, "-->",valuecheck(banco),end="\n\n")
    if valuecheck(banco)==21:
        print("blackjack!")
    if valuecheck(banco)< 22:
        wincheck()
    else:
        print("il banco sballa, hai vinto")
        askforreplay()

Ma come fa una macchina a giocare e prendere decisioni al posto di un croupié?

Non vi stupirà scoprire che il banchiere al casinò debba seguire delle regole specifiche, onde evitare perdite inutili. Mi è bastato sfruttare queste regole per costruire una funzione che decida quando il banco debba “chiamare” carta e quando debba evitarlo.

Dopo quei controlli, vi sarà la chiamata di winCheck(), che ci permetterà di scoprire chi ha vinto questa mano.

winCheck()



def wincheck():
    if splitted:
        if valuecheck(p1)==valuecheck(banco) and valuecheck(p1_1)==valuecheck(banco):
            print("parità")
            askforreplay()
        elif valuecheck(p1)< valuecheck(banco) and valuecheck(p1_1)< valuecheck(banco):
            print("vince il banco")
            askforreplay()
        else:
            print("hai vinto")
            askforreplay()
    else:
        if valuecheck(p1)==valuecheck(banco):
            print("parità")
            askforreplay()
        elif valuecheck(p1)< valuecheck(banco):
            print("vince il banco")
            askforreplay()
        else:
            print("hai vinto")
            askforreplay()

Ecco a voi il “termine” del mio script, infatti le funzioni che vedremo dopo saranno solo “comfort organizzativi”.

Per quanto riguarda winCheck(), notiamo che non faccia altro che sfruttare valueCheck() per controllare chi abbia la mano più alta ed assegnare la vittoria (anche in caso di split).

In ogni caso, da bravo ludopatico, ho inserito la possibilità di rigiocare tramite la funzoone “askForReplay()”, giusto per evitare di dover far ripartire lo script ogni volta (pigrizia over 9000).

askForReplay()



def askforreplay():
    risp=""
    while true:
        risp=input("vuoi rigiocare? [y/n] \n")
        if risp=="y":
            print("perfetto, ricominciamo!")
            time.sleep(1.8)
            os.system('cls' if os.name == 'nt' else 'clear')
            play()
        elif risp=="n":
            print("va bene, rigioca quando vuoi")
        else:
            print("davvero non riesci scrivere 'y' o 'n'? \nfiga zio ma ti svegli??")

Ecco come ho risolto il problema di far partire lo scritp al termine della partita.

Una semplice richiesta a cui rispondere “y” o “n”, con una piccola citazione in caso di indecisione ;)

Funzioni “comfort”



def table(n):
    print("le carte del banco: ", banco[0], "*", end="\n\n")
    print("la tua mano: ", n, "-->",valuecheck(p1), end="\n\n")

def play():
    shuffle()
    distro()
    table(p1)
    firstaction()

def main():
    load()
    play()

if __name__ == "__main__":
    main()

Queste sono semplici linee di codice che servono per organizzare le funzioni antecedentemente create.

table() non è altro che una coppia di print per mostrare le carte del banco e quelle in mano.

Cose che ero troppo pigro per scrivere ogni volta, creare una funzione apposita mi ha salvato da molti errori di battitura :)

play() organizza le fasi di gioco: mischiare il mazzo, distribuire, mostrare le carte e scelgiere cosa fare.

main() serve per richiamare il loading screen e poi avviare la partita.

L’if finale è giusto per convenzione, nulla di realmente essenziale ;)

Conclusioni

Prometto che una volta imparata la programmazione a oggetti sistemerò Scopa? e questo script. Ma prima devo pensare alla V2.0 di Crucisberla.

Vi ricordo che trovate tutti i miei progetti di coding sul mio profilo github.