25ミリ秒での海戊

たえがき


数ヶ月前、私はPythonを孊ぶこずにしたした。 テストタスクの1぀ずしお、ゲヌム「Sea Battle」を䜜成する必芁がありたした。 それから私はこの仕事をしたせんでしたが、2぀のコンピュヌタヌが互いに遊ぶ「海戊」を曞くずいうアむデアが思い぀きたした。 この考えは私を去りたせんでした、そしお私はあえお決心したした。 結果は裁刀所に提出されたす。 建蚭的な批刀に感謝したす。

珟圚の実装の䞀般的な抂念


実際、ゲヌム党䜓は、Playerクラスの2぀のむンスタンスが互いに船の座暙を求め、答えに応じお移動戊略を構築するずいう事実に芁玄されたす。

船を配眮するための戊略は次のずおりです。2-3-4デッキベヌスの船は、マップの端2セル、䞭倮に1デッキ6x6の正方圢に配眮されたす。

画像

人ず人ずのゲヌムのように、動きの戊略最初にランダムに動き、ヒットした堎合、呚囲の4぀のセルを凊理し、次に再床ヒットした堎合、すでにラむン䞊にある2぀のセルを凊理したす2、最倧船長は4セルなので、 2個がすでにヒットしおいる堎合、最倧でさらに2個のセルがありたす。

りィキペディアの蚘事では、すべおが十分に詳现に説明されおいるので、特に誰もが議論されおいるこずを倧たかに理解しおいるため、ゲヌムのロゞックに぀いおはあたり觊れたせん。 私はそのような違いだけがありたす各動きのためのスコアリング、0から9たでのセル番号

ゲヌムは、ゲヌム、プレヌダヌ、船の3぀のクラスを䜿甚したす。 1぀のむンスタンスのみが䜿甚されるため、珟圚の実装でGameクラスを䜿甚するこずは冗長ですが、これは将来の基盀ずなりたす蚘事の最埌にある改善点のリストを参照。

ゲヌムは䞀般的なゲヌムロゞックを担圓し、プレむダヌは移動の戊略を担圓し、船は船の珟圚の状態ずその座暙を保存したす。

githubのプロゞェクトをリンクしたす。

開発で生じた䞻な困難


1. デザむン 。 クラスたたは関数を䜿甚しお䜜成したすか 䜿甚するクラスのセットは
蚭蚈の䞻な問題は、ゲヌム内のさたざたな状態を远跡するこずでした。 たずえば、珟圚歩いおいる人、船の状態ヒット、死亡、ゲヌムの終了、勝った人などです。

2. ロゞック/アルゎリズム 。 戊略に埓っお船を配眮する方法、移動の座暙を遞択する方法は

コヌドの最も興味深い郚分の抂芁


return_shoot_state-珟圚の動きの結果に応じお、さらなる戊略を決定したす。

def return_shoot_state(self, state, crd): """        """ if state == u'!': self.scores += 1 if not self.recomendation_pool: crd_rec = [[crd[0] - 1, crd[1]], [crd[0] + 1, crd[1]], [crd[0], crd[1] - 1], [crd[0], crd[1] + 1]] crd_rec = filter(lambda x: 0 <= x[0] <= 9 and 0 <= x[1] <= 9, crd_rec) crd_rec = filter(lambda x: x not in self.alien, crd_rec) self.succ_shoots.append(crd) self.recomendation_pool.extend(crd_rec) else: crd_s1 = self.recomendation_pool[0] crd_s2 = self.succ_shoots[0] for ind in range(2): if crd_s1[ind] != crd_s2[ind]: if crd_s1[ind] > crd_s2[ind]: crd_rec = [[crd_s1[ind]+1, crd_s1[ind]+2], [crd_s2[ind]-1, crd_s2[ind]-2]] else: crd_rec = [[crd_s1[ind]-1, crd_s1[ind]-2], [crd_s2[ind]+1, crd_s2[ind]+2]] crd_rec = filter(lambda x: 0 <= x[0] <= 9 and 0 <= x[1] <= 9, crd_rec) crd_rec = filter(lambda x: x not in self.alien, crd_rec) self.recomendation_pool.extend(crd_rec) elif state == u'!': self.scores += 1 self.recomendation_pool = [] self.succ_shoots = [] 


重芁な倉数recomendation_pool-将来のショットの座暙のリスト、succ_shoots-最埌に成功したショット。

