Codificami un po 'di golf


15

Se non hai mai giocato a golf prima, ecco un elenco di termini relativi al golf che uso in questa domanda

  • Tiro , chiamato anche colpo : ogni volta che la palla viene colpita, questo è un tiro.
  • Buca : un campo da golf è diviso in buche, in cui l'obiettivo è quello di colpire una palla da una posizione designata all'altra nel minor numero di colpi possibile.
  • Tee : dove inizi una buca.
  • Spilla o bandiera : dove finisci un buco
  • Fairway , Rough , Water e Green : caratteristiche su un campo da golf che influenzano il modo in cui si gioca la palla nella vita reale. (In che modo influiscono sul programma è specificato di seguito)

Domani vado a giocare a golf e, a volte, ho difficoltà a capire quale club usare per colpire un certo cantiere. Così ho deciso di scrivere i miei club e i loro cortili per colpo.

Primo presupposto: tutte le buche sono dovute a nord delle loro scatole a T.

Tutti questi yardage misurano le possibilità per quanto viaggia a nord la palla. La palla percorrerà una distanza intera casuale tra i limiti specificati per ogni club (incluso).

Come maestro golfista, nessuno dei miei tiri ha uno spostamento orizzontale. Ciò significa che tutti i miei scatti vanno in linea retta direttamente sulla bandiera.

Club #     Club        Yardage
1          Driver      300-330
2          3-Wood      270-299
3          5-Wood      240-269
4          3-Iron      220-239
5          4-Iron      200-219
6          5-Iron      180-199
7          6-Iron      160-179
8          7-Iron      140-159
9          8-Iron      120-139
10         9-Iron      100-119
11         P-Wedge     80-99
12         S-Wedge     50-79
13         L-Wedge     0-49
14         Putter      (only on green)

Come persona che ama la programmazione, decido che voglio modellare una partita di golf e fissare un obiettivo per quanto voglio fare domani. Tuttavia, come ogni programmatore dilettante, dopo dieci minuti, ho rinunciato e ho chiesto aiuto su Stack Overflow (scherzando). Ecco alcuni altri dati sul corso.

