ゴルフをコーディングして


15

ゴルフをしたことがない場合、この質問で使用するゴルフ関連用語のリストを以下に示します

  • ショットストロークとも呼ばれる:ボールがヒットするたびに、これはショットです。
  • ホール:ゴルフコースはホールに分割され、ゴールはできるだけ少ないショットで指定された場所から別の場所にボールを打つことです。
  • ティー:穴を開けるところ。
  • ピンまたはフラグ:穴を仕上げる場所
  • FairwayRoughWaterGreen:ゴルフコースの機能で、実際の生活でボールをどのようにプレーするかに影響します。(それらがプログラムにどのように影響するかを以下に指定します)

私は明日ゴルフに出かけますが、時々、特定のヤードを打つためにどのクラブを使用するのかわからないことがあります。そこで、ショットごとにクラブとそのヤードを書き留めることにしました。

最初の仮定:すべての穴はティーボックスの真北にあります。

これらのヤードはすべて、ボールがどれだけ北に移動するかの可能性を測定します。ボールは、各クラブに指定された境界(両端を含む)の間のランダムな整数距離を移動します。

マスターゴルファーとして、私のショットには水平シフトがありません。これは、すべてのショットが直接旗に向かってまっすぐ進むことを意味します。

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)

プログラミングが好きな人として、私はゴルフのラウンドをモデル化し、明日はどれだけうまくやりたいかという目標を設定したいと思います。しかし、アマチュアプログラマーのように、10分後、私はあきらめてStack Overflow(冗談です)の助けを求めました。コースに関するその他のデータを次に示します。

第二の仮定:穴の地理

  • コース上の距離を表す数値はすべて整数です。

  • 各穴は直線です。各穴とピン(穴の端)間の直線距離はLengthです。

  • フェアウェイは、で定義される長さのセグメントflenです。記載されてflenいる値は、フェアウェイがあるティーから北のヤードの範囲です。

  • ウォーターハザードはwlen、で定義された長さを持つセグメントで、と同じプロパティを持ちますflen

  • 緑の長さはで定義されていglenます。

  • コースのフェアウェイ、ウォーター、グリーン以外の部分はすべて荒れています。

これがコースの各ホールを説明するチャートです。

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

ゴルフのプレイ方法(このプログラムの場合)

  • 常に正確に旗を目指してください。
  • できるだけピンの近くでボールを打ち、ボールをフェアウェイまたは(できれば)グリーンに留めようとします。
  • 水にショットを着地させるとき、次のショットは、水に入ったショットと同じ場所からプレイする必要があります。
  • ボールがグリーンに着地したら、パターのみを使用できます。ボールがピンから5ヤード以上厳密に着地した場合、2回パットします。そうでなければ、私は一度パットします。
  • ピンを越えてショットを打つことが可能です。

得点

ホールでの私のスコアは、撮影したショットの数に加えて、ラフまたは水に着地するたびに1ストロークです。

プログラム

さて、それは多くのルールでした。次に、プログラムについて話しましょう。

コースは一定であるため、プログラムで上記のようコースを定義する必要があります。ただし、ゴルファーによってショットごとに距離が異なるため、STDINへの入力は、クラブ番号の昇順で並べられ、カンマで区切られた(空白なしの)ヤードの範囲のセットである必要があります。

出力は、ゴルフのラウンドをどのように「プレイ」するかです。保留番号は、現在のホールHole #:がどこにあるか#として、各行の先頭に指定する必要があります。パットではない各ショットの形式は次のとおりです{club,distance of shot,condition of ball,distance to pin}。ショットの詳細はカンマで区切る必要がありますが、上記の順序で空白は使用しないでください。ショット自体は、それらがどのように再生され、スペースで区切られた順に書かれている必要があります。ボールがグリーンに着地すると、プログラムは、パット数をフォーマットで印刷する必要があります{# putts}。各行の最後に、ホールで撮影したショットの数を他のショットとスペースで分けて、次のように印刷する必要があります(#)。各穴はそれぞれの行にあり、順番に書かれている必要があります。最後に、プログラムの最後の(10番目の)行に、ラウンドのショットの総数をとして印刷する必要がありますTotal: # shots

プログラムが取る必要のある「戦略」はありません。任意の戦略でプログラムを作成できます。戦略の例には、グリーンに着く確率の最大化と、ホールに到達するまでの各ショットの距離の最大化が含まれます。

サンプル入力

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

サンプル出力

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

CG.SEの最初の投稿では、これはかなり野心的な課題であるため、コメントでこの課題を改善する方法についてお話しできることを嬉しく思います。ご協力ありがとうございました。


2
ゴルフ愛好家でなくても、ゴルフ用語(「ティーボックス」や「水平シフト」など)をあまり使用していなかったら、本当にありがたいです。:)
kirbyfan64sos

ゴルフ関連の用語のリストを追加します。ゴルフをしているとき、ボールは常にまっすぐに進むとは限らないので、ボールは常にホールに向かって直接進むため、水平方向のシフトがないと言っただけです。
アークトゥルス

ピンが301ヤードにあり、0~299ヤードからフェアウェイ、ヤードからグリーン、300~315ヤードから水があるとし316~330ます。どのクラブが選ばれますか?水がラフに置き換えられたらどうなりますか?
リルトシアスト