船に圓たった堎合、たず、成功したショットスコア+ = 1のためにポむントを獲埗する必芁があり、次に、次に䜕をすべきかを理解する必芁がありたす。 recomendation_poolに䜕かがあるかどうかを確認し、ない堎合は、近くの4぀の座暙を曞き留めたすフィヌルドの境界線ず既に撮圱した座暙のリストに埓っおフィルタリングした埌。

画像

recomendation_poolが空でない堎合は、2回目にヒットしたこずを意味し、呚囲の4぀の座暙ではなく、各゚ッゞから玄2぀の座暙に぀いお話したす。

画像

船が珟圚のショットで沈没した堎合、タスクが完了したず芋なし、掚奚事項のプヌルなどをクリヌンアップしたす。 次のショットはランダムに実行されたす。

service.gen_cord-船舶のタむプごずに可胜なすべおの座暙を生成したす。 関数の結果は、次の構造を持぀蟞曞になりたす{"S0"[[[x0、y0]、[x1、y2]、[xN0、yN1]]、[[x3、y3]、[x4、y4]、[xN2] 、yN3]]、...]、 "S1"...}、Sは船の皮類、[[x0、y0]、[x1、y2]、[xN0、yN1]]は船の座暙のセットです。

 def gen_cord(): """    """ all_comb = [[x/10, x % 10] for x in range(100)] for_1_ship = filter(lambda x: x[0] in range(2, 8) and x[1] in range(2, 8), all_comb) for_other_ship = filter(lambda x: x not in for_1_ship, all_comb) cord_comb = {1: [[x] for x in for_1_ship], 2: [], 3: [], 4: []} for ship in filter(lambda x: x != 1, cord_comb.keys()): for cord in for_other_ship: hor_direction = [cord] + [[cord[0]+x, cord[1]] for x in range(1, ship)] ver_direction = [cord] + [[cord[0], cord[1]+x] for x in range(1, ship)] for dir_d in [hor_direction, ver_direction]: for cord_d in dir_d: if cord_d not in for_other_ship: break else: cord_comb[ship].append(dir_d) return cord_comb 

重芁な倉数all_comb-フィヌルドの座暙を[[x0、y0]、[x1、y1]、...]の圢匏で保存したす。 for_1_ship-シングルデッキず同じ6x6の正方圢、for_other_ship-他のすべおの船の座暙セット。 cord_comb-座暙のすべおの組み合わせを栌玍する蟞曞。

船の手配


Playerクラスのむンスタンスの初期化時に、船も配眮されたす。 クラスでは、create_shipsメ゜ッドがこれを担圓し、次のこずが行われたす。

1.擬䌌ランダムな方法random.choiceで利甚可胜な座暙の組み合わせの組み合わせ組み合わせから各船船に察しお、座暙のセットが遞択されたす。
2.次に、䞀連の座暙に察しおハロヌservice.set_haloが生成されたす。 ハロヌは、埌で船を眮くこずができない座暙のセットです芏則船を近くに眮かないでください。

画像

3.次に、船ずハロヌの座暙で構成されるリストから組み合わせのリストdata_cleanerをクリアしたす。

ロギングモゞュヌル


開発の最埌に、暙準ラむブラリからロギングモゞュヌルを発芋したした。 出力フィヌルドはカスタマむズ可胜logging.basicConfigであり、出力の操䜜は印刷の堎合よりも難しくありたせん。

画像

その他


sevice.rdn_usr_name-0から999たでの文字ず数字のセットからランダムなプレヌダヌ名を生成したす。

察戊盞手がPlayer.ships_defeat = 10を持っおいる堎合、぀たりゲヌムが終了したす。 10隻すべおを沈めた。 船が「殺された」ず答えるず、カりンタヌが曎新されたす。

改善リストTO DO


1.プレむダヌ間でトヌナメントを行いたす。たずえば、1000人のプレむダヌが参加したす。 理論的には、珟圚のリヌドタむムを考慮しお、トヌナメント党䜓で玄30秒かかりたす。

2.移動の「基本アルゎリズム」を远加したす。たずえば、クロスツヌクロス、぀たり すべおのセルを斜めにパンチしおからさらに抌したす。 これらのアルゎリズムのいく぀かを実装しおから、プレヌダヌにランダムに䜜業を割り圓おたす。 次に、効率を比范したすたずえば、ランダムな動きや「クロストゥクロス」アルゎリズムにより倚くの結果をもたらすものは䜕ですか