Secondo presupposto: geografia del foro

  • Tutti i numeri che descrivono le distanze sul percorso sono numeri interi.

  • Ogni buco è una linea retta. La distanza in linea retta tra ciascun foro e il perno (l'estremità del foro) è Length.

  • I fairway sono segmenti con lunghezza definita da flen. Il valore elencato per flenè la gamma di iarde a nord dal tee dove si trova il fairway.

  • Gli ostacoli d'acqua sono segmenti con lunghezza definita da wlen, che ha le stesse proprietà di flen.

  • Il verde ha una lunghezza definita da glen.

  • Tutte le parti del corso che non sono fairway, acqua o green sono ruvide.

Ecco una tabella che descrive ogni buca del percorso.

Hole #     Length      flen               wlen        glen   
1          401         54-390                         391-425
2          171                            1-165       166-179
3          438         41-392             393-420     421-445
4          553         30-281,354-549     282-353     550-589
5          389         48-372                         373-404
6          133                                        125-138
7          496         37-413             414-484     484-502
8          415         50-391                         392-420
9          320         23-258             259-303     304-327

Come giocare a golf (per questo programma)

  • Mirare sempre esattamente alla bandiera.
  • Colpisci la palla il più vicino possibile al perno, cercando di mantenere la palla sul fairway o (preferibilmente) sul green.
  • Quando si lancia un colpo in acqua, il colpo successivo deve essere giocato dallo stesso punto del colpo che è andato in acqua.
  • Una volta che la palla atterra sul green, solo il putter può essere usato. Se la palla atterra rigorosamente a più di 5 iarde dal perno, allora metto due volte. Altrimenti, ho messo una volta.
  • È possibile colpire un colpo oltre il perno.

punteggio

Il mio punteggio in una buca è il numero di colpi che faccio, più un colpo per ogni volta che atterro in mare duro o in acqua.

Il programma

Ok, c'erano molte regole, ora parliamo del programma.

Il corso dovrebbe essere definito come sopra nel programma , perché il corso è costante. Giocatori di golf diversi, tuttavia, hanno distanze diverse per ogni tiro, quindi l'ingresso a STDIN dovrebbe essere un insieme di intervalli di yardage, disposti in ordine crescente di numero di mazza e separati da virgole (senza spazi bianchi).

L'output dovrebbe essere il modo in cui "gioco" il round di golf. Il numero di mantenimento deve essere specificato all'inizio di ogni riga come Hole #:dove si #trova il foro corrente. Ogni colpo che non è un putt è nella forma seguente: {club,distance of shot,condition of ball,distance to pin}. I dettagli dello scatto devono essere separati da virgole ma senza spazi bianchi nell'ordine sopra. I colpi stessi dovrebbero essere scritti in ordine di come sono giocati e separati da uno spazio. Una volta che la pallina si ferma sul green, il programma dovrebbe stampare il numero di put che prendo, nel formato {# putts}. Alla fine di ogni riga, il numero di scatti che ho fatto sul buco dovrebbe essere separato dagli altri scatti da uno spazio e stampato come(#). Ogni buca dovrebbe essere sulla propria linea e scritta in ordine. Infine, sull'ultima (decima) riga del programma, il numero totale di colpi per il round dovrebbe essere stampato come Total: # shots.

Non esiste una "strategia" definita che il tuo programma deve prendere. Puoi scrivere un programma con qualsiasi strategia tu voglia. Le strategie di esempio includono massimizzare la probabilità percentuale di atterrare sul green e massimizzare la distanza di ogni tiro fino a raggiungere la buca.

INGRESSO CAMPIONE

300-330,270-299,240-269,220-239,200-219,180-199,160-179,140-159,120-139,100-119,80-99,50-79,0-49

USCITA DEL CAMPIONE

Hole 1: {Driver,324,Fairway,77} {S-Wedge,70,Green,7} {Two putts} (4)
Hole 2: {6-Iron,162,Water,171} {6-Iron,168,Green,3} {One putt} (4)
Hole 3: {Driver,301,Fairway,137} {8-Iron,131,Green,6} {Two putts} (4)
Hole 4: {3-Wood,288,Water,553} {3-Wood,276,Fairway,277} {3-Wood,291,Green,14} {Two putts} (6)
Hole 5: {Driver,322,Fairway,67} {S-Wedge,62} {One putt} (3)
Hole 6: {8-Iron,120,Rough,18} {L-Wedge,10,Green,8} {Two putts} (5)
Hole 7: {Driver,325,Fairway,171] {6-Iron,170,Green,1} {One putt} (3)
Hole 8: {Driver,306,Fairway,109} {9-Iron,100,Green,9} {Two putts} (4)
Hole 9: {Driver,308,Green,12} {Two putts} (3)
Total: 36 shots

Devo ammettere che questa è una sfida piuttosto ambiziosa per un primo post su CG.SE, quindi sarei felice di parlare di come migliorare questa sfida nei commenti. Grazie per l'aiuto.


2
Ti sarei davvero grato se, per noi non golfisti, non avessi usato tutti i termini del golf (ad esempio "tee box" e "spostamento orizzontale"). :)
kirbyfan64sos,

Aggiungerò un elenco di termini relativi al golf. Quando si gioca a golf, la palla non sempre va dritta, quindi ho appena detto che la palla va sempre direttamente verso la buca e quindi non ha alcun movimento orizzontale.
Arcturus,

Supponiamo che il perno sia a 300 metri e che ci sia un fairway da 0~299iarde, verde da 300~315iarde e acqua da 316~330iarde. Quale club verrà scelto? Cosa succede se l'acqua viene sostituita da una di massima?
lirtosiast,

