第二ペアプログラミングジョブ(コピー)

第二の対ジョブ

始まりのリンク

チームメイト
のGithubリポジトリ

序文

私は麻雀を好みます。

労働者の特定の部門

秋チャン傑:バックエンド
日チェン甲斐:フロントエンドは、
労働力の非常にシンプルな部門です。


PSPテーブル

PSP2.1 パーソナルソフトウェアプロセス段階 推定時間がかかる(分) 実際の時間がかかる(分)
プランニング 計画 120 80
推計 このタスクが必要とどのくらいの時間を見積もります 120 80
開発 開発 2990 3330
分析 (新しい技術を学ぶ含む)ニーズ分析 60 60
デザインスペック 設計ドキュメントの生成 30 30
デザインレビュー デザインレビュー 30 30
標準コーディング コードの仕様(開発のための適切な規範の開発) 30 180
設計 具体的な設計 180 240
コーディング 具体的なコーディング 2500 2550
コードレビュー コードレビュー 60 120
テスト 検査(セルフテスト、修正、変更をコミット) 100 120
報告 レポート 80 100
試験報告書 テストレポート 30 30
サイズ測定 コンピューティングのワークロード 10 10
死後&プロセス改善計画 後知恵とは、プロセス改善計画を提案します 40 60
トータル 3190 3510

問題解決のためのアイデアの説明や解説の設計と実装

ネットワークインタフェースを使用します

次のように処理上の考慮事項のため、便宜上、上流のモジュール永福アクセスサーバからのpython安らかAPI要求を使用し、5つの機能で包装します。

インタフェース機能 機能
ログインする ログオン要求を送信します
登録 登録要求を送信します
find_info 情報戦争の問い合わせ
順位 ランキングを見ます
Srank 戦争の個人的なリストへのアクセス

内部コードの組織の設計と実現

支度をしています

我々が検討中のターゲットは現在、私たちの手を入れると13枚のカードを取得したときに最大のブランドを考えると、他の人が置くことができないなどの対象の設計プロセスの開始前に、私たちのチームは、いくつかの簡単な数学的分析を行います私たちは、現在のカードを置くよりも、より。この状態では、我々はその後、T / N、カードの種類がいくつかの他のカードタイプがトンで再生することができ入れ、カードタイプNの合計数を設定することができ、単にデッキの理想的な勝率考えることができます。

\ [C = \ FRAC {T} {N} \]

重みはシンプルに設定することができます

\ [\ LG(\ FRAC {N} {N T})= W]

また、考慮すべき相手の手の中に表示されますが、多くの場合ではない意思決定を行うためのカードの手だけを考慮するのに十分な、確率は私達のカード型の組み合わせよりも優れていることができ、我々はこの確率がSに設定されている参照してください。C×(1-S)は、比較的単純でデッキの成功率と考えることができます。

\ [P = C *(1-S)\]

多くの場合、Cが大きい場合、sの小さい、これは証明されていません。

ここでは、アルゴリズムの実装プロセスは、次のとおりです。

準備:底に時間を節約して、構築することができ利用できる図書館カードの書かれた基本的な枠組みを探して、ここにポーカーと呼ばれる非常に簡単なサードパーティのライブラリです。中国の文書、各カードの初期化の最も単純なを使用して。前端と後端のpythonを使用して達成されて、私はこれのPyQtでフロントページを達成するために前例のないHTML + CSSを使用した唯一の先端接触を書き込むために使用しました。

最初のステップ:事前にライセンス重みと各種製剤の種類ごとleveldictフラグを定義

レディ機能 機能
make_suit カラー辞書の現在のハンドを取得
make_rank カード値のdictの現在のハンドを取得
Weight_init 行列ブランドの重みの初期化
Times_init 初期化好奇心行列の重み
Compare_down 二枚のカード最初の桟橋の大きさの比較
Compare_up (注ぐかどうかをカード2 Sandunのデッキに相当する)は、2枚のカードの比較第二又は第三の桟橋桟橋サイズ
Compare_gap 水を注ぐ場合は第一及び第二桟橋桟橋のカードのデッキを比較
Compare_combo 勝ち負けの計算完全に2枚のカード

