Imports System.Net, System.Text, System.IO Module Module1 Dim hashmentusu2(1562500) As Integer 'ハッシュテーブルメンツ数 Dim hashkouho2(1562500) As Integer 'ハッシュテーブルメンツ候補数 Dim hashmentusu3 As Dictionary(Of Long, Integer) Dim hashkouho3 As Dictionary(Of Long, Integer) Sub Main() maindayo() End Sub Sub maindayo() hashyomikomi() 'プログラム開始時にハッシュテーブルを読み込む hashyomikomi2() Console.WriteLine("手牌を入力してください。") 'コンソールに表示される文 Dim tehaistring As String = "2m4m5m8m8m9m9m5P6p8p3s4s5s東" '入力文字列を変数に格納Console.ReadLine() Dim tehaifuroigaiakaari() As Integer = tehaitointhairetu(tehaistring) 'string型手牌をinteger型配列に変換 Dim furosu As Integer = tehaitofurosu(tehaistring) '副露数を計算 For i As Integer = 1 To 10000000 Dim shantensu() As Integer = totalshantenfunc_game2(akanasihenkan(tehaifuroigaiakaari), furosu) 'シャンテン数を計算 If i Mod 10000 = 0 Then Console.WriteLine(i) End If Next 'Console.WriteLine(shantensu(0) & "シャンテン") 'Console.WriteLine("国士" & shantensu(1) & "シャンテン") 'Console.WriteLine("チートイ" & shantensu(2) & "シャンテン") 'Console.WriteLine("面子手" & shantensu(3) & "シャンテン") '結果表示 'Console.ReadKey() '何かキーを押したらプログラム終了 End Sub Sub hashyomikomi() 'hashtable読み込み Dim hashtablefile = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "hashtable.txt") Dim fs2 As FileStream = New FileStream(hashtablefile, FileMode.Open) Dim sr2 As StreamReader = New StreamReader(fs2, Encoding.GetEncoding("Shift_jis")) Dim yomi As String = "" For i As Integer = 0 To 1562500 hashmentusu2(i) = -1 hashkouho2(i) = -1 Next Do Until yomi Is Nothing yomi = sr2.ReadLine If Not yomi = "" Then Dim m As Long = Long.Parse(yomi.Substring(0, yomi.IndexOf(" "))) yomi = yomi.Substring(yomi.IndexOf(" ") + 1) hashmentusu2(m) = Integer.Parse(yomi.Chars(0)) hashkouho2(m) = Integer.Parse(yomi.Chars(1)) End If Loop sr2.Close() End Sub Sub hashyomikomi2() Dim hashtablefile2 = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "hashtable2.txt") Dim fs2 As FileStream = New FileStream(hashtablefile2, FileMode.Open) Dim sr2 As StreamReader = New StreamReader(fs2, Encoding.GetEncoding("Shift_jis")) hashmentusu3 = New Dictionary(Of Long, Integer) hashkouho3 = New Dictionary(Of Long, Integer) Dim yomi As String = "" Do Until yomi Is Nothing yomi = sr2.ReadLine If Not yomi = "" Then Dim m As Long = Long.Parse(yomi.Substring(0, yomi.IndexOf(" "))) yomi = yomi.Substring(yomi.IndexOf(" ") + 1) hashmentusu3(m) = Integer.Parse(yomi.Chars(0)) hashkouho3(m) = Integer.Parse(yomi.Chars(1)) End If Loop End Sub Function tehaitointhairetu(ByVal tehai As String) As Integer() '手牌文字列を入力値として、int配列(赤あり副露以外)にしたものを返す Dim tehaiint(38) As Integer Dim a As Integer Do Until tehai = "" If Integer.TryParse(tehai.Chars(0), a) Then Select Case tehai.Chars(1) Case "m" tehaiint(a) += 1 Case "M" tehaiint(10) += 1 Case "p" tehaiint(a + 10) += 1 Case "P" tehaiint(20) += 1 Case "s" tehaiint(a + 20) += 1 Case "S" tehaiint(30) += 1 Case ";" Exit Do End Select tehai = tehai.Substring(2) Else tehaiint(haitoint(tehai.Chars(0), True)) += 1 tehai = tehai.Substring(1) End If Loop Return tehaiint End Function Function haitoint(ByVal hai As String, ByVal akaari As Boolean) As Integer 'haiのstring型を1〜37の数字に変換する If hai.Length <= 1 Then '字牌 Select Case hai Case "東" Return 31 Case "南" Return 32 Case "西" Return 33 Case "北" Return 34 Case "白" Return 35 Case "発" Return 36 Case "中" Return 37 Case Else Console.Write("haitoint関数_字牌(length<=1)変換エラー") Return -1 '数字変換エラー End Select Else Dim a As Integer Dim iro As String = hai.Chars(1) If Integer.TryParse(hai.Chars(0), a) Then Select Case iro Case "m" Return a Case "M" If akaari Then Return 10 Else Return a End If Case "p" Return a + 10 Case "P" If akaari Then Return 20 Else Return a + 10 End If Case "s" Return a + 20 Case "S" If akaari Then Return 30 Else Return a + 20 End If Case Else Console.Write("haitoint関数_数牌(2文字目)変換エラー") Return -3 '数字変換エラー End Select Else Console.Write("haitoint関数_数牌(1文字目)変換エラー") Return -2 '数字変換エラー End If End If End Function Function tehaitofurosu(ByVal tehai As String) As Integer '手牌文字列を入力値として副露数を返す Dim tmpfurosu As Integer = 0 Do While tehai.Contains(";") tehai = tehai.Substring(tehai.IndexOf(";")) tmpfurosu += 1 If tehai.StartsWith(";;") Then tehai = tehai.Substring(2) Else tehai = tehai.Substring(1) End If Loop Return tmpfurosu End Function Function akanasihenkan(ByVal tehai() As Integer) As Integer() '赤なしの手牌を返す Dim kekkatehai() As Integer = tehai.Clone() kekkatehai(5) += kekkatehai(10) kekkatehai(15) += kekkatehai(20) kekkatehai(25) += kekkatehai(30) kekkatehai(10) = 0 kekkatehai(20) = 0 kekkatehai(30) = 0 Return kekkatehai End Function Function kokusishantensu_game(ByVal tehaiakanasi() As Integer, ByVal furosu As Integer) As Integer '国士のシャンテン数を返す Dim kokusi_toitu As Integer = 0 Dim kokusi_shanten As Integer = 13 If furosu > 0 Then Return 100 '副露手はシャンテン計算しない End If For i As Integer = 1 To 29 If (i Mod 10 = 1) Or (i Mod 10 = 9) Then '老頭牌 If tehaiakanasi(i) > 0 Then kokusi_shanten -= 1 If tehaiakanasi(i) >= 2 Then kokusi_toitu = 1 End If End If End If Next For i As Integer = 31 To 37 '字牌 If tehaiakanasi(i) > 0 Then kokusi_shanten -= 1 If tehaiakanasi(i) >= 2 Then kokusi_toitu = 1 End If End If Next kokusi_shanten -= kokusi_toitu 'ヘッドあり Return kokusi_shanten End Function Function titoishantensu_game(ByVal tehaiakanasi() As Integer, ByVal furosu As Integer) As Integer Dim titoi_toitu As Integer = 0 Dim shurui As Integer = 0 Dim titoi_shanten As Integer = 7 If furosu > 0 Then Return 100 '副露手はシャンテン計算しない End If For i As Integer = 1 To 37 If tehaiakanasi(i) >= 2 Then shurui += 1 titoi_toitu += 1 ElseIf tehaiakanasi(i) >= 1 Then shurui += 1 End If Next titoi_shanten = 6 - titoi_toitu If shurui < 7 Then titoi_shanten += 7 - shurui End If Return titoi_shanten End Function Function normalshantenfunc_game(ByVal tehaifuroigaiakanasi() As Integer, ByVal furosu As Integer) As Integer 'メンツ手のシャンテン数を返す。(ハッシュテーブル+パーツで区切って高速化) '初期化 Dim tmppatunakami(10, 14) As Integer Dim tmppatunakami2(9) As Integer Dim listmenber As Integer = 0 Dim mentutatu(1) As Integer Dim tmpnumber As Integer = 1 Dim tmpnumber2 As Integer = 1 Dim hashkey As Integer = 0 Dim hashmoji As String = "" Dim hit As Boolean = False Dim normal_temp As Integer = 0 Dim normal_keshantensu As Integer = 8 Dim tmptehai() As Integer = tehaifuroigaiakanasi.Clone() Dim mentu As Integer Dim toitu As Integer Dim kouho As Integer For i As Integer = 1 To 37 mentu = furosu toitu = 0 kouho = 0 '頭抜き出し If tmptehai(i) >= 2 Then toitu += 1 tmptehai(i) -= 2 'パーツ分け tmpnumber = 1 listmenber = 0 For j As Integer = 1 To 10 For k As Integer = 0 To 14 tmppatunakami(j, k) = 0 Next Next Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else For k As Integer = 1 To 9 tmppatunakami(k, listmenber) = 0 Next tmpnumber2 = 1 Do tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) tmpnumber2 += 1 tmpnumber += 1 Loop Until tmpnumber >= 8 OrElse (tmptehai(tmpnumber) = 0 And tmptehai(tmpnumber + 1) = 0) tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) If tmpnumber <= 9 Then tmppatunakami(tmpnumber2 + 1, listmenber) = tmptehai(tmpnumber + 1) End If tmpnumber += 2 listmenber += 1 End If Loop Until tmpnumber >= 10 tmpnumber = 11 Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else For k As Integer = 1 To 9 tmppatunakami(k, listmenber) = 0 Next tmpnumber2 = 1 Do tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) tmpnumber2 += 1 tmpnumber += 1 Loop Until tmpnumber >= 18 OrElse (tmptehai(tmpnumber) = 0 And tmptehai(tmpnumber + 1) = 0) tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) If tmpnumber <= 19 Then tmppatunakami(tmpnumber2 + 1, listmenber) = tmptehai(tmpnumber + 1) End If tmpnumber += 2 listmenber += 1 End If Loop Until tmpnumber >= 20 tmpnumber = 21 Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else For k As Integer = 1 To 9 tmppatunakami(k, listmenber) = 0 Next tmpnumber2 = 1 Do tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) tmpnumber2 += 1 tmpnumber += 1 Loop Until tmpnumber >= 28 OrElse (tmptehai(tmpnumber) = 0 And tmptehai(tmpnumber + 1) = 0) tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) If tmpnumber <= 29 Then tmppatunakami(tmpnumber2 + 1, listmenber) = tmptehai(tmpnumber + 1) End If tmpnumber += 2 listmenber += 1 End If Loop Until tmpnumber >= 30 For j As Integer = 31 To 37 If tmptehai(j) >= 2 Then For k As Integer = 1 To 9 tmppatunakami(k, listmenber) = 0 Next tmppatunakami(1, listmenber) = tmptehai(j) listmenber += 1 End If Next 'パーツ分け完了 For k As Integer = 0 To listmenber - 1 hashkey = tmppatunakami(1, k) + 4 * tmppatunakami(2, k) Dim hashkey2 As Long = hashkey For j As Integer = 3 To 9 hashkey2 += 4 * 5 ^ (j - 2) * tmppatunakami(j, k) Next mentutatu(0) = hashmentusu2(hashkey2) If mentutatu(0) >= 0 Then 'ハッシュテーブルでヒット mentutatu(1) = hashkouho2(hashkey2) Else For l As Integer = 1 To 9 tmppatunakami2(l) = tmppatunakami(l, k) Next mentutatu = mentu_cut2(tmppatunakami2, 1, 0) '再帰式で計算 hashmentusu2(hashkey2) = mentutatu(0) hashkouho2(hashkey2) = mentutatu(1) End If mentu += mentutatu(0) kouho += mentutatu(1) If mentu + kouho > 4 Then kouho = 4 - mentu End If Next normal_temp = 8 - mentu * 2 - kouho - toitu normal_keshantensu = Math.Min(normal_temp, normal_keshantensu) tmptehai(i) += 2 toitu -= 1 End If Next mentu = furosu toitu = 0 kouho = 0 'パーツ分け(雀頭なし) tmpnumber = 1 listmenber = 0 For j As Integer = 1 To 10 For k As Integer = 0 To 14 tmppatunakami(j, k) = 0 Next Next Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else For k As Integer = 1 To 9 tmppatunakami(k, listmenber) = 0 Next tmpnumber2 = 1 Do tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) tmpnumber2 += 1 tmpnumber += 1 Loop Until tmpnumber >= 8 OrElse (tmptehai(tmpnumber) = 0 And tmptehai(tmpnumber + 1) = 0) tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) If tmpnumber <= 9 Then tmppatunakami(tmpnumber2 + 1, listmenber) = tmptehai(tmpnumber + 1) End If tmpnumber += 2 listmenber += 1 End If Loop Until tmpnumber >= 10 tmpnumber = 11 Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else For k As Integer = 1 To 9 tmppatunakami(k, listmenber) = 0 Next tmpnumber2 = 1 Do tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) tmpnumber2 += 1 tmpnumber += 1 Loop Until tmpnumber >= 18 OrElse (tmptehai(tmpnumber) = 0 And tmptehai(tmpnumber + 1) = 0) tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) If tmpnumber <= 19 Then tmppatunakami(tmpnumber2 + 1, listmenber) = tmptehai(tmpnumber + 1) End If tmpnumber += 2 listmenber += 1 End If Loop Until tmpnumber >= 20 tmpnumber = 21 Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else For k As Integer = 1 To 9 tmppatunakami(k, listmenber) = 0 Next tmpnumber2 = 1 Do tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) tmpnumber2 += 1 tmpnumber += 1 Loop Until tmpnumber >= 28 OrElse (tmptehai(tmpnumber) = 0 And tmptehai(tmpnumber + 1) = 0) tmppatunakami(tmpnumber2, listmenber) = tmptehai(tmpnumber) If tmpnumber <= 29 Then tmppatunakami(tmpnumber2 + 1, listmenber) = tmptehai(tmpnumber + 1) End If tmpnumber += 2 listmenber += 1 End If Loop Until tmpnumber >= 30 For j As Integer = 31 To 37 If tmptehai(j) >= 2 Then For k As Integer = 1 To 9 tmppatunakami(k, listmenber) = 0 Next tmppatunakami(1, listmenber) = tmptehai(j) listmenber += 1 End If Next 'パーツ分け完了 For k As Integer = 0 To listmenber - 1 hashkey = tmppatunakami(1, k) + 4 * tmppatunakami(2, k) Dim hashkey2 As Long = hashkey For j As Integer = 3 To 9 hashkey2 += 4 * 5 ^ (j - 2) * tmppatunakami(j, k) Next mentutatu(0) = hashmentusu2(hashkey2) If mentutatu(0) >= 0 Then 'ハッシュテーブルでヒット mentutatu(1) = hashkouho2(hashkey2) Else For l As Integer = 1 To 9 tmppatunakami2(l) = tmppatunakami(l, k) Next mentutatu = mentu_cut2(tmppatunakami2, 1, 0) '再帰式で計算 hashmentusu2(hashkey2) = mentutatu(0) hashkouho2(hashkey2) = mentutatu(1) End If mentu += mentutatu(0) kouho += mentutatu(1) If mentu + kouho > 4 Then kouho = 4 - mentu End If Next normal_temp = 8 - mentu * 2 - kouho - toitu normal_keshantensu = Math.Min(normal_temp, normal_keshantensu) Return normal_keshantensu '最終的な結果 End Function Function normalshantenfunc_game2(ByVal tehaifuroigaiakanasi() As Integer, ByVal furosu As Integer) As Integer 'メンツ手のシャンテン数を返す。(ハッシュテーブル+パーツで区切って高速化) '初期化 Dim tmppatunakami2(9) As Integer Dim mentutatu(1) As Integer Dim tmpnumber As Integer = 1 Dim tmpnumber2 As Integer = 1 Dim hashkey As Integer = 0 Dim normal_temp As Integer = 0 Dim normal_keshantensu As Integer = 8 Dim tmptehai() As Integer = tehaifuroigaiakanasi.Clone() Dim mentu As Integer Dim toitu As Integer Dim kouho As Integer For i As Integer = 1 To 37 mentu = furosu toitu = 0 kouho = 0 '頭抜き出し If tmptehai(i) >= 2 Then toitu += 1 tmptehai(i) -= 2 'パーツ分け tmpnumber = 1 '萬子 Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else tmpnumber2 = tmpnumber Do tmpnumber2 += 1 Loop Until tmpnumber2 >= 8 OrElse (tmptehai(tmpnumber2) = 0 And tmptehai(tmpnumber2 + 1) = 0) If tmpnumber2 = 8 AndAlso tmptehai(9) > 0 Then tmpnumber2 = 9 End If hashkey = tehaitolongtaiou(tmptehai, tmpnumber, tmpnumber2) If hashmentusu3.TryGetValue(hashkey, mentutatu(0)) And hashkouho3.TryGetValue(hashkey, mentutatu(1)) Then 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つかる Else 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つからない→再帰計算 For k As Integer = 1 To 9 tmppatunakami2(k) = 0 Next For k As Integer = tmpnumber To tmpnumber2 tmppatunakami2(k - tmpnumber + 1) = tmptehai(k) Next mentutatu = mentu_cut2(tmppatunakami2, 1, 0) '再帰式で計算 hashmentusu3(hashkey) = mentutatu(0) '2回目以降計算しなくていいようにハッシュテーブルに登録 hashkouho3(hashkey) = mentutatu(1) End If mentu += mentutatu(0) kouho += mentutatu(1) If mentu + kouho > 4 Then kouho = 4 - mentu End If tmpnumber = tmpnumber2 + 2 End If Loop Until tmpnumber >= 10 tmpnumber = 11 '筒子 Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else tmpnumber2 = tmpnumber Do tmpnumber2 += 1 Loop Until tmpnumber2 >= 18 OrElse (tmptehai(tmpnumber2) = 0 And tmptehai(tmpnumber2 + 1) = 0) If tmpnumber2 = 18 AndAlso tmptehai(19) > 0 Then tmpnumber2 = 19 End If hashkey = tehaitolongtaiou(tmptehai, tmpnumber, tmpnumber2) If hashmentusu3.TryGetValue(hashkey, mentutatu(0)) And hashkouho3.TryGetValue(hashkey, mentutatu(1)) Then 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つかる Else 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つからない→再帰計算 For k As Integer = 1 To 9 tmppatunakami2(k) = 0 Next For k As Integer = tmpnumber To tmpnumber2 tmppatunakami2(k - tmpnumber + 1) = tmptehai(k) Next mentutatu = mentu_cut2(tmppatunakami2, 1, 0) '再帰式で計算 hashmentusu3(hashkey) = mentutatu(0) '2回目以降計算しなくていいようにハッシュテーブルに登録 hashkouho3(hashkey) = mentutatu(1) End If mentu += mentutatu(0) kouho += mentutatu(1) If mentu + kouho > 4 Then kouho = 4 - mentu End If tmpnumber = tmpnumber2 + 2 End If Loop Until tmpnumber >= 20 tmpnumber = 21 '索子 Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else tmpnumber2 = tmpnumber Do tmpnumber2 += 1 Loop Until tmpnumber2 >= 28 OrElse (tmptehai(tmpnumber2) = 0 And tmptehai(tmpnumber2 + 1) = 0) If tmpnumber2 = 28 AndAlso tmptehai(29) > 0 Then tmpnumber2 = 29 End If hashkey = tehaitolongtaiou(tmptehai, tmpnumber, tmpnumber2) If hashmentusu3.TryGetValue(hashkey, mentutatu(0)) And hashkouho3.TryGetValue(hashkey, mentutatu(1)) Then 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つかる Else 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つからない→再帰計算 For k As Integer = 1 To 9 tmppatunakami2(k) = 0 Next For k As Integer = tmpnumber To tmpnumber2 tmppatunakami2(k - tmpnumber + 1) = tmptehai(k) Next mentutatu = mentu_cut2(tmppatunakami2, 1, 0) '再帰式で計算 hashmentusu3(hashkey) = mentutatu(0) '2回目以降計算しなくていいようにハッシュテーブルに登録 hashkouho3(hashkey) = mentutatu(1) End If mentu += mentutatu(0) kouho += mentutatu(1) If mentu + kouho > 4 Then kouho = 4 - mentu End If tmpnumber = tmpnumber2 + 2 End If Loop Until tmpnumber >= 30 For j As Integer = 31 To 37 '字牌 If tmptehai(j) >= 2 Then hashkey = tehaitolongtaiou(tmptehai, j, j) hashmentusu3.TryGetValue(hashkey, mentutatu(0)) hashkouho3.TryGetValue(hashkey, mentutatu(1)) mentu += mentutatu(0) kouho += mentutatu(1) If mentu + kouho > 4 Then kouho = 4 - mentu End If End If Next 'パーツ分け完了 normal_temp = 8 - mentu * 2 - kouho - toitu normal_keshantensu = Math.Min(normal_temp, normal_keshantensu) tmptehai(i) += 2 toitu -= 1 End If Next mentu = furosu toitu = 0 kouho = 0 'パーツ分け(雀頭なし) tmpnumber = 1 '萬子 Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else tmpnumber2 = tmpnumber Do tmpnumber2 += 1 Loop Until tmpnumber2 >= 8 OrElse (tmptehai(tmpnumber2) = 0 And tmptehai(tmpnumber2 + 1) = 0) If tmpnumber2 = 8 AndAlso tmptehai(9) > 0 Then tmpnumber2 = 9 End If hashkey = tehaitolongtaiou(tmptehai, tmpnumber, tmpnumber2) If hashmentusu3.TryGetValue(hashkey, mentutatu(0)) And hashkouho3.TryGetValue(hashkey, mentutatu(1)) Then 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つかる Else 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つからない→再帰計算 For k As Integer = 1 To 9 tmppatunakami2(k) = 0 Next For k As Integer = tmpnumber To tmpnumber2 tmppatunakami2(k - tmpnumber + 1) = tmptehai(k) Next mentutatu = mentu_cut2(tmppatunakami2, 1, 0) '再帰式で計算 hashmentusu3(hashkey) = mentutatu(0) '2回目以降計算しなくていいようにハッシュテーブルに登録 hashkouho3(hashkey) = mentutatu(1) End If mentu += mentutatu(0) kouho += mentutatu(1) If mentu + kouho > 4 Then kouho = 4 - mentu End If tmpnumber = tmpnumber2 + 2 End If Loop Until tmpnumber >= 10 tmpnumber = 11 '筒子 Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else tmpnumber2 = tmpnumber Do tmpnumber2 += 1 Loop Until tmpnumber2 >= 18 OrElse (tmptehai(tmpnumber2) = 0 And tmptehai(tmpnumber2 + 1) = 0) If tmpnumber2 = 18 AndAlso tmptehai(19) > 0 Then tmpnumber2 = 19 End If hashkey = tehaitolongtaiou(tmptehai, tmpnumber, tmpnumber2) If hashmentusu3.TryGetValue(hashkey, mentutatu(0)) And hashkouho3.TryGetValue(hashkey, mentutatu(1)) Then 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つかる Else 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つからない→再帰計算 For k As Integer = 1 To 9 tmppatunakami2(k) = 0 Next For k As Integer = tmpnumber To tmpnumber2 tmppatunakami2(k - tmpnumber + 1) = tmptehai(k) Next mentutatu = mentu_cut2(tmppatunakami2, 1, 0) '再帰式で計算 hashmentusu3(hashkey) = mentutatu(0) '2回目以降計算しなくていいようにハッシュテーブルに登録 hashkouho3(hashkey) = mentutatu(1) End If mentu += mentutatu(0) kouho += mentutatu(1) If mentu + kouho > 4 Then kouho = 4 - mentu End If tmpnumber = tmpnumber2 + 2 End If Loop Until tmpnumber >= 20 tmpnumber = 21 '索子 Do If tmptehai(tmpnumber) = 0 Then tmpnumber += 1 Else tmpnumber2 = tmpnumber Do tmpnumber2 += 1 Loop Until tmpnumber2 >= 28 OrElse (tmptehai(tmpnumber2) = 0 And tmptehai(tmpnumber2 + 1) = 0) If tmpnumber2 = 28 AndAlso tmptehai(29) > 0 Then tmpnumber2 = 29 End If hashkey = tehaitolongtaiou(tmptehai, tmpnumber, tmpnumber2) If hashmentusu3.TryGetValue(hashkey, mentutatu(0)) And hashkouho3.TryGetValue(hashkey, mentutatu(1)) Then 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つかる Else 'ハッシュテーブルから検索→メンツ数メンツ候補数の組が見つからない→再帰計算 For k As Integer = 1 To 9 tmppatunakami2(k) = 0 Next For k As Integer = tmpnumber To tmpnumber2 tmppatunakami2(k - tmpnumber + 1) = tmptehai(k) Next mentutatu = mentu_cut2(tmppatunakami2, 1, 0) '再帰式で計算 hashmentusu3(hashkey) = mentutatu(0) '2回目以降計算しなくていいようにハッシュテーブルに登録 hashkouho3(hashkey) = mentutatu(1) End If mentu += mentutatu(0) kouho += mentutatu(1) If mentu + kouho > 4 Then kouho = 4 - mentu End If tmpnumber = tmpnumber2 + 2 End If Loop Until tmpnumber >= 30 For j As Integer = 31 To 37 '字牌 If tmptehai(j) >= 2 Then hashkey = tehaitolongtaiou(tmptehai, j, j) hashmentusu3.TryGetValue(hashkey, mentutatu(0)) hashkouho3.TryGetValue(hashkey, mentutatu(1)) mentu += mentutatu(0) kouho += mentutatu(1) If mentu + kouho > 4 Then kouho = 4 - mentu End If End If Next 'パーツ分け完了 normal_temp = 8 - mentu * 2 - kouho - toitu normal_keshantensu = Math.Min(normal_temp, normal_keshantensu) Return normal_keshantensu '最終的な結果 End Function Function totalshantenfunc_game(ByVal tehaiakanasi() As Integer, ByVal furosu As Integer) As Integer() '現在のシャンテン数を返す(0-最小、1-国士、2-チートイ、3-メンツ手) Dim imashan(3) As Integer imashan(0) = 100 imashan(1) = 100 imashan(2) = 100 imashan(3) = 100 If furosu = 0 Then imashan(1) = kokusishantensu_game(tehaiakanasi, furosu) imashan(2) = titoishantensu_game(tehaiakanasi, furosu) End If imashan(3) = normalshantenfunc_game(tehaiakanasi, furosu) imashan(0) = Math.Min(imashan(1), Math.Min(imashan(2), imashan(3))) Return imashan End Function Function totalshantenfunc_game2(ByVal tehaiakanasi() As Integer, ByVal furosu As Integer) As Integer() '現在のシャンテン数を返す(0-最小、1-国士、2-チートイ、3-メンツ手) Dim imashan(3) As Integer imashan(0) = 100 imashan(1) = 100 imashan(2) = 100 imashan(3) = 100 If furosu = 0 Then imashan(1) = kokusishantensu_game(tehaiakanasi, furosu) imashan(2) = titoishantensu_game(tehaiakanasi, furosu) End If imashan(3) = normalshantenfunc_game2(tehaiakanasi, furosu) imashan(0) = Math.Min(imashan(1), Math.Min(imashan(2), imashan(3))) Return imashan End Function Function mentu_cut2(ByVal patunakami() As Integer, ByVal primenumber As Integer, ByVal genmentu As Integer) As Integer() 'パーツの中身と先頭文字と現在メンツ数が引数、patukekka(0)がメンツ数、patukekka(1)がメンツ候補数の返り値 'メンツの抜き出し Dim patukekka(1) As Integer Dim patukekka2(1) As Integer Dim tmppatunakami(9) As Integer For i As Integer = 1 To 9 tmppatunakami(i) = patunakami(i) Next patukekka(0) = genmentu '初期化 patukekka(1) = 0 Do While primenumber < 10 AndAlso tmppatunakami(primenumber) = 0 primenumber += 1 Loop If primenumber = 10 Then patukekka2(0) = genmentu patukekka2(1) = tatu_cut2(tmppatunakami, 1, genmentu, 0) 'メンツを抜き終わったので塔子抜きへ If patukekka2(0) > patukekka(0) Then patukekka = patukekka2 'より多くのメンツを塔子を抜けたので結果を更新 ElseIf patukekka2(0) = patukekka(0) AndAlso patukekka2(0) * 2 + patukekka2(1) > patukekka(0) * 2 + patukekka(1) Then patukekka = patukekka2 'より多くのメンツを塔子を抜けたので結果を更新 Else End If Return patukekka End If If tmppatunakami(primenumber) >= 3 Then '刻子 tmppatunakami(primenumber) -= 3 patukekka2 = mentu_cut2(tmppatunakami, primenumber, genmentu + 1) If patukekka2(0) > patukekka(0) Then patukekka = patukekka2 'より多くのメンツを塔子を抜けたので結果を更新 ElseIf patukekka2(0) = patukekka(0) AndAlso patukekka2(0) * 2 + patukekka2(1) > patukekka(0) * 2 + patukekka(1) Then patukekka = patukekka2 'より多くのメンツを塔子を抜けたので結果を更新 End If tmppatunakami(primenumber) += 3 End If If primenumber <= 7 AndAlso tmppatunakami(primenumber + 1) >= 1 AndAlso tmppatunakami(primenumber + 2) >= 1 Then 'シュンツ tmppatunakami(primenumber) -= 1 tmppatunakami(primenumber + 1) -= 1 tmppatunakami(primenumber + 2) -= 1 patukekka2 = mentu_cut2(tmppatunakami, primenumber, genmentu + 1) If patukekka2(0) > patukekka(0) Then patukekka = patukekka2 'より多くのメンツを塔子を抜けたので結果を更新 ElseIf patukekka2(0) = patukekka(0) AndAlso patukekka2(0) * 2 + patukekka2(1) > patukekka(0) * 2 + patukekka(1) Then patukekka = patukekka2 'より多くのメンツを塔子を抜けたので結果を更新 End If tmppatunakami(primenumber) += 1 tmppatunakami(primenumber + 1) += 1 tmppatunakami(primenumber + 2) += 1 End If patukekka2 = mentu_cut2(tmppatunakami, primenumber + 1, genmentu) 'メンツなしと仮定 If patukekka2(0) > patukekka(0) Then patukekka = patukekka2 'より多くのメンツを塔子を抜けたので結果を更新 ElseIf patukekka2(0) = patukekka(0) AndAlso patukekka2(0) * 2 + patukekka2(1) > patukekka(0) * 2 + patukekka(1) Then patukekka = patukekka2 'より多くのメンツを塔子を抜けたので結果を更新 End If Return patukekka End Function Function tatu_cut2(ByVal patunakami() As Integer, ByVal primenumber As Integer, ByVal genmentu As Integer, ByVal genkoho As Integer) As Integer 'パーツの中身と先頭文字と現在メンツ候補数が引数、patukekkaがメンツ候補数の返り値 Dim patukekka As Integer = genkoho Dim patukekka2 As Integer = 0 Dim tmppatunakami(9) As Integer For i As Integer = 1 To 9 tmppatunakami(i) = patunakami(i) Next Do While primenumber < 10 AndAlso tmppatunakami(primenumber) = 0 primenumber += 1 Loop If primenumber = 10 Then Return genkoho '抜き出し終了 End If '対子 If tmppatunakami(primenumber) = 2 Then tmppatunakami(primenumber) -= 2 patukekka2 = tatu_cut2(tmppatunakami, primenumber, genmentu, genkoho + 1) If patukekka2 > patukekka Then patukekka = patukekka2 End If tmppatunakami(primenumber) += 2 End If 'ペンチャンor両面 If primenumber <= 8 AndAlso tmppatunakami(primenumber + 1) >= 1 Then tmppatunakami(primenumber) -= 1 tmppatunakami(primenumber + 1) -= 1 patukekka2 = tatu_cut2(tmppatunakami, primenumber, genmentu, genkoho + 1) If patukekka2 > patukekka Then patukekka = patukekka2 End If tmppatunakami(primenumber) += 1 tmppatunakami(primenumber + 1) += 1 End If 'カンチャン If primenumber <= 7 AndAlso tmppatunakami(primenumber + 2) >= 1 Then tmppatunakami(primenumber) -= 1 tmppatunakami(primenumber + 2) -= 1 patukekka2 = tatu_cut2(tmppatunakami, primenumber, genmentu, genkoho + 1) If patukekka2 > patukekka Then patukekka = patukekka2 End If tmppatunakami(primenumber) += 1 tmppatunakami(primenumber + 2) += 1 End If patukekka2 = tatu_cut2(tmppatunakami, primenumber + 1, genmentu, genkoho) If patukekka2 > patukekka Then patukekka = patukekka2 End If Return patukekka End Function Function tehaitolongtaiou(ByVal tehaifiakaari() As Integer, ByVal startnumber As Integer, ByVal endnumber As Integer) As Long '手牌int型配列をstartnumber~endnumberの間でlong型に変換 '例 引数{1,1,0,2}→(2進数で)10101100→(10進数で)172 '1と1の間にある0の個数が手牌の枚数…最上位に1を置いて、先頭は1枚なので01、2番目が1枚なので01、3番目が0枚なので1、最後尾が2枚なので00、の順で2進数を並べる '異なる牌姿であれば必ず異なる戻り値を返す。 Dim kekka As Long = 0 Dim tmp2sinketa As Integer = 0 For i As Integer = startnumber To endnumber kekka = kekka << 1 kekka += 1 kekka = kekka << tehaifiakaari(i) Next Return kekka End Function End Module