Idealmente, il programma dovrebbe essere in grado di elaborare una propria strategia.
Arturo,

Cosa intendi con "strategia ottimale"? Ridurre al minimo il numero medio di colpi? Per quanto riguarda il criterio vincente andrei con il code-golf.
lirtosiast,

Risposte:


9

Python 2.7: 43 40,5 colpi in media

Questo è il mio primo post qui quindi abbiate pazienza.

Dato che il poster stava pensando di trattare questo come una sfida di programmazione, non come un golf di codice, l'ho affrontato come una sfida di programmazione. Ho cercato di mantenere la mia soluzione e la logica semplice ma si è rivelato più brutto quando le cose si sono complicate rapidamente.

Il mio codice

Alcune cose a cui pensare durante la lettura: il programma crea un elenco di mazze usate chiamate "mazze" e un elenco chiamato "distanze" che è la distanza percorsa dalla pallina dal tee, hlen è la lunghezza della buca, d1s è la distanza percorsa da ogni colpo.

Per prima cosa definisco il corso. Ogni fairway, acqua e lunghezza verde dovevano essere definiti in modo che in seguito il programma potesse controllare le condizioni della palla, quindi ho aggiunto valori non interi per le parti del campo che non esistevano.

from random import randint
import numpy as np

#Hole      Length     flen               wlen           glen    Name 
hole1 = [    401,     54, 390,       390.5, 390.5,    391, 425, 'Hole 1']
hole2 = [    171,    0.5, 0.5,           1, 165,      166, 179, 'Hole 2']
hole3 = [    438,     41, 392,         393, 420,      421, 445, 'Hole 3']
hole4 = [    553,     30, 549,         282, 353,      550, 589, 'Hole 4']
hole5 = [    389,     48, 372,         1.5, 1.5,      373, 404, 'Hole 5']
hole6 = [    133,    0.5, 0.5,         1.5, 1.5,      125, 138, 'Hole 6']
hole7 = [    496,     37, 413,         414, 484,      484, 502, 'Hole 7']
hole8 = [    415,     50, 391,         1.5, 1.5,      392, 420, 'Hole 8']
hole9 = [    320,     23, 258,         259, 303,      304, 327, 'Hole 9']

holes = [hole1, hole2, hole3, hole4, hole5, hole6, hole7, hole8, hole9]

Qui ho definito la logica principale per la scelta di un club. Il programma tenta di massimizzare la distanza scegliendo il conducente per tutte le lunghezze superiori alla distanza massima del conducente e sceglie una mazza con un raggio che contenga altrimenti la distanza dalla buca. Ciò richiede che l'intervallo fornito dall'input del club sia continuo, vale a dire senza lacune nella distanza del tiro. Un requisito realistico poiché si può colpire un club senza un backswing completo per limitare la distanza del tiro alla massima distanza del club più potente successivo.

def stroke(distance):
    Length = abs(hlen - distance)
    if Length >= Driver_a:
        club = 'Driver'
        d = randint(Driver_a,Driver_b)
    elif Length >= Wood3_a and Length <= Wood3_b:
        club = '3-Wood'
        d = randint(Wood3_a,Wood3_b)
    elif Length >= Wood5_a and Length <= Wood5_b:
        club = '5-Wood'
        d = randint(Wood5_a,Wood5_b)
    elif Length >= Iron3_a and Length <= Iron3_b:
        club = '3-Iron'
        d = randint(Iron3_a,Iron3_b)
    elif Length >= Iron4_a and Length <= Iron4_b:
        club = '4-Iron'
        d = randint(Iron4_a,Iron4_b)
    elif Length >= Iron5_a and Length <= Iron5_b:
        club = '5-Iron'
        d = randint(Iron5_a,Iron5_b)
    elif Length >= Iron6_a and Length <= Iron6_b:
        club = '6-Iron'
        d = randint(Iron6_a,Iron6_b)
    elif Length >= Iron7_a and Length <= Iron7_b:
        club = '7-Iron'
        d = randint(Iron7_a,Iron7_b)
    elif Length >= Iron8_a and Length <= Iron8_b:
        club = '8-Iron'
        d = randint(Iron8_a,Iron8_b)
    elif Length >= Iron9_a and Length <= Iron9_b:
        club = '9-Iron'
        d = randint(Iron9_a,Iron9_b)
    elif Length >= Pwedge_a and Length <= Pwedge_b:
        club = 'P wedge'
        d = randint(Pwedge_a,Pwedge_b)
    elif Length >= Swedge_a and Length <= Swedge_b:
        club = 'S wedge'
        d = randint(Swedge_a,Swedge_b)
    elif Length >= Lwedge_a and Length <= Lwedge_b:
        club = 'L wedge'
        d = randint(Lwedge_a,Lwedge_b)        
    else : print 'stroke error'
    return club, d