ヒント:そのような最初のカードタイプなどの量(に接続)は、第2のピア3第三のピア5(ストレート)の0埠頭(サン・カード)であり、重量[0] [3] [5]に初期化されます(0 + 3 + 5)/ 100そう他。各位置のための好奇心の重みは、それが使用されている場合、トレーニングによって、多分、その後、1に初期化されます。

ステップ2:実際DFSクラス、0-4は、3枚のカードを散乱する可能性があるすべての可能な(最初の桟橋グレードを通じて何の脳ではない、ストレートフラッシュに最初の0-9二桟橋散乱されるカードがあるかもしれませんSandunの共感)を描くことができるボードの現在の組成物の種類の5×10×10個の可能な組み合わせの合計

类一:choose_action_option(Hand,color_dict,rank_dict)
参数:手牌和前面两个函数得到的两个dict
功能:根据当前手牌给出各种牌型的dict
返回:
在这里插入图片描述

类内方法 功能 返回
Flush_Collection 判断同花顺 同花顺花色和该顺最后一张牌牌值的list
Bomb 判断炸弹 炸弹牌牌值的list
Gourd 判断葫芦 葫芦牌中三条部分和可能的所有对子组成的list
Flush 判断同花 同花的花色牌和能组成同花的5张牌中最大的牌值
Collection 判断顺子 该顺最后一张牌牌值的list
Three 判断三条 三条牌牌值的list
Pair 判断对子 对子牌牌值的list

Tips:此处后面为什么是函数而不是类了呢。。当然是因为方便调试!(懒得写了。函数比较方便。。)

主要函数 功能 返回
choose_step_sb(choose_) 根据类返回的dict返回所有可能的牌型 包含了0-9所有可能牌型的dict
action_step_sb(Hand,choose_,shape,rank,suit) 根据牌型dict对当前手牌进行更改 某墩的牌型和剩下的手牌
action_step_add(Hand_three,Hand_two,Hand_rest,shape,rank,suit) 将三墩牌完善 包含了三墩牌和各自牌型大小的dict
judge_right 判断牌型的合理性 True表示该三墩牌摆的合法

Tips:这里仅仅获得了手牌的一种排法的dict,包含了三墩的牌和各自的大小

第三步:由第二步得到的各种牌型可能训练权重

没错!这里我还是因为方便调试!只写了一个函数来训练它,甚至都没脸画表了!
主要函数:begin_game(myhand_need,Weight,Times,beta,is_Train,Auto,b,real)

参数 说明
Weight 牌型矩阵,决定了选某种牌型组合的可能性
Times 好奇心の行列は、各ブランドのトレーニングが発生した回数を記録します
ベータ 私は頻繁に減少トレーニング時間のカードタイプについての好奇心のいくつかの種類を使用し、好奇心カットインデックスの名前
is_Train それはトレーニングの状況、真の訓練であるかどうか、Falseのときに、現在可能な最大出力カードタイプ
オート トレーニングマニュアルまたは自動のトレーニング
B 他の人の場合は理事会、他の3枚のカードのis_Trainと比較した場合、そうでない場合はなし
リアル それは、実際のゲームシーンがあるかどうか

開始するには精神遅滞からの訓練の最初のステップ、:法律上の最初の行は、第三埠頭から何の脳、無トリック脳の二大種類の最大値を取得しないための第二段階にする必要があり、他の3枚のカードをテーブルの上にカードです手の兄弟とすべての組み合わせによる無脳、自分自身との巨大な放電は勝ち負けがあるの重みを変更するには(おそらくバックと呼ばれるように値しない)へのご褒美の復帰に応じて、大幅に比較的大きな脳ずに排出することができます。
第二段階のトレーニング、IQの使用は、知的障害ビート:テーブルの上に、より合理的な重み行列を取得するための最初のステップの完了後にトレーニング、真=真の調整、他の3枚のカードがまだかなり大きいですが、彼らは既存のカードの種類に基づいています可能な最大放電結果は兄弟リターンでデッキとの比較を見つけるためにカード型の行列に行きます。
第三段階のトレーニング、IQビートIQの使用、4人が、あなたの手札からカードの右のタイプを探しているテーブルには、回帰を最大重み行列カードタイプを緩和することがあります。
ヒント:水の勝ち負けされる報酬
の戻り道を:

\ [R =(S)* \ FRAC {β}は{\ SQRT {N(S)}} \]

数r(S)すなわち、水を勝ち負け、β即ち好奇心低下指数、N(S)即ち、行列メモリタイムズ

実行されるアルゴリズムのフローチャートの説明のキーとキー部

2つの初期機能の辞書を介して得られた辞書とカラーカード値


各カードタイプの辞書を介して取得choose_step_sb(またはなし)

action_step_sbとaction_step_add振り子のメソッドを介してカードの完全なデッキを取得

この振り子方式の正当性を介して取得Judge_right

トレーニングを開始するには正当なことです。

前端と後端の残りの部分

次のようにメインページのフロントエンドが分割されます

インターフェイスと独立PY、統一されたファイルmain.py、mainBox単一多形主催ファイルに対応するクラス。

インターフェース クラス名
ログインして歓迎 指数
登録 登録
主なインタフェース Naenindeksh
クエリーインターフェイス 調べる
自动出牌结果界面 ResultSingle
战局信息界面 Result
个人中心 Home
排行榜 Rank
个人战绩 SingleRank

与后端的接口如下:

接口函数 功能
login 登陆验证
register 注册
play 进行自动游戏
find_infp 查看战局信息
rank 查看排行榜
srank 查看个人记录

最终效果如下:
由于上传大小限制,拆分成5个部分来演示。







关键代码解释

算法

reward = 0
#得出手牌和牌桌其他人的输赢水
reward += Compare_Combo(finish_hand,b[0]) 
reward += Compare_Combo(finish_hand,b[1])
reward += Compare_Combo(finish_hand,b[2])
#好奇心衰减水
reward = reward * ((beta)/math.sqrt(Times[int(shape_1)][int(shape_2)][int(shape_3)]))
Times[int(shape_1)][int(shape_2)][int(shape_3)]+=1
#回归更改权重
Weight[int(shape_1)][int(shape_2)][int(shape_3)]+=(int(reward)/1000)

前端:

 # 登陆界面切换主界面
ind.show_mainindex_sg.connect(show_mainindex)
# 登陆界面切换注册界面
ind.show_register_sg.connect(show_register)
# 注册界面切登陆界面
regind.register_ok_sg.connect(register_ok)
# 主界面切自动对战
mainind.auto_pressed_sg.connect(show_result)
# 主界面切用户中心
mainind.home_pressed_sg.connect(show_home)
# 主界面切搜索
mainind.search_pressed_sg.connect(show_search)
# 搜索切结果
searchind.search_sg.connect(show_id)
# 搜索返回
searchind.back_sg.connect(back_off)
# 自动对战返回
sresultind.result_exit_sg.connect(sresult_exit)
# 结果返回
resultind.result_exit_sg.connect(result_exit)
# 用户中心返回
homeind.home_exit_sg.connect(home_exit)
# 用户中心切排行榜
homeind.rank_sg.connect(show_rank)
# 用户中心切个人战绩
homeind.single_rank_sg.connect(show_single_rank)
# 排行榜返回
rankind.rk_comeback_sg.connect(rank_exit)
# 个人战绩返回
sgrankind.single_rk_comeback_sg.connect(single_rank_exit)
# 详情
sgrankind.detail_sg.connect(show_de)
sys.exit(app.exec())

后端:

def play(token):
    for i in range(1):
        try:
            url = "https://api.shisanshui.rtxux.xyz/game/open"
            headers = {'x-auth-token': token}
            response = requests.request("POST", url, headers=headers)
            result = response.text.encode("utf8")
            result = json.loads(result)
            print(result)
            id = result['data']['id']
            card = result['data']['card']
            card = card.replace("10", 'T')
            card = card.replace("*", '@')
            hand_card = card.split()
            url = "https://api.shisanshui.rtxux.xyz/game/submit"
            Weight = pickle.load(open('./resource/model/a.txt', 'rb'))
            Times = pickle.load(open('./resource/model/b.txt', 'rb'))
            beta = 0.9
            myhand = []
            for i in range(13):
                myhand.append(Card(str(hand_card[i][1]) + str(hand_card[i][0])))
            print(myhand)
            myhand.sort()
            b = Game.begin_game(myhand, Weight, Times, beta, is_Train=False, Auto=False, b=None, real=True)
            three = b['level_3'][0]
            shape_3 = b['level_3'][1]
            two = b['level_2'][0]
            shape_2 = b['level_2'][1]
            one = b['level_1'][0]
            shape_1 = b['level_1'][1]
            a = []
            c = ''
            for i in range(3):
                c = c + str(one[i])[1] + str(one[i])[0]
                if (i != 2):
                    c += ' '
            c = c.replace("T", '10')
            c = c.replace("@", '*')
            a.append(c)
            c = ''
            for i in range(5):
                c = c + str(two[i])[1] + str(two[i])[0]
                if (i != 4):
                    c += ' '
            c = c.replace("T", '10')
            c = c.replace("@", '*')
            a.append(c)
            c = ''
            for i in range(5):
                c = c + str(three[i])[1] + str(three[i])[0]
                if (i != 4):
                    c += ' '
            c = c.replace("T", '10')
            c = c.replace("@", '*')
            a.append(c)
            payload = str({'id': id, 'card': a})
            payload = payload.replace(': ', ':')
            payload = payload.replace(', ', ',')
            payload = payload.replace("'", '"')
            headers = {
                'content-type': "application/json",
                'x-auth-token': token
            }
            response = requests.request("POST", url, data=payload, headers=headers)
            result = response.text.encode("utf8")
            result = json.loads(result)
            status = result['status']
            msg = result['data']['msg']
            if (msg != 'Success'):
                print("11111111111")
                print(myhand)
                print(three)
                print(two)
                print(one)
                break
            flag_hand = []
            for i in range(13):
                f = str(myhand[i])
                q = str(f[1]) + str(f[0])
                q = q.replace("T", '10')
                flag_hand.append(q)
        except:
            need = {'status': 1}
            print(need)
            return need
        need = {'status': status, 'id': id, 'msg': msg, 'origin_cards': flag_hand, 'cards': []}

        flag_one = []
        for i in range(3):
            a = str(one[i])
            b = a[1] + a[0].replace("T", '10')
            flag_one.append(b)
        flag_two = []
        for i in range(5):
            a = str(two[i])
            b = a[1] + a[0].replace("T", '10')
            flag_two.append(b)
        flag_three = []
        for i in range(5):
            a = str(three[i])
            b = a[1] + a[0].replace("T", '10')
            flag_three.append(b)
        flag = {'lv': level_dict[str(shape_1)], 'card': flag_one}
        need['cards'].append(flag)
        flag = {'lv': level_dict[str(shape_2)], 'card': flag_two}
        need['cards'].append(flag)
        flag = {'lv': level_dict[str(shape_3)], 'card': flag_three}
        need['cards'].append(flag)
        print(need)
        return need

性能分析与改进

描述你改进的思路

1.最开始的回归方式是单纯根据输赢水/100,这样可能会使一些很少遇到的情况出现偏差,它本来应该比另外一种经常出现的大,可经常出现的牌型出现的次数过多导致过分更改它的权重产生误判,所以使用了最近用来解决RL中sparse reward问题的好奇心的方法(其实就是个最简单的计数)。
2.因为由表得出make_suit也就是遍历得到花色dict的函数是最耗时的,估计因为是每次手牌的预处理都有用到它,所以第一墩13张牌时仍让它遍历,第二墩8张牌时就从先前的dict减去少掉5张牌的花色,第三墩类似,会稍微减少一点时间
3.在训练完十万个单位后,为了减少训练时间,不用让它遍历每种情况,只要是它经过的情况都用一个矩阵来标1,下次就不用再次访问同样牌型的情况
4.前端则是由于py的特性,导致本身启动时间较慢,唯一想到的解决方法是减少初始加载的模块数或者用c编写系统接口。
5.只有有网络请求,则网络请求部分往往是耗时最大的,该次作业也是一样。