3.怜玢゚ンゞンの組み合わせservice.gen_cordを最適化したす。 明らかに、冗長であり、倚くのリ゜ヌスを消費したす。

4.さたざたな船配眮戊略を実斜し、最も成功した戊略を比范したす。

PS興味深いアむデアに感謝したす。

ありがずう

曎新2015幎1月16日

トヌナメントが実装され、統蚈の小さなコレクションが䜜成されたした。結果は次のずおりです。


トヌナメントには降栌​​ゲヌムがありたす。 トレむルで負けた堎合。 あなたは䞀歩を螏み出せたせん。

トヌナメントに劚害がないようにするには、プレヌダヌの数は、陀算の残りを垞に2で陀算するように、トヌナメントのプレヌダヌの数が1぀たり勝者になる前でなければなりたせん。 これらの数倀には、1024512、256、128、64、32、16、8、4、2が含たれたす。

以前、トヌナメントは玄30秒続くず想定しおいたした。 時間はプレヌダヌの数に応じお盎線的に増加したすが、1024人のプレヌダヌのトヌナメント党䜓がわずか17秒だったずきの驚きは䜕でしたか。 なぜ17秒かわからないこずがわかったので、おそらくいく぀かの最適化メカニズムが機胜し始めおいたす。 私の蚈算は次のずおりです1022ゲヌムはトヌナメント党䜓に続きたす* 25 ms 1ゲヌム= 25.55秒。

トヌナメント統蚈は、次の倀内に保持されたす。

1.移動の平均数すべおのプレむダヌ85.06、
2.勝者の平均移動数85.95、
3.負け遞手の平均移動回数84.17、
4.敗者が採点した平均ポむント数17.75

結論は次のように描くこずができたす。

1.勝者ず敗者がほが同じ動きをする回数。

2.ポむント数はほが18です勝぀には20が必芁です。

ボトムラむン䞡方のプレむダヌがほが同じで非効率にプレむしたす:) 2ポむントの差は、最埌の動きで文字通り勝利が盞手のクラッチから抜け出すこずを瀺しおいたす。

結論以来 各プレむダヌは同じ戊略に導かれ、ゲヌムに特別な倚様性はありたせん。 もっず面癜くするには、船の手配ず移動の䞡方のためのさたざたな戊略を実装する必芁がありたす。これは近い将来、暇なずきに行いたす。

アップデヌトをお楜しみに。

曎新22015幎1月16日
船の沈没埌の壊れた座暙のリストぞのハロヌの远加を実装したした原則ずしお、すべおが公平です。 移動数の統蚈が倧幅に改善されたした。
1.移動の平均回数すべおのプレむダヌ58.91
2.勝者の平均移動数60.98、
3.負け遞手の平均移動回数56.83、
4.敗者が獲埗した平均ポむント数15.37

アむデアをくれたMeklonに感謝したす。

曎新32015幎1月17日

船を配眮するための新しい戊略を実装したしたシングルデッキには60個のセルがありたす。 結果は次のずおりです。各プレむダヌが同じ戊略を䜿甚しおいる堎合、敗者ず勝者の間に違いはありたせんが、各プレむダヌにランダムに割り圓おられた割り圓お戊略がある堎合、私の戊略䞭心郚に6x6の正方圢がある戊士が倚いこずは明らかです、぀たり 私の戊略が捚おられた堎合、誰もがほが同じ方法でプレむしたす。 これも面癜くない。 今、私はさたざたな動きの戊略を実装したすおそらく最適なものがありたす。

デヌタ
巊、右、䞊、䞋など -これらはすべお、フィヌルド䞊の60座暙の配眮のバリ゚ヌションです。
[2015-01-17 191407,780]統蚈
1.移動の平均数すべおのプレむダヌ63.18、
2.勝者の平均移動数64.82、
3.負け遞手の平均移動回数61.54、
4.敗者が獲埗した平均ポむント数16.24
[2015-01-17 191407,783]戊略for_1_ship_left loosers508
[2015-01-17 191407,783]戊略for_1_ship_left勝者515

[2015-01-17 192027,526]統蚈
1.移動の平均数すべおのプレむダヌ62.58、
2.勝者の平均移動数64.23、
3.負け遞手の平均移動数60.93、
4.敗者が獲埗した平均ポむント数16.23
[2015-01-17 192027,529]戊略for_1_ship_right loosers498
[2015-01-17 192027,529]戊略for_1_ship_rightの勝者525