Successivamente, definisco una funzione put che due put per tutte le lunghezze superiori a 5 iarde al foro e un putt per 5 e meno. Includo anche un'opzione per colpire la palla direttamente nel buco chiamato 'chip in'.

def putt(distance):
    Length = abs(hlen - distance)
    if Length > 5:
        club = '2 putts'
    elif Length == 0:
        club = 'chip in'
    else:
        club = '1 putt'
    return club

Qui è dove la strategia diventa un po 'funky. Al fine di mantenerlo semplice e anche evitare di rimanere bloccati in un circuito di guida in acqua solo per far cadere la palla nella posizione del tiro precedente e guidare di nuovo in acqua, in realtà faccio un passo indietro, colpendo la palla all'indietro con il cuneo di sabbia e quindi fai in modo che il codice valuti di nuovo lo scatto questa volta sperando di sparare proprio di fronte all'acqua in modo che lo scatto successivo possa cancellarlo. Questa strategia è penalizzata dalla penalità approssimativa, ma è efficace per la pulizia delle acque.

def water():
    club = 'S wedge'
    d = randint(50,79)
    return club, d

Questo programma conta il numero di colpi per buca dopo che quella buca è stata giocata. Aggiunge le penalità per i tiri grezzi e aggiunge le penalità per colpire in acqua sommando un array chiamato acqua che viene aggiunto dopo ogni colpo d'acqua. Questo sfrutta il fatto che il fairway porta sempre all'acqua o al green per ogni buca del percorso. Dovrebbe essere cambiato per i corsi che contenevano approssimativi nel mezzo del fairway.

def countstrokes(clubs, distances, waters):
    distances = np.array(distances)
    mask1 = distances < flen1
    mask2 = distances > grn2
    extra = sum(mask1*1)+sum(mask2*1) + sum(waters)
    if clubs[-1] == 'chip in' : strokes = len(clubs)-1+extra
    elif clubs[-1] == '2 putts' : strokes = len(clubs) +1+extra
    elif clubs[-1] == '1 putt' : strokes = len(clubs)+extra
    else : print 'strokes error'
    return strokes

Dopo l'esecuzione del codice principale, la condizione esamina le distanze a cui si trovava la palla durante la buca e segnala le condizioni della palla. Ho riscontrato un problema con la condizione a causa del modo in cui ho trattato di colpire la palla in acqua nel programma principale. Nel programma, se la palla veniva colpita in acqua, veniva immediatamente spostata indietro nel punto in cui veniva colpito il tiro. La distanza è stata registrata dopo che la palla è stata spostata indietro, quindi le condizioni della palla non possono essere "acqua". Se colpisci la palla fuori dal tee sulla buca 4 nell'acqua, il programma stampa la distanza che colpisci la palla e la mazza, ma la lunghezza della buca rimarrà invariata e la condizione sarà 'approssimativa' poiché la palla è caduta a 0 distanza approssimativa. Puoi decommentare una 'acqua' di stampa