展示性能分析图和程序中消耗最大的函数

万万没想到居然是make_suit。这玩意不就遍历个手牌把花色记录下来居然花这么多时间。惊了。

单元测试

覆盖率

poker是用来初始化卡牌的基础库,这个就不关键了,可见控制出牌发牌逻辑的Game的覆盖率是87,虽然低但还算勉强。

Github的代码签入记录。

Github readme

遇到的代码模块异常或结对困难及解决方法

问题描述(2分)

1.手牌合法性检测
2.因为是遍历手牌牌型的所有情况,两种情况的两副牌有可能出现某一墩完全一样的情况,无法比较大小。
3.底层poker库的Card类型和接口提供的卡牌样式完全不同,本身花色类型和前端接口也是八字不合,会出现❤这种无法保存的现象
4.网络请求失败导致整个程序崩溃。
5.多界面切换的挂起导致的内存损耗。
6.队友的屁股真的翘

做过哪些尝试(2分)

1.本来是想写一个判断手牌牌型和最大牌大小的顺便也方便前端,但因为后面训练的时候需要进行两副牌输赢水的计算,干脆就把每墩之间的比较独立写出,若合法情况则是第三墩赢第二墩,第二墩赢第一墩,这种牌型就是合法的。
2.根据鸵鸟算法,那么我们就把它........直接返回不输不赢吧
3.手动更改底层库
4.增加异常处理
5.修改控件件的父子关系。

是否解决(2分)

1.解决了
2.根据鸵鸟算法,解决了
3.解决了,哭了
4.解决了
5.不完美解决

有何收获(2分)

1.大千世界无奇不有,换种思路展开新世界
2.操作系统教会了我们非常关键的一种算法,使我受益良多
3.在开展项目前因先沟通好前后端的接口设计问题,同时将功能合理区分开,降低耦合度。
4.完成不使用ps纯手码前端成就。

评价你的队友

值得学习的地方(2分)

1.你是小队之光
2.你是天选之子
3.你是人工智障带师
4.你是力量的象征
5.敏捷,果敢
6.速度很快
7.屁股真的翘

需要改进的地方(2分)

1.别用jupyter开发这种项目了,会死人了。

学习进度条

学习表

第N周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
1 407 407 15 15 学到了十三水的玩法,了解了原型设计工具的使用方法
2 230 637 14 14 制定了基本实现思想和前端窗体框架
3 1200 1837 20 20 实现基本交互逻辑
4 1045 2882 20 20 实现接口对接和后端处理

牢骚

单说算法,采用这样一个算法其实只是个尝试,十三水这个游戏本身的决策不算复杂,单一情况下的所有解也比较的少,正确率最高的解法应该还是根据胜率去穷举最好,在这方面ai所体现的优势便没有那么明显,当然本身训练过程也发现某些牌型出现的情况较少,导致对其的权重较低,而往往出现概率小的牌是更大的牌,这就很危险了,所以在开始引入数学模型的基础权值再进行调整。还是偶尔能看到一些权值系统下天马行空的想法的。
再说设计本身,我们接口的设计比较的简洁,也减少了各自开发的难度,各司其职,干扰较少。前端用了PyQt,emmm,怎么说,有优有劣,我可能会更喜欢html+css的组合,qss本身作为类似css的样式表,其选择器和功能都些许不如css,总之还是不错的,曾经几度按下自己想打开ps的手,最后还是去画了一张背景出来。

おすすめ

転載: www.cnblogs.com/pullself/p/11710790.html