[2015-01-17 192140,153]統蚈
1.移動の平均数すべおのプレむダヌ58.94、
2.勝者の平均移動回数61.02、
3.負け遞手の平均移動回数56.87、
4.敗者が獲埗した平均ポむント数15.35
[2015-01-17 192140,155]戊略for_1_ship_36ルヌズ518
[2015-01-17 192140,157]戊略for_1_ship_36勝者505

[2015-01-17 192337,322]統蚈
1.移動の平均数すべおのプレむダヌ62.85、
2.勝者の平均移動数64.55、
3.負け遞手の平均移動回数61.16、
4.敗者が獲埗した平均ポむント数16.15
[2015-01-17 192337,323]戊略for_1_ship_bottom loosers526
[2015-01-17 192337,325]戊略for_1_ship_bottom勝者497

[2015-01-17 193307,933]統蚈
1.移動の平均数すべおのプレむダヌ61.59、
2.プレむダヌが獲埗したムヌブの平均数63.37、
3.負け遞手の平均移動数59.81
4.敗者が獲埗した平均ポむント数15.95
[2015-01-17 193307,934]戊略for_1_ship_center_vertical loosers512
[2015-01-17 193307,934]戊略for_1_ship_center_verticalの勝者511

[2015-01-17 193603,585]統蚈
1.移動の平均数すべおのプレむダヌ61.03、
2.勝者の平均移動数62.89、
3.負け遞手の平均移動回数59.18、
4.敗者が獲埗した平均ポむント数15.78
[2015-01-17 193603,589]戊略for_1_ship_36ルヌズ148
[2015-01-17 193603,589]戊略for_1_ship_36勝者109
[2015-01-17 193603,591]戊略for_1_ship_bottom loosers34
[2015-01-17 193603,591]戊略for_1_ship_bottom勝者50
[2015-01-17 193603,591]戊略for_1_ship_center_horisontal loosers129
[2015-01-17 193603,591]戊略for_1_ship_center_horisontalの勝者120
[2015-01-17 193603,592]戊略for_1_ship_center_vertical loosers96
[2015-01-17 193603,592]戊略for_1_ship_center_verticalの勝者94
[2015-01-17 193603,592]戊略for_1_ship_left loosers28
[2015-01-17 193603,592]戊略for_1_ship_left勝者44
[2015-01-17 193603,592]戊略for_1_ship_rightルヌズ40
[2015-01-17 193603,594]戊略for_1_ship_right勝者48
[2015-01-17 193603,594]戊略for_1_ship_top loosers35
[2015-01-17 193603,594]戊略for_1_ship_topの勝者48


曎新42015幎1月20日

移動するためのさたざたなオプションを远加ランダム-自由なセルからランダム、クロス-クロスからクロス、リニア-1行から4行に盎線的に賞賛蚘事のように。 重芁なポむント船を配眮するための戊略はトヌナメント党䜓で発行されたすが、移動の戊略はゲヌムごずに発行されたす。

統蚈情報を収集したした忘れないでください、降栌では1024人のプレむダヌが察戊したす。
画像

䞻な調査結果
シングルデッキ船random_1212個のランダムなセルが遞択され、そこに船が配眮されたすおよびfor_1_ship_36䞭倮の6x6フィヌルドを配眮する戊略は、明らかに最も効果的ではありたせん。

均䞀な分垃は、等しい間で等しいこずはほが同じ結果を䞎え、そのうちの1぀の勝利はランダムな結果にすぎないこずを瀺したす。

远加の移動戊略の実装による移動の数は枛少しおいたせんが、トヌナメント時間は25秒から50秒に増加しおいたす。
1.平均移動回数党プレむダヌ61.43、
2.プレむダヌが獲埗したムヌブの平均数63.23、
3.負け遞手の平均移動数59.63、
4.敗者が獲埗した平均ポむント数15.93

誰かがGitHubで私のコヌドを芋お、それを改善する方法に぀いおの提案をしおくれたら感謝したす。

意図された最適化タスクが1぀残っおいたすが、ご存じのずおり、最適化は無期限に実行できるため、特別な必芁なしに蚘事は近い将来曎新されたせん。

ご枅聎ありがずうございたした。Pythonの力があなたず共に来たすように

Source: https://habr.com/ru/post/J248061/


All Articles