def condition(distances):
    conditions=[]
    for distance in distances:
        if distance >= grn1 and distance <= grn2:
            conditions.append('green')
        elif distance >= flen1 and distance <= flen2:
            conditions.append('fair')
        else:
            conditions.append('rough')
    return conditions

Ecco la parte principale del codice che carica i buchi e gioca. Dopo aver inizializzato alcune condizioni, il codice esegue il "colpo" colpendo la palla verso la buca, incluso il contrario se la buca è stata superata, fino a quando non si incontra acqua o verde. Se si incontra acqua, si aggiunge a un segnalino penalità e si avvia l'acqua del programma e dopo aver spostato la palla nella posizione da cui è stata colpita. Se viene rilevato il verde, viene chiamato put e il foro viene terminato. Dopo che le distanze e le mazze sono state analizzate per determinare le condizioni di ogni tiro e i colpi sono contati.

def golf(driver_a, driver_b, wood3_a, wood3_b, wood5_a, wood5_b, iron3_a, iron3_b, iron4_a, iron4_b, iron5_a, iron5_b, iron6_a, iron6_b, iron7_a, iron7_b, iron8_a, iron8_b, iron9_a, iron9_b, pwedge_a, pwedge_b, swedge_a, swedge_b, lwedge_a, lwedge_b):
    global Driver_a, Driver_b, Wood3_a, Wood3_b, Wood5_a, Wood5_b, Iron3_a, Iron3_b, Iron4_a, Iron4_b, Iron5_a, Iron5_b, Iron6_a, Iron6_b, Iron7_a, Iron7_b, Iron8_a, Iron8_b, Iron9_a, Iron9_b, Pwedge_a, Pwedge_b, Swedge_a, Swedge_b, Lwedge_a, Lwedge_b
    Driver_a, Driver_b, Wood3_a, Wood3_b, Wood5_a, Wood5_b, Iron3_a, Iron3_b, Iron4_a, Iron4_b, Iron5_a, Iron5_b, Iron6_a, Iron6_b, Iron7_a, Iron7_b, Iron8_a, Iron8_b, Iron9_a, Iron9_b, Pwedge_a, Pwedge_b, Swedge_a, Swedge_b, Lwedge_a, Lwedge_b = driver_a, driver_b, wood3_a, wood3_b, wood5_a, wood5_b, iron3_a, iron3_b, iron4_a, iron4_b, iron5_a, iron5_b, iron6_a, iron6_b, iron7_a, iron7_b, iron8_a, iron8_b, iron9_a, iron9_b, pwedge_a, pwedge_b, swedge_a, swedge_b, lwedge_a, lwedge_b
    totals =[]
    for hole in holes:
        distance = 0
        strokes = 0
        clubs = []
        distances = []
        d1s = []
        waters=[]
        global hlen, flen1, flen2, wtr1, wtr2, grn1, grn2
        hlen, flen1, flen2, wtr1, wtr2, grn1, grn2, name = hole
        while True:
            club1, d1 = stroke(distance)
            clubs.append(club1)
            if distance > hlen:
                d1 = -d1
            distance = distance + d1
            d1s.append(d1)
            if distance >= wtr1 and distance <= wtr2:
                #print 'water'
                waters.append(1)
                distance = distance - d1
                distances.append(distance)
                club1, d1 = water()
                if distance < wtr1:
                    d1 = - d1
                distance = distance + d1
                d1s.append(d1)
                clubs.append(club1)
            distances.append(distance)
            if distance >= grn1 and distance <= grn2:
                club1 = putt(distance)
                clubs.append(club1)
                break
        strokes =  countstrokes(clubs, distances, waters)
        totals.append(strokes)
        conditions = condition(distances)
        shots = len(d1s)
        print name, ':',
        for x in xrange(0,shots):
            print '{', clubs[x], ',', d1s[x],',', conditions[x],',', hlen-distances[x], '}',
        print '{',clubs[-1], '}', '{',strokes ,'}'
    print 'Total:', sum(totals), 'shots'
    return sum(totals)