理想的には、プログラムは独自の戦略を考え出すことができるはずです。
アークトゥルス

「最適戦略」とはどういう意味ですか?ストロークの平均数を最小化しますか?受賞基準については、私はコードゴルフに行きます。
リルトシアスト

回答:


9

Python 2.7: 平均43 40.5ショット

これが私の最初の投稿ですので、ご容赦ください。

ポスターは、これをコードゴルフではなくプログラミングの課題のように扱うことを考えていたので、プログラミングの課題として取り組むことにしました。私は自分のソリューションを維持し、ロジックをシンプルにしようとしましたが、事態がすぐに複雑になるにつれて、よりいものになりました。

私のコード

読みながら考えること:プログラムは、「クラブ」と呼ばれる使用されるクラブのリストと、ボールがティーから移動した距離である「距離」と呼ばれるリストを作成します。hlenはホールの長さ、d1sは各ショットが移動する距離。

まず、コースを定義します。後でプログラムがボールの状態をチェックできるように、各フェアウェイ、ウォーター、グリーンの長さを定義する必要があったため、コースの存在しない部分に整数以外の値を追加しました。

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]

ここで、クラブを選択するためのメインロジックを定義しました。プログラムは、最大ドライバー距離よりも長いすべての長さのドライバーを選択することで距離を最大化しようとし、それ以外の場合はホールまでの距離を含む範囲を持つクラブを選択します。これには、クラブ入力によって提供される範囲が連続的である、つまりショット距離にギャップがないことが必要です。完全なバックスイングなしでクラブにヒットして、ショットの距離を次に強力なクラブの最大距離に制限できるため、現実的な要件です。

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

次に、穴までの長さが5ヤードを超えるすべての長さに対して2つのパットと5以下の長さに対して1つのパットを使用するプット関数を定義します。また、「チップイン」と呼ばれる穴にボールを直接打つためのオプションも含まれています。

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

ここで、戦略が少しファンキーになります。シンプルに保つために、また水の中に打ち込むループに巻き込まれないようにするために、前のショットの場所でボールを落とし、再び水の中に打ち込むために、私は実際にバックトラックし、砂のくさびでボールを後方に打ちます次のショットでクリアできるように、今度はコードでもう一度ショットを評価して、できれば水の前で撮影するようにします。この戦略は、大まかなペナルティによって罰せられますが、水をきれいにするのに効果的です。

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

このプログラムは、そのホールがプレイされた後のホールごとのストローク数をカウントします。ラフのショットのペナルティを追加し、各ウォーターショットの後に追加されるwaterと呼ばれる配列を合計することで、水にヒットするペナルティを追加します。これは、コースのすべてのホールでフェアウェイが常に水またはグリーンにつながるという事実を利用しています。フェアウェイの真ん中にラフが含まれているコースでは変更する必要があります。

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

メインコードが実行された後、条件は、ホール中にボールがあった距離を見て、ボールの状態を報告します。メインプログラムでボールを水に打ち込むのを扱った方法のために、私は状態に関する1つの問題に遭遇しました。プログラムでは、ボールが水に当たった場合、すぐにショットが当たった場所に戻りました。ボールが戻った後に距離が記録されたため、ボールの状態が「水」になることはありません。ホール4のティーからボールを​​水中に打ち込んだ場合、プログラムはボールとクラブを打った距離を出力しますが、ホールまでの長さは変わらず、ボールはラフにある0の距離。印刷物の「水」のコメントを外すことができます

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

これが、穴をロードしてゲームをプレイするコードの主要部分です。いくつかの条件を初期化した後、コードは「ストローク」を実行して、ボールをホールに向けて打撃します。水に遭遇すると、ペナルティーカウンターに追加され、プログラムwaterが実行され、ボールがヒットした場所に戻されます。緑に出会うと、putが呼び出され、ホールが終了します。距離とクラブを分析して各ショットの状態を判断し、ショットを集計した後。

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)

コードは次のように実行されます

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)

アウトは次のようになります。

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

これは多くの試験の中で最も低いスコアの1つであり、100,000回の実行で最低の26でした。しかし、4番ホールで8回のストロークを行っても、通常の34〜36のパー以下です。

上記の特定のクラブでのゲームの配布を見つけるために使用したコードを含めます。

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()

ランニング

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

次のヒストグラムを与えます ゴルフヒストグラム

そして、平均と中央値を使用して見つけることができます

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

約43の平均と41の中央値。単純なショットの最適化で9ホールには悪くない。

今はすべてあなたのものです

先に進み、プログラムをコピーして微調整し、ツールを使用して評価して、平均ショット数を減らします。私が説明しなかった、または先に進んでゴルフバージョンを作成したシナリオがあれば教えてください。最良のプログラムは、多くのクラブのインプットに対して最も低い平均ショットを返したプログラムだと思います。私のコードはそのための最良の選択肢ではありませんが、私はボールを転がすと思いました。

更新

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

前に使用したクラブが砂くさびではなかった場合、水に遭遇した後、後方ではなく少量でボールを前方に打とうとするように水の論理を変更することで、1つでテストした後、平均を40.5に、中央値を39に改善しました百万回の実行。最小23、最大135。時には幸運になることもあれば、そうでないこともあります。新しいヒストグラムを確認してください。

ヒストグラム2

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.