Il codice viene eseguito come

golf(300,330,270,299,240,269,220,239,200,219,180,199,160,179,140,159,120,139,100,119,80,99,50,79,0,49)

e il risultato è simile al seguente:

Hole 1 : { Driver , 308 , fair , 93 } { P wedge , 96 , green , -3 } { 1 putt } { 3 }
Hole 2 : { 6-Iron , 166 , green , 5 } { 1 putt } { 2 }
Hole 3 : { Driver , 321 , fair , 117 } { 9-Iron , 105 , green , 12 } { 2 putts } { 4 }
Hole 4 : { Driver , 305 , rough , 553 } { S wedge , -62 , rough , 615 } { Driver , 326 , fair , 289 } { 3-Wood , 293 , green , -4 } { 1 putt } { 8 }
Hole 5 : { Driver , 323 , fair , 66 } { S wedge , 73 , green , -7 } { 2 putts } { 4 }
Hole 6 : { 8-Iron , 125 , green , 8 } { 2 putts } { 3 }
Hole 7 : { Driver , 314 , fair , 182 } { 5-Iron , 181 , green , 1 } { 1 putt } { 3 }
Hole 8 : { Driver , 324 , fair , 91 } { P wedge , 91 , green , 0 } { chip in } { 2 }
Hole 9 : { Driver , 317 , green , 3 } { 1 putt } { 2 }
Total: 31 shots

Questo è stato il punteggio più basso di molte prove, con un minimo assoluto di 26 su 100.000 corse. Ma ancora sotto un tipico par di 34-36 anche con 8 colpi sulla buca 4.

Includerò il codice che ho usato per trovare la distribuzione dei giochi con i club sopra specificati.

import matplotlib.pyplot as plt
class histcheck(object):

    def __init__(self):
        self = self

    def rungolf(self, n=10000):
        results=[]
        for x in xrange(0,n):
            shots = golf(300,330,270,299,240,269,220,239,200,219,180,199,160,179,140,159,120,139,100,119,80,99,50,79,0,49)
            results.append(shots)
        self.results = results

    def histo(self, n=20):
        plt.figure(figsize=(12,12))
        plt.hist(self.results, bins=(n))
        plt.title("Histogram")
        plt.xlabel("Shots")
        plt.ylabel("Frequency")
        plt.show()

In esecuzione

play = histcheck()
play.rungolf()
play.hist()

fornisce il seguente istogramma Istogramma del golf

e la media e la mediana possono essere trovate usando

np.mean(play.results)
np.meadian(play.results)

una media di circa 43 e una mediana di 41. Non male per 9 buche con una semplice ottimizzazione del tiro.

Adesso è tutto tuo

Vai avanti, copia e modifica il mio programma e valutalo usando i miei strumenti per ridurre il numero medio di scatti. Fammi sapere se c'è qualche scenario di cui non ho tenuto conto o andare avanti e realizzare una versione giocata a golf. Penso che il miglior programma sarebbe quello che ha restituito i tiri medi più bassi per un certo numero di ingressi di club. Il mio codice non è l'opzione migliore per questo, ma ho pensato di far rotolare la palla.

Aggiornare

def water():
    if clubs[-1] =='S wedge':
        club = 'S wedge'
        d = randint(50,79)
    elif clubs[-1] !='S wedge':
        club = 'S wedge'
        d = -randint(50,79)
    else: print 'water error'
    return club, d

Modificando la logica dell'acqua in modo che tenti di colpire la palla in avanti di una piccola quantità dopo aver incontrato acqua anziché all'indietro se il club precedente utilizzato non era il cuneo di sabbia, ha migliorato la media a 40,5 e la mediana a 39 dopo aver provato con uno milioni di corse. Minimo 23, massimo 135. A volte sei fortunato, a volte no. Dai un'occhiata al nuovo istogramma.

Histogram2

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.