From c54ec17dfc5db5aef1cd1b9342fc04f220e61ebf Mon Sep 17 00:00:00 2001 From: Wang Chengke Date: Sun, 12 Apr 2020 11:47:21 +0800 Subject: [PATCH 01/10] [webapi] add (tenhou only) --- core.go | 8 ++++++++ server.go | 12 ++++++++++++ webapi/data.go | 14 ++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 webapi/data.go diff --git a/core.go b/core.go index 3ec5f60..cb31b2e 100644 --- a/core.go +++ b/core.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "github.com/EndlessCheng/mahjong-helper/webapi" "github.com/EndlessCheng/mahjong-helper/util" "github.com/EndlessCheng/mahjong-helper/util/model" "github.com/fatih/color" @@ -167,6 +168,8 @@ func (p *playerInfo) doraNum(doraList []int) (doraCount int) { // type roundData struct { + ApiData webapi.ApiData + parser DataParser gameMode gameMode @@ -470,6 +473,10 @@ func (d *roundData) newModelPlayerInfo() *model.PlayerInfo { } func (d *roundData) analysis() error { + defer func() { + d.ApiData.Counts = d.counts + }() + if !debugMode { defer func() { if err := recover(); err != nil { @@ -854,6 +861,7 @@ func (d *roundData) analysis() error { // 安全度分析 riskTables := d.analysisTilesRisk() mixedRiskTable := riskTables.mixedRiskTable() + d.ApiData.RiskTable = mixedRiskTable // 牌谱分析模式下,记录可能的鸣牌 if d.gameMode == gameModeRecordCache { diff --git a/server.go b/server.go index 432d113..7897498 100644 --- a/server.go +++ b/server.go @@ -74,6 +74,17 @@ func (h *mjHandler) index(c echo.Context) error { return c.String(http.StatusOK, time.Now().Format("2006-01-02 15:04:05")) } +// 以 JSON 格式返回游戏相关信息 +func (h *mjHandler) apiGetStatus(c echo.Context) error { + data := h.tenhouRoundData.ApiData + b, err := json.Marshal(data) + if err != nil { + h.logError(err) + return c.String(http.StatusBadRequest, err.Error()) + } + return c.String(http.StatusOK, string(b[:])) +} + // 打一摸一分析器 func (h *mjHandler) analysis(c echo.Context) error { if h.analysing { @@ -521,6 +532,7 @@ func runServer(isHTTPS bool, port int) (err error) { e.Use(middleware.Recover()) e.Use(middleware.CORS()) e.GET("/", h.index) + e.GET("/api", h.apiGetStatus) e.POST("/debug", h.index) e.POST("/analysis", h.analysis) e.POST("/tenhou", h.analysisTenhou) diff --git a/webapi/data.go b/webapi/data.go new file mode 100644 index 0000000..a3ff33f --- /dev/null +++ b/webapi/data.go @@ -0,0 +1,14 @@ +package webapi + +type ApiData struct { + // 数据更新时间戳 + Timestamp int `json:"timestamp"` + + // 自家手牌 一个长度为 34 的整数数组 + Counts []int `json:"counts"` + + // 手牌危险度 一个长度为 34 的浮点数组 + RiskTable []float64 `json:"risk"` +} + + From 7b7b21c26d6649b7c2e56c510bdd4b3b8d1d884d Mon Sep 17 00:00:00 2001 From: Wang Chengke Date: Sun, 12 Apr 2020 12:50:03 +0800 Subject: [PATCH 02/10] [webapi] add html & js for front-end --- server.go | 2 + webapi/core.js | 119 ++++++++++++++++++++++++++++++++++++++++++++++ webapi/img/0m.png | Bin 0 -> 3001 bytes webapi/img/0p.png | Bin 0 -> 3404 bytes webapi/img/0s.png | Bin 0 -> 2899 bytes webapi/img/1m.png | Bin 0 -> 1345 bytes webapi/img/1p.png | Bin 0 -> 2740 bytes webapi/img/1s.png | Bin 0 -> 3293 bytes webapi/img/1z.png | Bin 0 -> 1282 bytes webapi/img/2m.png | Bin 0 -> 1489 bytes webapi/img/2p.png | Bin 0 -> 1972 bytes webapi/img/2s.png | Bin 0 -> 846 bytes webapi/img/2z.png | Bin 0 -> 1339 bytes webapi/img/3m.png | Bin 0 -> 1630 bytes webapi/img/3p.png | Bin 0 -> 1953 bytes webapi/img/3s.png | Bin 0 -> 1147 bytes webapi/img/3z.png | Bin 0 -> 1069 bytes webapi/img/4m.png | Bin 0 -> 1707 bytes webapi/img/4p.png | Bin 0 -> 2088 bytes webapi/img/4s.png | Bin 0 -> 1401 bytes webapi/img/4z.png | Bin 0 -> 1001 bytes webapi/img/5m.png | Bin 0 -> 1842 bytes webapi/img/5p.png | Bin 0 -> 2777 bytes webapi/img/5s.png | Bin 0 -> 1610 bytes webapi/img/5z.png | Bin 0 -> 114 bytes webapi/img/6m.png | Bin 0 -> 1735 bytes webapi/img/6p.png | Bin 0 -> 2153 bytes webapi/img/6s.png | Bin 0 -> 1314 bytes webapi/img/6z.png | Bin 0 -> 1561 bytes webapi/img/7m.png | Bin 0 -> 1585 bytes webapi/img/7p.png | Bin 0 -> 2833 bytes webapi/img/7s.png | Bin 0 -> 1639 bytes webapi/img/7z.png | Bin 0 -> 856 bytes webapi/img/8m.png | Bin 0 -> 1515 bytes webapi/img/8p.png | Bin 0 -> 2578 bytes webapi/img/8s.png | Bin 0 -> 1989 bytes webapi/img/9m.png | Bin 0 -> 1632 bytes webapi/img/9p.png | Bin 0 -> 3082 bytes webapi/img/9s.png | Bin 0 -> 1993 bytes webapi/index.html | 19 ++++++++ 40 files changed, 140 insertions(+) create mode 100644 webapi/core.js create mode 100755 webapi/img/0m.png create mode 100755 webapi/img/0p.png create mode 100755 webapi/img/0s.png create mode 100755 webapi/img/1m.png create mode 100755 webapi/img/1p.png create mode 100755 webapi/img/1s.png create mode 100755 webapi/img/1z.png create mode 100755 webapi/img/2m.png create mode 100755 webapi/img/2p.png create mode 100755 webapi/img/2s.png create mode 100755 webapi/img/2z.png create mode 100755 webapi/img/3m.png create mode 100755 webapi/img/3p.png create mode 100755 webapi/img/3s.png create mode 100755 webapi/img/3z.png create mode 100755 webapi/img/4m.png create mode 100755 webapi/img/4p.png create mode 100755 webapi/img/4s.png create mode 100755 webapi/img/4z.png create mode 100755 webapi/img/5m.png create mode 100755 webapi/img/5p.png create mode 100755 webapi/img/5s.png create mode 100755 webapi/img/5z.png create mode 100755 webapi/img/6m.png create mode 100755 webapi/img/6p.png create mode 100755 webapi/img/6s.png create mode 100755 webapi/img/6z.png create mode 100755 webapi/img/7m.png create mode 100755 webapi/img/7p.png create mode 100755 webapi/img/7s.png create mode 100755 webapi/img/7z.png create mode 100755 webapi/img/8m.png create mode 100755 webapi/img/8p.png create mode 100755 webapi/img/8s.png create mode 100755 webapi/img/9m.png create mode 100755 webapi/img/9p.png create mode 100755 webapi/img/9s.png create mode 100644 webapi/index.html diff --git a/server.go b/server.go index 7897498..ee18044 100644 --- a/server.go +++ b/server.go @@ -538,6 +538,8 @@ func runServer(isHTTPS bool, port int) (err error) { e.POST("/tenhou", h.analysisTenhou) e.POST("/majsoul", h.analysisMajsoul) + e.Static("/web", "webapi") + // code.js 也用的该端口 if port == 0 { port = defaultPort diff --git a/webapi/core.js b/webapi/core.js new file mode 100644 index 0000000..e11859f --- /dev/null +++ b/webapi/core.js @@ -0,0 +1,119 @@ +"use strict"; + +function tile_img_url(index) { + function label(index) { + let offset = [0, 9, 18, 27, 34]; + let l = ["m", "s", "p", "z"]; + + for (let i = 0; i < l.length; i++) { + if (index < offset[i+1]) { + return (index - offset[i]) + l[i]; + } + } + throw new Error("invalid index"); + } + + let l = label(index); + return `img/${l}.png`; +} + +function show_tiles(data) { + if (data["counts"] === null) { + return; + } + + let container = document.getElementById("my-tiles"); + container.innerHTML = ''; + + for (let i = 0; i < 34; i++) { + var risk = data["risk"] === null ? 0 : data["risk"][i]; + risk = risk / 25; + risk = Math.min(risk, 1.0); + let count = data["counts"][i]; + for (let c = 0; c < count; c++) { + let img = document.createElement("img"); + img.src = tile_img_url(i); + img.classList.add("tile"); + img.style.border = `solid 3px rgba(255, 0, 0, ${risk})`; + container.appendChild(img); + } + } +} + +var data = { + "counts": [ + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0 + ], + "risk": [ + 6.8689162795508745, + 1.3130278422273782, + 14.364682863109048, + 26.086178013431933, + 0, + 3.996171693735499, + 26.609623463447978, + 10.24728615971008, + 4.707313155452437, + 1.62, + 12.041053092734451, + 4.955252900232019, + 4.019039743204979, + 31.297173259860788, + 22.897446084686777, + 13.089059187935034, + 21.93600580280426, + 20.047425288863106, + 2.1125103680057706, + 4.555635730858469, + 23.916679946635732, + 18.880975342227377, + 22.090670997703363, + 35.24169806753138, + 21.933339973317867, + 4.555635730858469, + 20.978551860920128, + 0, + 1.04143593387471, + 0, + 0.8999999999999999, + 2.519098836845261, + 0.14272041763341067, + 17.777878904753784 + ], + "timestamp": 0 +} + +show_tiles(data) \ No newline at end of file diff --git a/webapi/img/0m.png b/webapi/img/0m.png new file mode 100755 index 0000000000000000000000000000000000000000..3a28ee4dc7adc8ac7bc2d0015a18d0fde924d0f6 GIT binary patch literal 3001 zcmb_e3se(V8V)|HsHphD)rv6`k;jmEA-p06C=bOI#mPKKG|7a_00F5ey4yvt z#q})sC2H*d}aCJf<*G02It4)xJT+j ziDXEAlZA%K8{e5*(~Agkcl#}LH|wB2MA zO}tg=WTXsyj;N6Vr9CNFY;Ibs&|4-@Fu8-W$&palnUV|0&~BV9$8L57XJ|QVW-Y8$ z6aW@+V{JxWhJQfp@^k+-Mvyt%JYNqv%~TCKA&YUzymCM(0|34#6Auu+uAYGlrN2v$KD zoQkMO90u=TSWUuk4^+=HCN94}6rh! z8L*zkC^g422!s)+5>lygC0LKa5YAE@%HcGoG_ZZ~6YVD8LdyKBd4OArHRDAX#5WpNy$3>XF>oB~xa48l-KEKKgS z5uoUC=nJ_Rf;DiQiiK1J0s2okOG%+H1REG!g@XV%%=P1PvGz!mKNIx4TwF#W<4n%n z@_SXJu-R@sQkOSKigtQlBcq+0on>Ub!=~r-`sI4nLz`!00qHL|pa&-KoR~-1*@!H# zFJ8uE@)zkBsN7#x4=WfLRigxOqym8y1WrH%t!5z(h7~Z((1Zd<`?Bw^-fc>lR4DsQ z`771;7MC_s)+`nrBXZgQkk3mw??1cY&Zqy6%>OkX*B78Q+52VL^AMzE-E6`c=^`m!=>XQ#(n-U5veF0oH9^57V|?8 z6vYr6!C@S9b$nSgG3c~*w0HPu@6U@OijtDT7AKy%RoE_;?!#mGQ|*?+ZD-G(<#Qi) zRljlTtD2`pEpJ;NZ@P5u%_sM-T{_zJ@bcn=bCwr%P3Yzms~jVJ(Te1 zyNm;`4%y;8-TzPfJomgZC5`c39kNo{60RvMPeRA6p4POw(AWU`i?2U@P*>Xgf&b9N z{U7;@Kls$wH^pUW=VvmrJswQ>*S=LFt<&Oe_-Sr*C7>q_-*YLM^Jf=)FAa z{i(0F1?;M9K3ef*Y)8ck`H68smE=SrWLGV`?!e;PHAs`>cLBa7p2`j`V``IL8xu19 z%ZiEQ+65O^D$&E{^(k(cylLw<9_@pxo?1VCD}FaVz#G|p<@b4K)+>!0 zDB8O^Yr8JsN+hcV;Y_IrBsYT<53SyUH3}UD?XD+`=o3$Ii7(LuUUy`(SSS zo#Eskpxo(mKRExjk602@JS(km((Kr|A^+U=&6>dOb3v_{V+%SOM{2YD_l9>~`)#VF z=AzH;8Alhj1x0NhvFLi?`HYICRX?7$4cqokJRWHnm|V1!xak$hynsiWTONp^TgzV08MH_-z_Zk| z7AncUSM^EvTQys*+7HNdf%mJ%#5}4>(C%q$4Wv5O#C42TwNLP$9`x-Oj%y3&iG%LH zd(rF>_pz`Jp1k^rGXKc;$lTSwZ&bf~Vq(nxF-Mu#ZjCcY;zzDHQ?q@o5P1C`$Kd)c zwd5C9Pn$b7cw*@V+@9jb_)iY4+OhQQkO0k&1(x^^<8`AN_ojCTj~U=S1$B~{>=_MP0)hbw7{RCrlbJ~fgiM+Q!y*N-Q1^w3 zD1ss?iVC<}0@Qe1I7qU{%*?VtDOsRj z;O_^cL<|kV2pLX`i_ws1Gqc%laT)}T#`P2#u28B4)W>C~sT3t9poX&jL4S=9k5u|3 zXz_Uo0TMJJ8s%eDH&@E+IG8jLgXgEf=F03j|NOs5+R2AY9MBeV)S#OL$rAcM|e03-s?#jEv59H7=s>a!rib*NUU(JKix z#bgnY5wUs!m1No@Ax6`0R;}v|6B#gi9HOB^G|(ie8;GI(I8Cfp)$JTZ>9`7y!PR;l ziG}*Hnn*%V=pu=anC@TxlLIoe{{HBd9v4te>j20F zn4kpW!Yq*d%m8^X2=+kz2}~)E9|$GU90`L7Lrj?cXDC@U7@|l1Cm2IvIiZa~NX^O^ zM1j*aY6X?jA4yn9s0c0Tm}JKsIPWVI25JepQbjK4g6DWre7%Gmh|l2w3>wr;*WVxZ zRqOPK8pVA@0xB6Fno^0uC>LXKFrFNMASM&wF<2}BK`|M?gP0J?m$P^buB>mrh(Kda zRnWH|BlpYsJPyvpL4dQYl?~`W7QllIr`d5EBDgkemU?*gP(P<0jEEQa&VSGuRjg zVF-sgn{H|&(nL>(e$*Dm$7OOk7YDd}KAC^MDF6rq1V9mi|3^NG?OzEEbzAG6(|@9t#I}7>~>$hs{PH8Iyy9 zoIdpf+4nak2(!6;{rj2hdxMKcB5DOr9wT(>=j-{j&in6d^y?Y;BlCaN(_N!IrAGg2 z6?U%;IBdvtc2AKfm}%I5bdnGKhcB)sL!~8;*3K!VU1nw$e!e0PNo3=rY(ccdV|04g zz6Ii_%G+mdR8`Ma`JvgYs9l`=v=Hls3+oovS>MiINpbLGt(>sZ>VEjOsjg4)tz}KK z${ZiivcRtDoNb2c99>H;v+d1mMRLWM&UYhU-6;*9=l1>RS6xM?!gspfd-?R`%{^Of zg0=+MS>^^Ah=#b>`~P0Ed(N|R*Vtzd&RRZ5DX?EBmKyWV{`8y}`sUZ?iqvo8RWXUr z2MeF6a@{T+v>lu8b->&o6>Z*Yi??m5{@o(C*eQKtJYMRu?8oG+$F0L`sI3RxTwz6a zkhi(Vxwh{XS_c$*HVsLrlK*T^HyW-tMdJ|T;lPpT zEX~?QNh?+a9WlT7km0uErO%k*->vcSYieu_XH41`flA+Si6|Ftdhs1mx*f3Jb6@k(Yd1rylBjDkx@%6oqu$#!gCIknn4cVf%nhQmeHwtI4imYA)cFY%bt9^vS)hMjbWlEg_b z4t8P>+In9He zvH3q`dj1wl=9+u>K5ny!L$-JU7xUZy6xk)kv1JE5o4F%I|%H1Jp6u2N<_qjkot8~ zPTaMcX9zdx&NdWP)jyDM)5;pU7n`qUGg^0iC8CEmj1fJ>0zT&eR*Z# zg=;@t-M_wL{AH}U#u(jl?^aQx*TK5i84aw>bveTBa>@kVnH!nk zkGr5q>re+zarVm!4tTb(vjLPn`O=Va-TO_mSBCk{n#?)Ekwx>n)Nr9zl5{GXbLQ5h z6=icRop({357`HLKgL>|Q^VD6?t&pAiJ<^nEb?4DI#@!znIY+eXjad{)^NT9u zjOr&*H8Ce-&E>{bMuz<1i{S9&;GzQjRe^ZB$JK1(to$8awIxq|^l6P*x3~C4W&5UN zW^S=a$lRkYiM1UQ74S}coJJo!wE9tJU--FDES^~(dluzDfgv|WWt7NQq%t(U#|dBv1df;e*l)@A>sf4 literal 0 HcmV?d00001 diff --git a/webapi/img/0s.png b/webapi/img/0s.png new file mode 100755 index 0000000000000000000000000000000000000000..673901309f5166d8087af2781a12ff576be0e847 GIT binary patch literal 2899 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 D?dXMh literal 0 HcmV?d00001 diff --git a/webapi/img/1p.png b/webapi/img/1p.png new file mode 100755 index 0000000000000000000000000000000000000000..783ca19ce39f4a570c011442decb6a435f70a5b0 GIT binary patch literal 2740 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 literal 0 HcmV?d00001 diff --git a/webapi/img/1s.png b/webapi/img/1s.png new file mode 100755 index 0000000000000000000000000000000000000000..831f9846327de55780ce46b029d5e60de2fc6083 GIT binary patch literal 3293 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 literal 0 HcmV?d00001 diff --git a/webapi/img/2m.png b/webapi/img/2m.png new file mode 100755 index 0000000000000000000000000000000000000000..45002bd3b7d459f9aafec0a84055da1a6fa44eef GIT binary patch literal 1489 zcmV;?1upuDP)ZER?p8`RJ%oCCn6 zuf7>Q^1+M6+oh7Wxk2@Z_i~%=aS0)!_P6;Fe|XNHTHAST^LMK2e;4wN6C{LEpM5Te zLVJl9j%HR@Jdpr!KvCmE!$eiX(VjNJ?cx`2eD~vx?>&)3Rf*D1RMi*KAKqEUGREO( z4^jI&@Uofqz1o(u2OCew%5Q6%8&uc-Fmy2@V=RZ>CaM}A8g3S?-Fk23w==6N_ck|d z#&(!?Kv9#Y&or)*4)J!WwEWA@Eva?-`1B{q(`P!zx7>j(W&Ble-+Jes>b3lZd!p8M z-Y)$^4V~%_>wJAD5+$li)P5WaxwA`kT_mN>$^%NP;AdA?=Dz(}lx|N+2oXh%4-Fq0 z9!6+?Q#S$N`5cYDehLzCO~S_nfg?A5J{DJQs{c`i>=> z@wcMkmx0$V%vLLvXV0&-?!)l_LN6R|r8Blk0RUkc01D|$4L=z7`>9THuU(uK7g&i| z=}d*$&LcX%zzoV6a}P>b9+)}jX18#usziy2~x0U?dzssLFY{ zU^#=`hvTwBgni7QC?q3{o4M4erY)zK)9Czyo8-1bjuEWHg3)j}Z!yEPP3p`%IFsr- znrM8>Q%!^4Js9sEj8{2-oVNhLHq8J+!APVFNu1ftFq;|YtMdD3xY~tF#hm68IB;;7wMDYlvU04}VCw38`)q%Bp^@uzRyt#?WjSM+Tq;EsnJ z^TF-}zxZwqP+@k3*>a2^EQ`PZKrrI3=C_My1{D{=Kij0elM@5y&xuD4zH!smja=x{+ygr>;pZ?Sr(ybQW2M{XW)tF%>?$rF#F3yTZXRT#n zEeik=mfh*!OFRIG(?l_+iCbr{i$;PK@;Gm0Pb53Tw{Eyti2*<{r-@}nrjleT2>=M= z?!kBfA=@;a$;_a1exaDtczZuRTbCU=zd+{~0pQ?Fs+iNpZZ3)u3Cjp$(fB*fvdp@12}LAzaQE+_g`R5v&j~L1^UK95c+~UCn9vy^|BM zQzt!}o;Uvf<*Sc={jHhFjwWtr0HB!D9$cAo29tl*;=v61;L268R)Uf6*v-X83%r+} z*wBp@^iEDh#>Y6bMUh{hPStgtfFwEBSRoFtT(Gv5mdVt~x(~L}7<#+YF`);QR1!_6E|+9nOZH;R=QGfV&&IDhVO-lFphwn+n$6pTjd4nl58 zSWeu|HjcN8X9mrlNP3=R%K5_9(sJEVz@Z|Hu|mS*W1id3$8n>aFQ5=^c4(|}Ud(CC rFgddkma!6(71HwD_xkUJ|1bVup$^!tCrIq)00000NkvXXu0mjfO{3#c literal 0 HcmV?d00001 diff --git a/webapi/img/2p.png b/webapi/img/2p.png new file mode 100755 index 0000000000000000000000000000000000000000..22d96123cf5dcd0f8f42b52566349c91276dead8 GIT binary patch literal 1972 zcmV;l2TS;gP)u0FZ>V{-pe$pMSm>3$;;d}Z^~000zA6{Vd1-aF?2;Kh0*m**%_ z0swXInn^-}!4Lg&N;!S-;^J>V;r393w8U31-6%qu%X1d{2LQlm)tG%2`v7KR?2BcrxCVyF%V{S8l{|ej7_5_vJ&rT)BA#9 zp)&uQiKJdA8UujJ-~Rys3KF6#!zNM` zDNS!=4_;qn^GmM|k0K>SzIBjYp2zyBrx z;4e@$)Vap4vGF8jF|+X`05Cd@QhvP8KWiVJ^acN2jW|VAUL^IDa+=Yq6HnH$q5$Aw zV2&cBvmXDT-Aa*Cij)r8t+O6KMMxh8<}gMfqZ3co8LheoU2o84WfQ56HvN7lUaaX% zHl4{*gw#2Fb^mBbo1RUis=0N<K}j;NJgLyFc_`yTCD8buQ0s7dQY=$Y@n# z{oVU9g^cbpwa)+Xwo*nfc|NR$JF3MEtT$gU%xKj=)4csCxq*;_w%^&^X{?@k4hLI8 z$Hg~pdb=I~(i_>eOctHa;j5zAesp=XbS4{GX0htf7@fvsV4B35Ol{f!&?PL7P>y(;ZQM*5e-;pHax@jyCLjc7>snC*FGVyX43BR<;Y=^`WbM)~*`M+Z7W0ikkRvS-C3C|H-+Y%jUM*(N%%-b9t_*v0mW(bS8^Oj-20qw&kP1 zy~mM-+Hk%?MsMxxewp(};Y*x9x}Wp6c6Jpqx(1w|%X7Y9xXaWkba^w=CzlWwo7q0Twnk9WMy zF}0oFQ#I7(3VR2yFS7Y;Jc*p&qSXKZepvNcF9LwuIdEq=c4s+;KLVW?(4y5K=kLFk zj`H?`A?K$v&vJ#mVyO)KIRCt%832SK6W=UwzNm@FGdc|$PYRsx9PZEMIsBA#j7^XK z)(!wezjpyZF3&lw7qQX=&KKn^5qXM`BEZaf1DM8l@5cb3*J7UY2HGvZ#xQ)mdq4Jz zGtC%NCFhHrJ$0HA89`{YroW}LtFbhEYj6iIxMP|o3gJeOCT-!BZ2 zgrv3k)Y{X{nsI)w#q65Db-}173CU@5FFG+5N_+*sY60N1xtAm)7mRw>{H~#0$pZizPfoZ!Y$8PxlBULb{Cr=_WYd{!iLWqP z^`Omqs6Tg)$oXtMxf)Ljf2y|VG>lI3n)6@Fzn1@I$o~tKxA#^ac_()O0000a7{?o4xfI6AbRg3X9(m?Ki-k=mv{HQ-}}>ZadCn6*}XP$ zcj?Z%@zCr;w@=`l9_r1{YlWvUuUJSAK=uYrIxV5M_t{K3Eun9riO?Ihs!69M^oexp66~fD zyQwCpwe*Sf`p(flfPmYVoLNfFECt*?06RzftC=s<)5xNm*9sgQ{`uYL`E`06C!R)* zo@=|uH4+$|2#ii}p%svQvgQMr-(F_#f6O@y;G}p4ATs%Q^ZEO`pf_sO2d^Ii_z~Lx z@MP^3fWMy(1X8~%I~_*PGwoKVCG?5(x=H7)MwXqdl4C6%0Is+I4o{D>N{(7~$>b>^4>z^GMOpXqUqh)JFxy{eb8 zN^Ujtl?@pEy|#Ghh3pLqbh_kkpH*_tw%#(_Sn&XSoBKdbJaY7^Ug9_t+XTR>U(+L# zM!tH{Ntp!=z^GS@dWGRJ=WujVww&JHXN!ks8CLbOdNuFGL$h~O@7p}(w9q<`p5Jhz zRxxUoCMU_rd2iIJp|yFI>y6uuG3Rh5wn@Exa&zveUy3%Yc=;pqCNgHIdP&vGe3QdE?jgs(U39vwwGK?YE`5va YKM1Hx{&hEOUH||907*qoM6N<$f?b@O2><{9 literal 0 HcmV?d00001 diff --git a/webapi/img/2z.png b/webapi/img/2z.png new file mode 100755 index 0000000000000000000000000000000000000000..85b0e71cc1d019d846f84a80b71a4bbeecf5a4bc GIT binary patch literal 1339 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 literal 0 HcmV?d00001 diff --git a/webapi/img/3s.png b/webapi/img/3s.png new file mode 100755 index 0000000000000000000000000000000000000000..4ec0ff70ca57201e22c5060b4a93033817fe3acd GIT binary patch literal 1147 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 X-o=U{kyW&N00000NkvXXu0mjfoOAC1 literal 0 HcmV?d00001 diff --git a/webapi/img/5m.png b/webapi/img/5m.png new file mode 100755 index 0000000000000000000000000000000000000000..207179d28052321ef257a812e425a1cbb2dc2730 GIT binary patch literal 1842 zcmV-22hI42P)7&-6@DoS`m&=7bJ<}JyqL=raSvYZ8urDM?D|ASKXrgm4kaT+sj7T&@mr5s}*q59RD7^g**1@sz`;qcyoSmzEMA z`ki(jXXktG&HG#Mm8Vai!ppL@dyB#PqC`iwFjA%mP^@ zkA%XnafwkVn58X*P;6kZ`B+cZQ@WjAm~Rjwgq+K_62n8o=fyyyiL$E7s@m#gPl;!5 zQ~K?*glQ*LPM{Dx|S1A)b* z+xmB9woHysxcWJl%^Uzd=RPcjS&EZt6#&fA7Q2g+r}t{OQP``1)7P(#jwHM&(UN}p z+7-rqR8bd~Z_Da20QgV2MCta*@)DEt^cx*X{Qi8x`TC|_n7)3s`&cA3d()~`Td}y* ze5+cWx^{&H*YC#PO^#0h!01SVNscNidk`^})nnSmBQIHZR8f=T6V27Pkv^Brq~>N= zE=|qO@#dlYQfhUyi1Eo&r-z2mzwzsy=PSXD;n<6OqfkgM%x~%i5#z}#*BTlW3-ty` ztbd?)V34aA>mT4P$K2X#=)wT7vb@yWKj>^rd)B8H=B;W~R#ex{$eTSgH#t7xy3Gj| zB@Hu3g9E(wd#hSaFU+$7kpD*aUe}zF1ORt451iA0S9%6Yx9x4(+|(%{mTm-lqP}N` z01l&2$UVr!`Ue}LuQPgAn5%2r2U7qbM&#bl(;dCL-#NdM*BCbdSVe<&Sa)BXo)SU{ zL0I$&!k(~d{S@?+ko#xjUw@eLhovKlAufM49QrBfwfCp$w!K3s0PJk<=2ft}W#}Cw z{gXTQtfBz`2#Wwvd8{#csIRxvqh91A>+8Ry*h8?V+gx3<$?kpEDK%~_65XJLa3KH) zSUhp*Vz4KAF!X0WNv;2J5&-<+(EYP@HBdSsk0s@?(SxCPV*SD-(TmQ@W^Q;jEIETN_P2DaKx;+^ zkQl4ivU1$gVQ%8 zeOt7t`E^RyFHAbSc=XRx>~>j+UB587e&M~&EO4N`^_9mO(Tl(NVudZ&-bu1X=XAJh z1|9&t4?n*0_ zInMu6+o80Q*Z2Se0LgE6{Xuj?```vs!Y_q-KTkJn;2wG`p_?^${ajq?>#dbdR^-2U zGwz&f0Khr*Vns$6vkkSf`Q*;M=2q0^?ul*yKqdc}sdD_%WUW-L7sFK zu~sSvd!q6mMiItDH*7+PUUXiH>qkhN#A6i(1w=;gbTY#ZrFBaAxliugGd^2%b^#8_ zZ4mX^aPPkvua(Wv8!@azh+YJM6PGVm@){dSe1hN)OU^;40Rk3>{*h~zd!=XNm+K@$ zbi-VI==8Ib6=94OIn>wdntmOO8?{my1#qhmi8`f~yhijQB^JUWRwAMzx1IYA;0t#@ g`2YSR?IqLy0LjLU&PW6AG5`Po07*qoM6N<$f|Bf)Pyhe` literal 0 HcmV?d00001 diff --git a/webapi/img/5p.png b/webapi/img/5p.png new file mode 100755 index 0000000000000000000000000000000000000000..e5ad87378d7c21bae81694ffa45aec0b05436e2d GIT binary patch literal 2777 zcmV;~3MTc5P)+|XEec$K(J&*7C@05*=4fOQrnWu>T6a3SK|M?z!!7vpHuOoyMM`S{bf1rD#OpILd zBZQ=B;`B7p0pO!dY`{M5aJoVfid|G>XBrJBYbvxq2<&jW2JAOUUw~baN<=jkTBD(I zyACNyj^|zV*EPQvickWKrz^!laPNwraC>MbuE@?D>HE`e+62Q?UGpDFUx3RS3{%rH z1kJ>y646NC`%1Zt%aZWzy{rE6`j$|Hdbg==?aPT;y%r%P#Q5fB!_wW+YQ2{91kg8h4clg_1dMoqpYsAdhObm6YnA88gwf94K-q=RR%1)<<)z;n*=jPq;%(AB+)lJ==wGEBI z^V-88%e4g$SDQO}=jPqOY#SPbts0{R?pk{o)YYC#5v!+e&vLP+ZqKHO)wrGRZwHJ zfN<>XT>0ka-8DvwFsoqnz4!qe%r-cDdn=U30LR&20Tv{ zWnv%LMg$m-X5x6BN-39>zxhruOyL^UXZPlJHa+DL8BNC!LU^8PdWH~Syvh^BZ@;0Z znK-%P2cz|_`qR@yT)zU*)6+y?R!X^yT=COP{OvdNl_!b?7;k!p!1GiHA)1aUk0e-r zg5O8!Cnnw0+5_Gqe*W2itOa33A(tV9z?}pbkIM+Ju+?uLCs+Llp^a~&S-(oBnfQQx zJQ${uAa>B6Snx>G#0a5KcztesP?4Q^v2Xb1t=Ve5c5?VKx$2inL_&;DxR;aMS1Fef z?qwmymr6wBs(*6$a;o%Ip<)M zi4pGQYP}Y1TG$q6lJguZJH7TWs4T1k^HvsC>1xk`v(*?a;1|NIf+gcYVBbV;sMub5%(4@4EP(ktg^7mHZ;bHW$x(R9(KT|0me2o1}7oT zm^*s8VsW_=;8_50bnZI%{dSMv?)}270+5wmw+)SfCLkP_B{}6Fgj&0<4vskCS&^Ly z9}LXf++;8sD$(vVU?1nhC6h65EQ2Y`<VGY*+-TXzA|gwH&p&;f%WB z?6n*I! z_wJ|W<|2e5?#1*p5w}F%oA#>nlSr^>&yRh+2lwtD;`9IY?YFSv9leoJQndf84h%2A zc%kt6bMnIgraV>qc-2SV7()mh;`1{~ioByY5JJz%4@c=(QZ=v#?f1vWH7e2~OPJZG@%~hx7s!x96$S5iLo@O$Ni`MDyNM8Wg?91#A0AE|7MF_QaU47Zy zf)JW|>&zqfA|^@2B&m;}#7~suTP=;hO!*HJeuNOh(o+BV z-=DR1UH$Cdya3}Z-5uS3&^=hnVY@hl5U$CA&_*nHAocCt0Uiu~dWPWkW4cnDEiWBT zmt*2{Hj#rUHTu`s{@1(eXOlHTNGX>k)rNb)PtOpoUH#ib2d>F6HyOCW9C}UePfaX% zx@~r@WI$4h$ZBcWE<`eXQ)|!IgiC<&YV_Kgiq}A6V!?A`!ZkMGLJ0MBns)2*9Zpws zTMt60TCc6uYuQh8Yld)4xM(I`t=HPDrd{E?ZT1grBk&1B;q`v|I8-dsG%?gz<@GHz z6Cb(KzFm*$8KUl7y8z>X*$>#qp|%%b{02j%G))Xf^KMg}xyi5td@xM?`qfiXiD=F_ z(Aw2MHsMlaXX1IPC=-VwzpvAzI3g>rZ$StpnKw8ELTGaMGP&Y!ZtIasM0lP`i1CO8 z4^#t1<&>g!mI+L>B5qC1qyX`CUC6mG*rsl%XR1_cO41h)VtibaLnh8hf?*2R ziB?+NTDiKBL7!K75)sYB=}p6Y0>PnYxK|Jh9z0J4 z1^ndj<&i7x!3ZV9_%^F)r0;#HM1*T{f?4Ye#Da$_`WC#dG(Qxf98QyfChuKk&t`rZ2*H4{$ zk7nXYF*`ZtvvC`e*ps2^s^8)K9Hyl^Vkb$U$j)T*MKDaU>2Z6$*dgP2SN+|6cJBBK z2mR}d)Isq)ATRg9)!>_jp{%%b(p5JynD>l4_58`==A^n fXUb3TPm%ry;cM!HbV@Cg00000NkvXXu0mjfKfigb literal 0 HcmV?d00001 diff --git a/webapi/img/5s.png b/webapi/img/5s.png new file mode 100755 index 0000000000000000000000000000000000000000..f0ba7bf332324ec2baf9865b700323341bc41d31 GIT binary patch literal 1610 zcmV-Q2DSN#P)tkL%C5{Ud*kL4Q%X#uC|#EjejW1SXr#y%ZL~{T2^Qcj=C+SZn01X*3GeQ z1{B+ZLs(JFp1PP6$2v-C%tK9+EAyS|A@Fl0`o@?Tb?PeePJ$-!l ze81m0=icvkzjOAiudl=I*=xJV{fd5f>0eidqRCaK+ZBk10iexraKt*$tlzf-Xa;An z`*geEATwqU{pClKt0yMEN{VR!sIKGy;Gc~w0O+-~H|*c3pM-iG+2+p%eI&=@8232F zF`g9DzKCD_x_uEp;s5~R;3Se_dN$~zN6P5?%vLhldabUeioA@mbsI=Z%s{)ly; zUaKog4*>0r?AHMRT`isJxl5!d!C87{b}!bH;4hi%Bt+rABU6IQ=rg(OsAmd&=iHcc zZVdhY>EUvjND7TJ>Y2*qvh*;S>W$7%%?57)faO3(-}^n75Qv9ogSYCny20+#D!E5J zc^niw0J!?cobSQi+2F03Dh(+vmOh%ySIA;KjM{{fiIG8-tUx>*h~1|ngaS>r z`9zc34F}sA54ANOYN~5s9?>SHQsTpyGEN3J)iodvi7?8&hv|0ur-yOhka%V75dica z{&3>dMKWenl2Z3VOW*&HO$h+N@jBCm^L(qZLZcyLoNm|E+wRghThM26*|)zq3IM-3 z#sT2?mCpcR{aSzwNZkwlKJevcHVXh199L1T!AVqb+y|~7`Bozt`R3U+2Iude78vzp z3vXL-6_%Hg8vtwz^B?~@o8OXbR#;vxovQ>dTXvdH*f>5fUQZ?IsU)G#@w(;{wsO(R zrmxUwOc&0hFFg^YCwV0?T{us_`yJAg3ZadumbczJq8!5nnUrGSEIm=ZZG)vvC5}vX zW|n+JXNXb)fbYRwZ^WePrpIlC&`35SBv#fF*!+uY1>c)OCe?ecp(FCAms)qRCZX z#IM)t=%sH#zpdT5cq#tdJn|XsX8|BIc@1Y{IDYKN@Hb_lZPDkKHYt^_H1T09G4bKAravSYu@DagTjD?+U7s0Wct-U4-)9%UMy*J|jWb$kD=|2?!{9^x> zF1+jS7y;ne)O7%uKYa!O&iobH0gkNjRw$|RI3_%f33@fktt)2qUI+PtLm6DzaZ)i9&6_q&b>iegMF~@SCU$5%e#St3tIVZHX(NM`pE^S!qqmtXm#yajU}f!5LKG6BfHy?r zCx^J^%m!07*qo IM6N<$f|?X2lK=n! literal 0 HcmV?d00001 diff --git a/webapi/img/5z.png b/webapi/img/5z.png new file mode 100755 index 0000000000000000000000000000000000000000..5a2234bc31583e0c04e3da77bfaa54e15f19993e GIT binary patch literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^T0m^g!2~3mwEK;Kl%=POV@SoEw`UImIUFn-PR;)+ y!NjrPyxIo8p!#PYuf6_SwKs14b#&@iHe;O;v%|a<)=z-?7(8A5T-G@yGywqJ94m7G literal 0 HcmV?d00001 diff --git a/webapi/img/6m.png b/webapi/img/6m.png new file mode 100755 index 0000000000000000000000000000000000000000..7f0c83070d9f1267e685def24e154b559e425cce GIT binary patch literal 1735 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 literal 0 HcmV?d00001 diff --git a/webapi/img/6s.png b/webapi/img/6s.png new file mode 100755 index 0000000000000000000000000000000000000000..e3a01ee2a30d5e25a9145e140cef45da54300310 GIT binary patch literal 1314 zcmV+-1>O3IP)oQ zcamHMfc{<+0Q}pi0f5ai@JIM3oWx@>D5}jr$O+UZwYrsB-NJTBt_p<=>Ovud3;-Bs za1xSSJ;({HMV0x*IX_L-ZW%Q9nXtXT*R(hnKt1U8AOisAK9k)tNKDY}X^s=%7+igS zuW514f3JDFWpLBKa`#7Em&N7^w&&MqDl8+))#7y-^-cc@O~u@2+MZu)&FGj1fawwb zbO3NSInZ3kDGSL(G`Y8UnBVLW;m zM}28;oyDTbxR#+tt_#b=QoGzNRZ%bY*X}{?2mm}|Gm9SwutT<#Kgb=~ErSu?0susl z31l#k=`yj@F2}t3`%t(zImjKE`#vDY;msGNI}bT6}mO_F^seaM{k%-a76Z z8os=K0|3FvPq*iPcn}j!CSJWxwq|t9EA`q(-+lrBf39u;z-KSN27sGivu&Awem>@0 z|HH4Q+A_T38HpYphaD}`Wnt%;&69_)!g&k#X`Imx&YP#G*P=0+OlTRd(a1Q!g`NE~ zf#M8BN&pZpPSS-8-l6G2MwiK!@+>1f+SZw zu2~FEr=@)M>fC7?V$%nXDN1Fbkg-_?*=3~*nM+i)}i~t z*`qMLc~P#U3z=BzH%g5ozAwG5SvE~G$edo~qsas@;W>ZM?cvfr)qkHZWWLz>9(DGn z0)XGcKax{D3Zt|7OD0sMR<{8FZ#H1kG&W!BfVq^)ta+}=3D_(Hs4IbFY$wyD?JGF$~i zU0N`}`MpxF`CcxekFu{4POBrex{X`+Sd7lM{oAtkR;>Aj!P9Cglw%6!P}+3+s|z~%KDQLcz`1z(7^UaXN@dtI{}gZsSUUuK!D7i$0@ z$yJWw(hdIPhyQ;<@&?^rnpRsTtd6GCr3Is7{)wf_%y*Ej8W-*0+A8N<+b!LEuGIZB z&S(ec-*%{2VS^=CozUk)nP@V>ZGbB1?z}!+Oa6j78!Q1}!@rE@_OTe9)w2(@A-Bit znxUuJQQI)5AQNJqcpt>*tR4VFxgyF{N)|9vwp#|cEY=`H`L!;iWB!Sy%l!VG`6rbB Y0MSpkz_W%IR{#J207*qoM6N<$g71xyRsaA1 literal 0 HcmV?d00001 diff --git a/webapi/img/6z.png b/webapi/img/6z.png new file mode 100755 index 0000000000000000000000000000000000000000..37ff7ddeddde6c72daa19593480f629a22f2305a GIT binary patch literal 1561 zcmV+!2Il#RP)Vyzp^2lQ4ivv%RD)%XRNv* z0FX+kRoeoNtKB31c<8?PYF)q!XV^QvxmarmR^3q6_m0uf0ASS(4JfrGzT#tN6tW%w z=$1SNfM8;$%%A!9HX_YnyvD9OduQ02KP~#$mp*pJsyC_RecfFY0QmQ&r4q_zo&e`rVmca zMT1hyQZmZL((Ze#%f z+1pdg?JON`OuSJ&0|3*Tizla_=vOv$D$cHIx zpV^J9O3_Dt&6kS+VAU~(AD?YGmhdt2inASdTX>v-p{Zr1&lP9b`@_sHYWD~phg3qD zH1vQ{Ytqno1ShAToMG?ZhL5DU<7OYhU~AiDW-5pzi)>v0WF znl!Z9JyL532BkJ%F5-C3w_B|X``ILyO_un|_SCY*{VVYhc)oz~duzOyo%C#WcTxM< zg_?J8qI=EsgeZA!A;d&No|ui*}vp1`|6Av9~RQ?`H!ldEZ!Y z?pX9KEf#ivJmlZo5Wj-`&!vd#DxSk=!6sVlNG0zxuQ&-?A?tZR8xR*2yU~I*mzeeH zl5<1BUA1}a%>vpl?_ITd_OnSmU8#g}4NoLJn=Jt^uDLklYkJPMzH+K{A%9v#4C;@x ziyGCLu4?E|!BmPqMnhkpjkoy7`X}uF_197d-@$kA9efA>AIAR)WPkMU_bO&c00000 LNkvXXu0mjff_nW2 literal 0 HcmV?d00001 diff --git a/webapi/img/7m.png b/webapi/img/7m.png new file mode 100755 index 0000000000000000000000000000000000000000..17f6b942a96148263e76b425cfc8c29791ac41fd GIT binary patch literal 1585 zcmV-12G043P)}hF_#_p;0s=Zpa<4#1Q+ZOMLi_YP>>p^N!3bD(-x&7QAnd!O+v+G@JUrZ5xgYoL z+&+E${c1J<$bP@&J9pShx<^}s1|a~jOY%lzaq~x`!$Zm0ScScavB$ex_8;gv({1^} zdN-e`z4Q3b<2T@SZzx^qITQLjmu18KieL8oW#vFEj~mDH_(#pF4|;Zaq-JF=B{k9RkFperkk-P0W^Q7RyGZR}<}?rsXt0m<1IcD?iC50?NyKxp#zUA{6~ zvKM*)5Io>3QObv#VT0X@N9l@ay6&4~+rw*%i>Et}@dyV1gpj_x+%OyJ-27zhe)P_5 zGq^&#Brj@iW(jA%;=gudyw3Pv4{sC-Q{!XlhY!q$U60NU4cE#u6|#21E%lRL$KIa3Eysi}tdfrIx0nkFQ1m zK#a>Bx29};ce9OlK9y!{05CEdC1jiMl#pr|Eg0K@FJ^NyC%PVAiMU$=drx=q`JGf^tU6H_B$mBE3)NB zHSv^?d@5b0)PWH8$xg3i{)j!yoao}N1Ayq0osy@i`L*MBAhhqJQ?)48_*KxOAJX4v{=UE*9j7$b$EMVM(1WF8|W{iwxxj4BuEcftmlS=g1tys)X%no=h5DF zJ)*}G`dpF{lK3Rd@(-6SwjKPdS~B(S>J2UtqeKkRCnGHCb4fN?>wa$*&*csVUQ%jg zw7sXh4xJwW0HSIfZ&w@S{4%BKZ@x1Z*0$>r<|0e6^L_pEediiu!-n3!q*R|v=2L0j z#>|}TVug--?36r~H*gE^EQOUzCHks_a1tvdSdpJ+_2j4F#_$^#T$XF~ctXG;00b_K z$h~2N1K>rStW2`B%eyRU5~IC0gDLZii>BKfJJvOurG9K zoho3B*W(FFh*Odr2<1}?fBkX~0Oa1V10h4z%(;(eAvSafLg4#RqGs|7XO;xvI)}hBPboC14-mp6uDCTt5 zSw!D!H+MAv;1C4@Q|>`Ba*3zEkoX z930RlCMhA_2OCk6}T|s zsd9p-8b6&1IVFz+A*{%rV;z>)&qljZ%;t~_*ZLt*rZk^Q6E#DLfv|`bpQy+i_I+FP j1G{1UOa4mwZ{q&}JQ?*G&xwG~00000NkvXXu0mjfTEPn7 literal 0 HcmV?d00001 diff --git a/webapi/img/7p.png b/webapi/img/7p.png new file mode 100755 index 0000000000000000000000000000000000000000..108bef00c9e1f992d889ac0692876390dd0daf1a GIT binary patch literal 2833 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 literal 0 HcmV?d00001 diff --git a/webapi/img/7s.png b/webapi/img/7s.png new file mode 100755 index 0000000000000000000000000000000000000000..21fae0ea46412247ba311526e0262d4c75908c7e GIT binary patch literal 1639 zcmV-t2AKJYP)G1Q+_!MMP6Oix@4ot{RouMU;Vxg=wRu3YKP2Hw8`2q6-JD zZNcJD8PT1M$*K-R{Fz0YF(oeAq>CZ3iJKH+9tm_ci&Jl(?>&t^20PF>tNSkBJ>R|O zoO|vE@63k}AMoYun=i=yKmC`b|5n?wd^#O@_&EN21whs17Ke98f9{+HKW8*le)i4V zK<`fm8)9b6Qv`A;FuC$ct^%`7hEWPZTH~=x7rqBHQv^GClN-r|=I5P7D zKpDpYpgL&q{M6t%as0IeKm9U7gND8v4f`o)lP5AQ!RM_)=2Zkh*8tc| z)zdwrwdNWnkxKA?+YH_MbzC}Q=8f~73AR3#N_0H9wO9NsH!5^oU}#DT_;KdvRCZVD zWa`>TccV+jr4sy&_+K=5=DFYHxC$VZ-A!gQ3=oQjiF@3Ad)$2+z+O=dMZ?nA5ONC%MncEWdKKG!RHv%w}>nWtJy5_d}OAO%cxNb951E@6%wPpc;%~b8}xXu7=^_N_A z%>XQXrJ-C8z|0$c?!jZx8_KyR!7iO~Nw^uo5ueH>O@dukJ!C4Smn(>|R02S*kf)fZ zB#|d0Kr9uPeoBp&B(oV?A+HJ`Qz^ZU2e+uC&Ac&J5Gl>l!Wmwge6+em005Nco2_o2 zdw>8ltBWH`zW}JvafWh^0Is^``MwDmmul&4(ZJ^(Xsd6g@xq@W+0lveW~*BnfKYUe z25t4tY)^CvWu_8*S6wqfhnFUEg-^H3wZ9JlwdNYyqCfCdI?2Xe4i^D}(Y5vc!#EGt z6Pe2C=ldq8u%~-QJ*{p!rKh!%0etQOD(v~b35uty?(-=DbT_)Z?Y#gzt?ucbQ2;hm z^}I(Od3Ac(Q2^LX@`fb?C_9?@U=yr0*Qi#$3Vp61vWSsMTMAk5;7m{fkS$q{Z?Qa< zp!cuLQmrm*2FY*e^_p};GpmdA94u@G7dC?cws+pmtS(B)sCt6YFac88UH{6gl1ruZ zY^ItD9k*8$*_O?`(V+VrItyRP05nsfM6zo3tfb42X^@ysPh@}$4OOvd5``iP{X9>rY8!|N!jE4K? z#$|G2x@UwDDD?=AFE_S#KE?By=RURcy`m_U8{4S_dxxg3jSyg4l7(b8Lx7vDZYDRF z+YnTAT~%%vbR3f#-uCNI*s0A$+9POb@H zqx93Pcr7dnH6a7YmdG3)MV~8(!RP^5DAk!{CFO=}Nie#00=Yre{^-Rb`Q4DD5P&~0 zOWocdnDqx{0c`KQqXFB^zSImqda(##uPCa@4HbH)V6V_|pjW>r0k1vGs&v)g`&>cH74t+HOC^-4l>(C4j6tVYHZ`{J lFus literal 0 HcmV?d00001 diff --git a/webapi/img/7z.png b/webapi/img/7z.png new file mode 100755 index 0000000000000000000000000000000000000000..190990667a4fba7e8f4ba69d006cbc0af91fea14 GIT binary patch literal 856 zcmV-e1E>6nP)TxSmG|8>}cb>Vsy91NcqY1L7 z_$hvhe^7Xrkc$oN>aaQ_ekMlLvv1J(rsm)d06<>O!{SbC{J^t!2{E>H$_4;fr)S28 zkK@CmTHQvL*J7QX#omQDv+p*V`{h9U=<$Lm2KeMSs8$~bUM{FBCsmH;{T_^G_5grH zN|6hy*TV6<&vK7=0DzRsdaH}?-vw^Uec@+QGAr|9(l>R2al2te8Rv04JSPaOEM+01 zTD3Z=)oE0avJe(^Z_94QiF#C(=V@AiyE*`%-7wmhhObRRk=27rhzG%Vmk``Er5ucc z4_CMc!F!Kt^@~mI=cg}$zY>gnftDAObFW{${JOVtQiZ#^_it$<>wH7&i9v z;Es1hc{y*Lp8cJ=_-|i=n=Rjf?Z)K*cqs=N%ypdWqhng;cz*uPs$5V7QDk`GS<>70 z>aglM4yz^?(qbmvD<}oy<$~IMl6{NJ;VMH+Q-{}7E?5R5${E&)|kN2n> z8Q%BGA2)s^n&RW>zeqXBg-9>G(c`Ja%)(^wQVw!FKja-G=H~?ffKpHsN~G&-h~j@< i7>OS2A8(3(==eV`{Xrq>fPsnt00007fK6vrP`}hF_)cOd|_=Q=wfGV+8Ryi+F-cXF>DkH zt>L$|P;{*sz_i2diO(lmz_*h52(?e&p5+iSEzfh=@v}c{5&pFYw`Q%D)Pwox@nK5W zwgL|Tf@kN&E0b2s?A{xNg1o#G2nG>qx7t(l_s7qTRt)Ab4g?Q{ z!UGk9TgOL_4?j*X13=(l@YLv8>%28RUftF}yFNLQdN6MVOZ$2v$4*p- z-kR3!cv>bCo4jI{Hnw!lB=bh`6?wGRzb_CxB<<_jM5?K`7GKY<#wI78Dj6PQvGZfm z*SWW+XLG}CfTwE|cXZg@T1tqaXfD6xurvbO_|~LNO>0v#0Kj|212<=E{qIJvntCG1 z*Z^Rt8YN_l@RX1;r4_493&vL9i`m@0!y)9PY;)bdLfYU7ifSyRc!FSu8%HBPn>5pqM_JDofmAQDiR0048$CWA7rlyIa zQ9?@OpCsTg-*r0b@=MiIwQ}(CX?gMc5da81Ox`;jV)!}|dIMc&qBZwr-RLPH`LxV( z8+%2k$8G%+d$6({9Ov}7oo=D6{Vj|Gq1|8gtw*ViH{-L4_lf{ernH#TnWbDRxw<9Z zCo=ztqM;5Rz5N|hU+XTuo=C3D#Z8h`PPf2&MeOrppO{a}L{W=5-5j~+^hlj>o5eGg zDSeUE0l-jIgfWM48{#N2h@u**R@1r7#9Ng-8YyOT)VF(PbBq)6eT2iG{Sr`Ws7YC|BAj| z^O=uC_D~{5i5R?BM3~nXQp|{b;=h77NszJ@CgvjSF zmMyJi|BV<6k(JoRlOu~KPqoH|W}?>@Qu(yJ|HgIpnmig|RnLsr=@x39z)irj5>_si z%mpxWjl;ZjX?(j!c#+jp-$Yu&H*UDB*6N8Qhj{>yE{%yp5#|}&1w&QM!9>x_rq>L< zaoKrt^~b;N+y#I=r$>s}oOF4d-7PuHBaAB!o>d&?UER{|{=Pb0pf+AlBq`ZhN!4<}J?@%W!kvmASa~%XH1_m;18=)y8HU?!7NU#hfnm2C&ad z6xD%{cX%+Lmf4krHM)u$rd1r~`ySRP%+2EUL{h#mCS4j6s)8VjX6{afoNmE^kjpQ* z{8G*1XXCn2%;r!BUhhMqOewo~QDPv>W1pAzi4E_4oA8CZ5&Z{$O!@!d{{~DR@>G-x Rqv`+v002ovPDHLkV1k$V{DS}h literal 0 HcmV?d00001 diff --git a/webapi/img/8p.png b/webapi/img/8p.png new file mode 100755 index 0000000000000000000000000000000000000000..11dc85b680deb2327a261aa7b63b7db63ad62c9f GIT binary patch literal 2578 zcmV+t3hniYP)=d=+8w;M+Czb4**(Nq-VKQ@vx-xXSBqCsF=&IOU}<4Npw+I#%+U1M!%L?qDLAoP z<*-90(c67-Msn&|`DbIFwT{3Ts`8#_H(D3;UN8~~7N72RoYc;3nE?nU0c3;>Rc zmv!xJ5%wyVOyx^u0MKixR*lNzy^fkDD`;q66~rH&JV&aPH-cBsx!=i`Dzwo60Ni$p zR4ZrR_KaU+^Q8&^)PJqlNI(4R`i(|Up<(F7*SC0~=J&eX-s@GNrXXZ~ugmXs>9tf< zsEuD^+38VUsPRILogN*(##V)zUQ3}yLCC5?&F#JJ_quqY7GK|L@5tq{ zR<-hWf@|c`F!FgpBsI!-f}@Qcq(*t?ldV%f{ZTvh`tSerA*oU7wNyHr!$3=Cb9ybM zAY|P3&aZ#*^WEH+cRty=!Cs+_9q|N5YLvVnzVO}SP!O_oHfJ3i#;?1%F9ENV4i zG<2sSU#zrhR4;6Q+-NA2Dw&75o-UJbW}eh2{o^ht)2};5%?87?v4iKu%aXA2g_^H zd{38Y+UNR-eMs8dkHP`3fBw!V|BCQ4Hp{uwr_Q>5L#mYdloN>Zc58D#L3*VV)u_Kp0^!yE=VZ8XrGPd)&UFI6%RbCL$}Ckc>!>1{p6mhw!@MPqBx*qUczPMSnbpP9ZNTO`#=&%|83 zF>~N~m_PHj=fc=*RS+?A#1ou?kVV)l6Vvm!F?uaE<#jnclTT^hn;pYMa1iE4V{6F# z@oOvqCf603OQk54sVhdG4%w!+Y#tz!p!6j2wLEMNfRCy6K$b1Y4U3=SRGS$eX8S`5; zs?F_`UP~eK-|9d0{qKGEk2ja`MkVIwOJ&@W%z#~YtMV5dgLJdDKrcw!4RV;+W`8rk^tfmnMSdH1rDIgOfhHg^!__nA$+ zP~(!RA%`9L<@a82GX11R>GsX_beRgpa-mcylq!W{xu?tI_RWzRrIYFRdoKWhZ)SeT zVds)5Ua0k%O^sZdQ4f>mN+=MGtu97l()^Ia{xi#uk>>z_dEukAzdWTGuyqLa_`0)dQG3;-KTi%8-Z zwg-T!AX=H>%gS{W+nQm>^*wX)Al_nB!0 z(Lx&y*1=)##X)4g_u`;+aF{k46hsSZNVQV0r5v8g2z&K_%#SBHU3*(5`=~025%!8g zE<>IJKyZ2l0Cv83!u*{t9!Zm^QOIQx_DWR{u@`8PbDM=8f={a9-|9aF05_NJ0)Spi zmUeFz*7Q#!{gOPo?yFc?C zo=IeQt6HfbT9EDa*R9VBy7soJP%B{FZS07!R}Ra3>@fyxmgAiU1tGhg;Npp`%$KF(;MMui zt;I+T&-7v>CTTFq>a^6y;or@NZh0o=0HDbV8g4!&d#vG+`A()E*Ca6?d&-_Jlf-;< z!iBDc0@w>QN%;-$9?uNxA4Q%QiciqSX_Rt;vJMX4k1e7-cDuCEzzZU3NVQTSmpMF> zE1|#}Z=Q=MI9&R(=Fe9{`Z~ufL}9|KZO7Kx&lr%*VaW?C$w~b^gn*%2HlPXLHS& zzfXrts#VV~-8#~zuF_cvhgUI_(WJ#ysLBS%(3fiX7&00XveWd4Ay8vw@KOuc5n-VFd9KR9|Q z=0}%TN8OIuV3y|XL z!SDymYySb}`=;Nkf31b%jLqWrUXYl-ujYXEIP%4c^s-z*$a>B6vlPo0EAa$}caJaK on>05sX8+$C|J(mcddc?x0CY~400vnPO#lD@07*qoM6N<$f}y-6Z2$lO literal 0 HcmV?d00001 diff --git a/webapi/img/8s.png b/webapi/img/8s.png new file mode 100755 index 0000000000000000000000000000000000000000..49d6c954dd9f04524d3d170fc034c2a04678a2b2 GIT binary patch literal 1989 zcmV;$2RitPP)`GIQ`SbR##x6c;Iz-B2WQsZI(j#dQzA*1!WBF`Jo5djHeQOa0&X z>VNSK7RZNzn=Z>SLFUb{cn!GE?s()p)bF2eff z$q@SgXY0qI=>M?tXT7M?&?aWIbH-{MBWC*01AuE zKj8qNSS#Z|v-r%nIAEDk_GUY^NwobFu2?JMAee~*fG9PCnHWLWb?$jlzyr!MhO@*w z0C*Vr8dvl0fBd*#I&7&50322d)y752AFVb70I(X(q20LEI5ur}1AuOXp0>N~k-zrE z`Ds1VS$VqlUW>M@Dx3K?IJjO}L(syjqv*FwFSttKpmYQPzVWG)KN`us-2CBt{9wZJ z=r$Z;L%Zm0Ml%*jB1Bf>7?vZJG1!de54Cb6_fnLan0g1LqYt$*0C*lg<{N@2HEpcf zY8*GiFap- zcRGp|rRKE#@v3(L=VevNhtn)$Xtfny6zb9?{!%`i8c_9Ytl4F80D#XqjhlqE!kY~0 zDB5Llc$1;d&SrfvBur zwb}}9IbjE-qgGpy)vI(M3IOhypBIIJ;DgIftF72r^Qw1YetQi7R-ZiOML}*W+OI55 z&hVn3r)V2%-Z{<%Gx5FUjm`Xp4@-mup2jN)n*Cui??@99Tqyr9vM7X@Cd5#XA2RlT}&>3$yQJ@>sT<GusAs*tIFmNZ%oYS-qOafSH7$&^E+#G>2meS0stJ8I9a_) z2i8BO^?rH#?dkl_h`xW-+swbgOUyU!nR9yXjlO@v9h5i#n6Nljy$ih`kf|rDiZ>bT ztUNA@g>Z=9`#N@un*S zfY--4-}uzqr5C|W+?xz8PR>>v0xt?4`(x}Yc8;@L<-LtHTaD(|$Jx5n>=dG%u)SP^ z<%W);4=e9^QP^AFnBQK*Bm#h9t&H@jfHBE+6uq~+5y@`VrDk8%N?4z=L+AnVL4vReR9c$OhTeJ8oGf5KtXMzUM`B@O_1QIJ(-Z+WBIxG2`j zc#v)o65lo`F+Ym&gVK@QzQX2QPd&hw6_zoi1M7*|6;#im-8dn5 z2>R=cE7r=z^HZ);z#MF~6|BM4#zi#uN=MP@z`E5qCQ40FYFdqB>A<>WlO^W0IeAG4?Y0QIX&o*m|ekQX=BYq4sYhKTgj>@ zRBz<0Hi@QrP21gx*%kbs-plhok1N`%)y{El=Qu}9-e&)^$CXv@g3swWIN>lqisz?3 zr)OXb(AVxm4*(`+RFe_00000NkvXXu0mjfeG2J4 literal 0 HcmV?d00001 diff --git a/webapi/img/9m.png b/webapi/img/9m.png new file mode 100755 index 0000000000000000000000000000000000000000..dd24e3a8ded4646c508f5ea8279885ad41957a25 GIT binary patch literal 1632 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 Y1!LUuK{eze9smFU07*qoM6N<$f+ni{9{>OV literal 0 HcmV?d00001 diff --git a/webapi/img/9s.png b/webapi/img/9s.png new file mode 100755 index 0000000000000000000000000000000000000000..9307540d249099ca5ddda2e4348232eb21ee7585 GIT binary patch literal 1993 zcmV;)2R8VLP)>33tyqD^_}~k6aKr)Z902Yu)R5gWwj_s4JJ`RB8syKt0f9? zK-yMf6+)<#Dyy)da3jXfrA-n4a%jAEToW_M7*p{j2=@mH(}7Z(7P-dU$(7i~|^G_Xj)sja35g zAZN3&d$Zz`WdL>Oyq@5Q!D8VZ@&#pb`N92f7Xh@|oYQ?bPMgeHp%1i?zb?jm?_Jy5 zS6EMDZT;Nf1RF1HrNS3JJ5b&_R0u-X*I$`Fw6nMGy?5>9s~?#|b)_&jIB~}2RB7of z{=#O2v~T-A_cgTvc=_tb^;DcWq?W>@?YTPQxjF*iKv7al;kO@yp?B%w_`>t20Ia5(d_kc& zcoewP(R`L1Vl%U`nXdp;2m%0#16SZPSKx5{BZ<{N&HM#Gb){ge5;D>*fPr>@$Umgg z(hI%kPw64#A7WchM~E!@eT*JlgBM-JEoYs)b5DzpN%Au=(^>pho0Crb^~I@t;qY|v zXU1f=*xG+G0r!m#RX)>@3gk59ip1>B>Bnk1B%sXVwHw1Jb%iM z7nj1c_u|qMap?(w+>4mVXFV}a@w+a@={+*i?qv9ZR!b-Js*9^MzZs=dM@f*k3PCtf zl$~cQtf`))QrO#9HpF-`v#pwzH=T12AT8zc1;t@)$QP94t8GVZgSO(yuXC2)y8vXr zj~PyxwH1#IOlG!?RYJKH@4sokNZd$fwl6&#XGL?mZ&bVZE2Co+fM&PLJ3gje{7VnV zqd%+xXsoTD?i;1zsWP3#pWlpL{^xDJhmr;xUlKQxneE=0Ynh{E=I)ON*E6gD+1BI)v zsg0F80Iq-zZm@C(priRLCEe2|v$4tmz-p>_2i#C4T_2}Sro|1FgKEfeNmnQI@&$!* zMZO@@njeQ7QYytad7~j|Dc4w#0kGtwGM&)t`r(x^(6{hB`u5XPhu`Yx?Q!(>s5${e z6KnL)(cH#xgASp}bQa&&)JCp6ZumI(EQuT49v^)}B(cV7RoS>PIMG;J4-Pj5+Wmp{ z^UQ(a#>Z1%emwOhG`P{z;tO_O0EZimwe{uV1^`utYOGZ!EEQj9al?AFz&NbxqIIl% zzMz!E4OVJ(o7y4kVw~+`3Hiz8L)=){j1VYBe^}#RC^4o%%cnYdA1 zDTGJvvNzaywz4w%Hx+Jp$8WN_m&|N;eQ}xpKZ5dc!-V%f*dg z=LL4hE{PkH;Rln;U*jllwA!5Ek-Me8p5aE1$H#VoKfa7C?4NeoKkZU=^3G>$&Yt2w zrVYIWpd(Mw4j@vz;qsl}c6#U83afQIZZPL{G0y&O5VMz-5BZ0POhV^}2{(eB7gUjN z`$H!H&($lQt5=}GjgIEC3^zjOhjI8{b+jyb0H;kgeAB9_7KT$tu2dy)Lp9+^^7(=i zNgTmKo-@fx;)ZHSB(e4mxIxi=|C`6Oa~s?i0*KAbQlQ0VW@9t60Hl;i4@I%nB5JPQ z|K>4(y?sR&H+1A%ZBF`~k(P1<3yrn)e6=>a-E`y*Wcfgr0SFee+3jWyr%h&p)qF8q zS62$Uq^n==^93cpFOy_4v#q@wAIS1gvP^^{XS2U6{^H_|4NOZpW2Hei>-~ap<5&6r bZ~31A0}CDL8f^N~00000NkvXXu0mjfZKLlM literal 0 HcmV?d00001 diff --git a/webapi/index.html b/webapi/index.html new file mode 100644 index 0000000..3b2cfce --- /dev/null +++ b/webapi/index.html @@ -0,0 +1,19 @@ + + + + 日本麻将助手 + + + +
+ + +
+ + + + From 07844a66eee01034ddf59a26bb7350c740728ae4 Mon Sep 17 00:00:00 2001 From: Wang Chengke Date: Sun, 12 Apr 2020 14:14:49 +0800 Subject: [PATCH 03/10] [webapi] send request periodically (via ajax) --- webapi/core.js | 96 ++++++++++------------------------------------- webapi/index.html | 6 ++- 2 files changed, 23 insertions(+), 79 deletions(-) diff --git a/webapi/core.js b/webapi/core.js index e11859f..bda8fac 100644 --- a/webapi/core.js +++ b/webapi/core.js @@ -3,11 +3,11 @@ function tile_img_url(index) { function label(index) { let offset = [0, 9, 18, 27, 34]; - let l = ["m", "s", "p", "z"]; + let l = ["m", "p", "s", "z"]; for (let i = 0; i < l.length; i++) { if (index < offset[i+1]) { - return (index - offset[i]) + l[i]; + return (index - offset[i] + 1) + l[i]; } } throw new Error("invalid index"); @@ -40,80 +40,22 @@ function show_tiles(data) { } } -var data = { - "counts": [ - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 0, - 2, - 0, - 0, - 0, - 0, - 0 - ], - "risk": [ - 6.8689162795508745, - 1.3130278422273782, - 14.364682863109048, - 26.086178013431933, - 0, - 3.996171693735499, - 26.609623463447978, - 10.24728615971008, - 4.707313155452437, - 1.62, - 12.041053092734451, - 4.955252900232019, - 4.019039743204979, - 31.297173259860788, - 22.897446084686777, - 13.089059187935034, - 21.93600580280426, - 20.047425288863106, - 2.1125103680057706, - 4.555635730858469, - 23.916679946635732, - 18.880975342227377, - 22.090670997703363, - 35.24169806753138, - 21.933339973317867, - 4.555635730858469, - 20.978551860920128, - 0, - 1.04143593387471, - 0, - 0.8999999999999999, - 2.519098836845261, - 0.14272041763341067, - 17.777878904753784 - ], - "timestamp": 0 +let interval = 1000; +var backoff = interval; + +function update_tile() { + $.getJSON("/api") + .done(function(data) { + show_tiles(data); + backoff = interval; + setTimeout(update_tile, interval); + }) + .fail(function( jqxhr, textStatus, error ) { + var err = textStatus + ", " + error; + console.log("Request Failed: " + err); + backoff = backoff * 2; + setTimeout(update_tile, backoff); + }); } -show_tiles(data) \ No newline at end of file +setTimeout(update_tile, interval); diff --git a/webapi/index.html b/webapi/index.html index 3b2cfce..edc7e86 100644 --- a/webapi/index.html +++ b/webapi/index.html @@ -10,10 +10,12 @@
- - + Waiting
+ + + From d2202b4d0b8a61282544b34fee7a1a949b76eb2e Mon Sep 17 00:00:00 2001 From: Wang Chengke Date: Sun, 12 Apr 2020 17:39:24 +0800 Subject: [PATCH 04/10] dump terminal output --- analysis.go | 23 ++++++----- cli.go | 103 +++++++++++++++++++++++----------------------- core.go | 10 +++-- interact.go | 4 +- main.go | 3 +- server.go | 2 +- webapi/core.js | 47 +++++++++++++++++++++ webapi/data.go | 37 +++++++++++++++++ webapi/index.html | 6 +++ 9 files changed, 166 insertions(+), 69 deletions(-) diff --git a/analysis.go b/analysis.go index 9e3c178..6633a39 100644 --- a/analysis.go +++ b/analysis.go @@ -3,6 +3,7 @@ package main import ( "github.com/EndlessCheng/mahjong-helper/util" "fmt" + "io" "strings" "github.com/fatih/color" "github.com/EndlessCheng/mahjong-helper/util/model" @@ -45,7 +46,7 @@ func humanHands(playerInfo *model.PlayerInfo) string { return humanHands } -func analysisPlayerWithRisk(playerInfo *model.PlayerInfo, mixedRiskTable riskTable) error { +func analysisPlayerWithRisk(writer io.Writer, playerInfo *model.PlayerInfo, mixedRiskTable riskTable) error { // 手牌 humanTiles := humanHands(playerInfo) fmt.Println(humanTiles) @@ -61,7 +62,7 @@ func analysisPlayerWithRisk(playerInfo *model.PlayerInfo, mixedRiskTable riskTab result13: result, mixedRiskTable: mixedRiskTable, } - r.printWaitsWithImproves13_oneRow() + r.printWaitsWithImproves13_oneRow(writer) case 2: // 分析手牌 shanten, results14, incShantenResults14 := util.CalculateShantenWithImproves14(playerInfo) @@ -87,8 +88,8 @@ func analysisPlayerWithRisk(playerInfo *model.PlayerInfo, mixedRiskTable riskTab // TODO: 接近流局时提示河底是哪家 // 何切分析结果 - printResults14WithRisk(results14, mixedRiskTable) - printResults14WithRisk(incShantenResults14, mixedRiskTable) + printResults14WithRisk(writer, results14, mixedRiskTable) + printResults14WithRisk(writer, incShantenResults14, mixedRiskTable) default: err := fmt.Errorf("参数错误: %d 张牌", countOfTiles) if debugMode { @@ -107,7 +108,7 @@ func analysisPlayerWithRisk(playerInfo *model.PlayerInfo, mixedRiskTable riskTab // isRedFive: 此舍牌是否为赤5 // allowChi: 是否能吃 // mixedRiskTable: 危险度表 -func analysisMeld(playerInfo *model.PlayerInfo, targetTile34 int, isRedFive bool, allowChi bool, mixedRiskTable riskTable) error { +func analysisMeld(writer io.Writer, playerInfo *model.PlayerInfo, targetTile34 int, isRedFive bool, allowChi bool, mixedRiskTable riskTable) error { if handsCount := util.CountOfTiles34(playerInfo.HandTiles34); handsCount%3 != 1 { return fmt.Errorf("手牌错误:%d 张牌 %v", handsCount, playerInfo.HandTiles34) } @@ -132,7 +133,7 @@ func analysisMeld(playerInfo *model.PlayerInfo, targetTile34 int, isRedFive bool result13: result, mixedRiskTable: mixedRiskTable, } - r.printWaitsWithImproves13_oneRow() + r.printWaitsWithImproves13_oneRow(writer) // 提示信息 // TODO: 局收支相近时,提示:局收支相近,追求和率打xx,追求打点打xx @@ -148,12 +149,12 @@ func analysisMeld(playerInfo *model.PlayerInfo, targetTile34 int, isRedFive bool // TODO: 接近流局时提示河底是哪家 // 鸣牌何切分析结果 - printResults14WithRisk(results14, mixedRiskTable) - printResults14WithRisk(incShantenResults14, mixedRiskTable) + printResults14WithRisk(writer, results14, mixedRiskTable) + printResults14WithRisk(writer, incShantenResults14, mixedRiskTable) return nil } -func analysisHumanTiles(humanTilesInfo *model.HumanTilesInfo) (playerInfo *model.PlayerInfo, err error) { +func analysisHumanTiles(writer io.Writer, humanTilesInfo *model.HumanTilesInfo) (playerInfo *model.PlayerInfo, err error) { defer func() { if er := recover(); er != nil { err = er.(error) @@ -231,13 +232,13 @@ func analysisHumanTiles(humanTilesInfo *model.HumanTilesInfo) (playerInfo *model if er != nil { return nil, er } - if er := analysisMeld(playerInfo, targetTile34, isRedFive, true, nil); er != nil { + if er := analysisMeld(writer, playerInfo, targetTile34, isRedFive, true, nil); er != nil { return nil, er } return } playerInfo.IsTsumo = humanTilesInfo.IsTsumo - err = analysisPlayerWithRisk(playerInfo, nil) + err = analysisPlayerWithRisk(writer, playerInfo, nil) return } diff --git a/cli.go b/cli.go index e334dc6..83e3da1 100644 --- a/cli.go +++ b/cli.go @@ -7,6 +7,7 @@ import ( "math" "sort" "strings" + "io" ) func printAccountInfo(accountID int) { @@ -464,7 +465,7 @@ type analysisResult struct { */ // 打印何切分析结果(单行) -func (r *analysisResult) printWaitsWithImproves13_oneRow() { +func (r *analysisResult) printWaitsWithImproves13_oneRow(writer io.Writer) { discardTile34 := r.discardTile34 openTiles34 := r.openTiles34 result13 := r.result13 @@ -474,19 +475,19 @@ func (r *analysisResult) printWaitsWithImproves13_oneRow() { // 进张数 waitsCount := result13.Waits.AllCount() c := getWaitsCountColor(shanten, float64(waitsCount)) - color.New(c).Printf("%2d", waitsCount) + color.New(c).Fprintf(writer, "%2d", waitsCount) // 改良进张均值 if len(result13.Improves) > 0 { if r.highlightAvgImproveWaitsCount { - color.New(color.FgHiWhite).Printf("[%5.2f]", result13.AvgImproveWaitsCount) + color.New(color.FgHiWhite).Fprintf(writer, "[%5.2f]", result13.AvgImproveWaitsCount) } else { - fmt.Printf("[%5.2f]", result13.AvgImproveWaitsCount) + fmt.Fprintf(writer, "[%5.2f]", result13.AvgImproveWaitsCount) } } else { - fmt.Print(strings.Repeat(" ", 7)) + fmt.Fprint(writer, strings.Repeat(" ", 7)) } - fmt.Print(" ") + fmt.Fprint(writer, " ") // 是否为3k+2张牌的何切分析 if discardTile34 != -1 { @@ -496,14 +497,14 @@ func (r *analysisResult) printWaitsWithImproves13_oneRow() { if openTiles34[0] == openTiles34[1] { meldType = "碰" } - color.New(color.FgHiWhite).Printf("%s%s", string([]rune(util.MahjongZH[openTiles34[0]])[:1]), util.MahjongZH[openTiles34[1]]) - fmt.Printf("%s,", meldType) + color.New(color.FgHiWhite).Fprintf(writer, "%s%s", string([]rune(util.MahjongZH[openTiles34[0]])[:1]), util.MahjongZH[openTiles34[1]]) + fmt.Fprintf(writer, "%s,", meldType) } // 舍牌 if r.isDiscardTileDora { - color.New(color.FgHiWhite).Print("ド") + color.New(color.FgHiWhite).Fprintf(writer, "ド") } else { - fmt.Print("切") + fmt.Fprint(writer, "切") } tileZH := util.MahjongZH[discardTile34] if discardTile34 >= 27 { @@ -513,71 +514,71 @@ func (r *analysisResult) printWaitsWithImproves13_oneRow() { // 若有实际危险度,则根据实际危险度来显示舍牌危险度 risk := r.mixedRiskTable[discardTile34] if risk == 0 { - fmt.Print(tileZH) + fmt.Fprint(writer, tileZH) } else { - color.New(getNumRiskColor(risk)).Print(tileZH) + color.New(getNumRiskColor(risk)).Fprint(writer, tileZH) } } else { - fmt.Print(tileZH) + fmt.Fprint(writer, tileZH) } } - fmt.Print(" => ") + fmt.Fprint(writer, " => ") if shanten >= 1 { // 前进后的进张数均值 incShanten := shanten - 1 c := getWaitsCountColor(incShanten, result13.AvgNextShantenWaitsCount) - color.New(c).Printf("%5.2f", result13.AvgNextShantenWaitsCount) - fmt.Printf("%s", util.NumberToChineseShanten(incShanten)) + color.New(c).Fprintf(writer, "%5.2f", result13.AvgNextShantenWaitsCount) + fmt.Fprintf(writer, "%s", util.NumberToChineseShanten(incShanten)) if incShanten >= 1 { - //fmt.Printf("进张") + //fmt.Fprintf(writer, "进张") } else { // incShanten == 0 - fmt.Printf("数") + fmt.Fprintf(writer, "数") //if showAgariAboveShanten1 { - // fmt.Printf("(%.2f%% 参考和率)", result13.AvgAgariRate) + // fmt.Fprintf(writer, "(%.2f%% 参考和率)", result13.AvgAgariRate) //} } } else { // shanten == 0 // 前进后的和率 // 若振听或片听,则标红 if result13.FuritenRate == 1 || result13.IsPartWait { - color.New(color.FgHiRed).Printf("%5.2f%% 参考和率", result13.AvgAgariRate) + color.New(color.FgHiRed).Fprintf(writer, "%5.2f%% 参考和率", result13.AvgAgariRate) } else { - fmt.Printf("%5.2f%% 参考和率", result13.AvgAgariRate) + fmt.Fprintf(writer, "%5.2f%% 参考和率", result13.AvgAgariRate) } } // 手牌速度,用于快速过庄 if result13.MixedWaitsScore > 0 && shanten >= 1 && shanten <= 2 { - fmt.Print(" ") + fmt.Fprint(writer, " ") if r.highlightMixedScore { - color.New(color.FgHiWhite).Printf("[%5.2f速度]", result13.MixedWaitsScore) + color.New(color.FgHiWhite).Fprintf(writer, "[%5.2f速度]", result13.MixedWaitsScore) } else { - fmt.Printf("[%5.2f速度]", result13.MixedWaitsScore) + fmt.Fprintf(writer, "[%5.2f速度]", result13.MixedWaitsScore) } } // 局收支 if showScore && result13.MixedRoundPoint != 0.0 { - fmt.Print(" ") - color.New(color.FgHiGreen).Printf("[局收支%4d]", int(math.Round(result13.MixedRoundPoint))) + fmt.Fprint(writer, " ") + color.New(color.FgHiGreen).Fprintf(writer, "[局收支%4d]", int(math.Round(result13.MixedRoundPoint))) } // (默听)荣和点数 if result13.DamaPoint > 0 { - fmt.Print(" ") + fmt.Fprint(writer, " ") ronType := "荣和" if !result13.IsNaki { ronType = "默听" } - color.New(color.FgHiGreen).Printf("[%s%d]", ronType, int(math.Round(result13.DamaPoint))) + color.New(color.FgHiGreen).Fprintf(writer, "[%s%d]", ronType, int(math.Round(result13.DamaPoint))) } // 立直点数,考虑了自摸、一发、里宝 if result13.RiichiPoint > 0 { - fmt.Print(" ") - color.New(color.FgHiGreen).Printf("[立直%d]", int(math.Round(result13.RiichiPoint))) + fmt.Fprint(writer, " ") + color.New(color.FgHiGreen).Fprintf(writer, "[立直%d]", int(math.Round(result13.RiichiPoint))) } if len(result13.YakuTypes) > 0 { @@ -594,64 +595,64 @@ func (r *analysisResult) printWaitsWithImproves13_oneRow() { } if len(shownYakuTypes) > 0 { sort.Ints(shownYakuTypes) - fmt.Print(" ") - color.New(color.FgHiGreen).Printf(util.YakuTypesToStr(shownYakuTypes)) + fmt.Fprint(writer, " ") + color.New(color.FgHiGreen).Fprintf(writer, util.YakuTypesToStr(shownYakuTypes)) } } else { // debug - fmt.Print(" ") - color.New(color.FgHiGreen).Printf(util.YakuTypesWithDoraToStr(result13.YakuTypes, result13.DoraCount)) + fmt.Fprint(writer, " ") + color.New(color.FgHiGreen).Fprintf(writer, util.YakuTypesWithDoraToStr(result13.YakuTypes, result13.DoraCount)) } // 片听 if result13.IsPartWait { - fmt.Print(" ") - color.New(color.FgHiRed).Printf("[片听]") + fmt.Fprint(writer, " ") + color.New(color.FgHiRed).Fprintf(writer, "[片听]") } } } else if result13.IsNaki && shanten >= 0 && shanten <= 2 { // 鸣牌时的无役提示(从听牌到两向听) - fmt.Print(" ") - color.New(color.FgHiRed).Printf("[无役]") + fmt.Fprint(writer, " ") + color.New(color.FgHiRed).Fprintf(writer, "[无役]") } // 振听提示 if result13.FuritenRate > 0 { - fmt.Print(" ") + fmt.Fprint(writer, " ") if result13.FuritenRate < 1 { - color.New(color.FgHiYellow).Printf("[可能振听]") + color.New(color.FgHiYellow).Fprintf(writer, "[可能振听]") } else { - color.New(color.FgHiRed).Printf("[振听]") + color.New(color.FgHiRed).Fprintf(writer, "[振听]") } } // 改良数 if showScore { - fmt.Print(" ") + fmt.Fprint(writer, " ") if len(result13.Improves) > 0 { - fmt.Printf("[%2d改良]", len(result13.Improves)) + fmt.Fprintf(writer, "[%2d改良]", len(result13.Improves)) } else { - fmt.Print(strings.Repeat(" ", 4)) - fmt.Print(strings.Repeat(" ", 2)) // 全角空格 + fmt.Fprint(writer, strings.Repeat(" ", 4)) + fmt.Fprint(writer, strings.Repeat(" ", 2)) // 全角空格 } } // 进张类型 - fmt.Print(" ") + fmt.Fprint(writer, " ") waitTiles := result13.Waits.AvailableTiles() - fmt.Print(util.TilesToStrWithBracket(waitTiles)) + fmt.Fprint(writer, util.TilesToStrWithBracket(waitTiles)) // - fmt.Println() + fmt.Fprintln(writer) if showImproveDetail { for tile, waits := range result13.Improves { - fmt.Printf("摸 %s 改良成 %s\n", util.Mahjong[tile], waits.String()) + fmt.Fprintf(writer, "摸 %s 改良成 %s\n", util.Mahjong[tile], waits.String()) } } } -func printResults14WithRisk(results14 util.Hand14AnalysisResultList, mixedRiskTable riskTable) { +func printResults14WithRisk(writer io.Writer, results14 util.Hand14AnalysisResultList, mixedRiskTable riskTable) { if len(results14) == 0 { return } @@ -705,6 +706,6 @@ func printResults14WithRisk(results14 util.Hand14AnalysisResultList, mixedRiskTa result.Result13.AvgImproveWaitsCount == maxAvgImproveWaitsCount, result.Result13.MixedWaitsScore == maxMixedScore, } - r.printWaitsWithImproves13_oneRow() + r.printWaitsWithImproves13_oneRow(writer) } } diff --git a/core.go b/core.go index cb31b2e..f25bd82 100644 --- a/core.go +++ b/core.go @@ -473,7 +473,11 @@ func (d *roundData) newModelPlayerInfo() *model.PlayerInfo { } func (d *roundData) analysis() error { + d.ApiData.Init() + writer := webapi.ApiDataConvertor{&d.ApiData} + defer func() { + d.ApiData.GetOutput() d.ApiData.Counts = d.counts }() @@ -589,7 +593,7 @@ func (d *roundData) analysis() error { color.HiYellow("宝牌指示牌是 " + info) fmt.Println() // TODO: 显示地和概率 - return analysisPlayerWithRisk(playerInfo, nil) + return analysisPlayerWithRisk(writer, playerInfo, nil) case d.parser.IsOpen(): // 某家鸣牌(含暗杠、加杠) who, meld, kanDoraIndicator := d.parser.ParseOpen() @@ -775,7 +779,7 @@ func (d *roundData) analysis() error { // 打印何切推荐 // TODO: 根据是否听牌/一向听、打点、巡目、和率等进行攻守判断 - return analysisPlayerWithRisk(playerInfo, mixedRiskTable) + return analysisPlayerWithRisk(writer, playerInfo, mixedRiskTable) case d.parser.IsDiscard(): who, discardTile, isRedFive, isTsumogiri, isReach, canBeMeld, kanDoraIndicator := d.parser.ParseDiscard() @@ -913,7 +917,7 @@ func (d *roundData) analysis() error { // 为了方便解析牌谱,这里尽可能地解析副露 // TODO: 提醒: 消除海底/避免河底 allowChi := d.playerNumber != 3 && who == 3 && playerInfo.LeftDrawTilesCount > 0 - return analysisMeld(playerInfo, discardTile, isRedFive, allowChi, mixedRiskTable) + return analysisMeld(writer, playerInfo, discardTile, isRedFive, allowChi, mixedRiskTable) case d.parser.IsRoundWin(): // TODO: 解析天凤牌谱 - 注意 skipOutput diff --git a/interact.go b/interact.go index 012188c..f89de00 100644 --- a/interact.go +++ b/interact.go @@ -16,7 +16,7 @@ func interact(humanTilesInfo *model.HumanTilesInfo) error { }() } - playerInfo, err := analysisHumanTiles(humanTilesInfo) + playerInfo, err := analysisHumanTiles(os.Stdout, humanTilesInfo) if err != nil { return err } @@ -67,7 +67,7 @@ func interact(humanTilesInfo *model.HumanTilesInfo) error { tiles34[tile]-- playerInfo.DiscardTiles = append(playerInfo.DiscardTiles, tile) // 仅判断振听用 } - if err := analysisPlayerWithRisk(playerInfo, nil); err != nil { + if err := analysisPlayerWithRisk(os.Stdout, playerInfo, nil); err != nil { fmt.Fprintln(os.Stderr, err) } } diff --git a/main.go b/main.go index 548a055..cc03de2 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "math/rand" "time" "flag" + "os" ) var ( @@ -131,7 +132,7 @@ func main() { case isInteractive: // 交互模式 err = interact(humanTilesInfo) case len(flag.Args()) > 0: // 静态分析 - _, err = analysisHumanTiles(humanTilesInfo) + _, err = analysisHumanTiles(os.Stdout, humanTilesInfo) default: // 服务器模式 choose := welcome() isHTTPS := choose == platformMajsoul diff --git a/server.go b/server.go index ee18044..59dc989 100644 --- a/server.go +++ b/server.go @@ -103,7 +103,7 @@ func (h *mjHandler) analysis(c echo.Context) error { return c.String(http.StatusBadRequest, err.Error()) } - if _, err := analysisHumanTiles(model.NewSimpleHumanTilesInfo(d.Tiles)); err != nil { + if _, err := analysisHumanTiles(os.Stdout, model.NewSimpleHumanTilesInfo(d.Tiles)); err != nil { fmt.Println(err) return c.String(http.StatusBadRequest, err.Error()) } diff --git a/webapi/core.js b/webapi/core.js index bda8fac..0931cdd 100644 --- a/webapi/core.js +++ b/webapi/core.js @@ -40,6 +40,52 @@ function show_tiles(data) { } } +function inline_img(line) { + function img_tag(index) { + return `` + } + + let pattern = [/(\d)万/, /(\d)饼/, /(\d)索/, + / ()东/, / ()南/, / ()西/, / ()北/, + / ()白/, / ()发/, / ()中/] + let offset = [-1, 8, 17, 27, 28, 29, 30, 31, 32, 33] + + for (let i = 0; i < pattern.length; i++) { + line = line.replace(pattern[i], function(_, j) { + return img_tag(offset[i] + (parseInt(j) || 0)) + }); + } + + + line = line.replace(/\[[\dmpsz ]*\]$/, function (s) { + let offset = { + 'm': 0, + 'p': 9, + 's': 18, + 'z': 27, + }; + return s.replace(/(\d+)(\w)/g, function(_, s, t) { + var result = ""; + for (var i = 0; i < s.length; i++) { + result += img_tag(parseInt(i) + offset[t]); + } + return result; + }) + }); + + return line; +} + +function show_outputs(outputs) { + let lines = outputs.replace(/\u001b\[\d*m/g, '').split('\n') + let result = lines.map(function(line) { + return `

${ inline_img(line) }

`; + }).join(''); + document.getElementById("outputs").innerHTML = result; +} + +// show_outputs("\u001b[96m39\u001b[0m\u001b[97m[47.04]\u001b[0m 切 南 => \u001b[96m22.95\u001b[0m两向听 [12345789m 7p 8s 37z]\n\u001b[96m39\u001b[0m\u001b[97m[47.04]\u001b[0m 切 西 => \u001b[96m22.95\u001b[0m两向听 [12345789m 7p 8s 27z]\n\u001b[96m31\u001b[0m[40.21] 切9万 => \u001b[96m20.10\u001b[0m两向听 [12345m 7p 8s 237z]\n\u001b[96m39\u001b[0m\u001b[97m[47.04]\u001b[0m 切 中 => \u001b[96m22.95\u001b[0m两向听 [12345789m 7p 8s 23z]\n\u001b[96m33\u001b[0m[39.99] 切3万 => \u001b[96m18.33\u001b[0m两向听 [14789m 7p 8s 237z]\n\u001b[96m28\u001b[0m[37.66] 切2万 => \u001b[96m14.00\u001b[0m两向听 [3789m 7p 8s 237z]\n\u001b[96m65\u001b[0m\u001b[97m[68.44]\u001b[0m 切9索 => \u001b[96m45.00\u001b[0m三向听 [12345789m 2347p 56789s 237z]\n\u001b[96m58\u001b[0m[63.13] 切7饼 => \u001b[96m44.83\u001b[0m三向听 [12345789m 56789p 8s 237z]\n\u001b[96m57\u001b[0m[61.50] 切7索 => \u001b[96m39.95\u001b[0m三向听 [12345789m 2347p 789s 237z]\n\u001b[96m61\u001b[0m[64.97] 切4饼 => \u001b[96m34.84\u001b[0m三向听 [12345789m 12347p 789s 237z]\n\u001b[96m61\u001b[0m[64.44] 切2饼 => \u001b[96m34.84\u001b[0m三向听 [12345789m 23457p 789s 237z]\n\u001b[96m57\u001b[0m[61.50] 切3饼 => \u001b[96m31.60\u001b[0m三向听 [12345789m 2347p 789s 237z]\n"); + let interval = 1000; var backoff = interval; @@ -47,6 +93,7 @@ function update_tile() { $.getJSON("/api") .done(function(data) { show_tiles(data); + show_outputs(data["outputs"]); backoff = interval; setTimeout(update_tile, interval); }) diff --git a/webapi/data.go b/webapi/data.go index a3ff33f..aa2c24f 100644 --- a/webapi/data.go +++ b/webapi/data.go @@ -1,5 +1,11 @@ package webapi +import ( + "os" + "io" + "bytes" +) + type ApiData struct { // 数据更新时间戳 Timestamp int `json:"timestamp"` @@ -9,6 +15,37 @@ type ApiData struct { // 手牌危险度 一个长度为 34 的浮点数组 RiskTable []float64 `json:"risk"` + + // 显示终端结果 + Outputs string `json:"outputs"` + + output_buffer bytes.Buffer +} + +func (data *ApiData) Init() { + data.output_buffer.Reset() +} + +func (data *ApiData) GetOutput() { + s := data.output_buffer.String() + if len(s) > 0 { + data.Outputs = s + } +} + +// implement the io.Writer interface +var _ io.Writer = (*ApiDataConvertor)(nil) +type ApiDataConvertor struct { + *ApiData } +func (writer ApiDataConvertor) Write(p []byte) (n int, err error) { + n, e := writer.output_buffer.Write(p) + if e != nil { + return n, e + } + return os.Stdout.Write(p) +} + + diff --git a/webapi/index.html b/webapi/index.html index edc7e86..66ca070 100644 --- a/webapi/index.html +++ b/webapi/index.html @@ -6,6 +6,9 @@ .tile { width: 50px; } + .small-tile { + width: 1.3em; + } @@ -13,6 +16,9 @@ Waiting +
+
+ From 36343a950f1872caa1810f859fbfcd422ff38a86 Mon Sep 17 00:00:00 2001 From: Wang Chengke Date: Mon, 13 Apr 2020 12:40:41 +0800 Subject: [PATCH 05/10] =?UTF-8?q?[fix]=20=E6=98=BE=E7=A4=BA=E8=BF=9B?= =?UTF-8?q?=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapi/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapi/core.js b/webapi/core.js index 0931cdd..a3d2596 100644 --- a/webapi/core.js +++ b/webapi/core.js @@ -67,7 +67,7 @@ function inline_img(line) { return s.replace(/(\d+)(\w)/g, function(_, s, t) { var result = ""; for (var i = 0; i < s.length; i++) { - result += img_tag(parseInt(i) + offset[t]); + result += img_tag(parseInt(s[i]) + offset[t]); } return result; }) From d3ef43875cf1efddf1f5b66e304dab91b38caee5 Mon Sep 17 00:00:00 2001 From: Wang Chengke Date: Mon, 13 Apr 2020 12:41:14 +0800 Subject: [PATCH 06/10] [fix] /regex/g --- webapi/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapi/core.js b/webapi/core.js index a3d2596..04b3239 100644 --- a/webapi/core.js +++ b/webapi/core.js @@ -45,7 +45,7 @@ function inline_img(line) { return `` } - let pattern = [/(\d)万/, /(\d)饼/, /(\d)索/, + let pattern = [/(\d)万/g, /(\d)饼/g, /(\d)索/g, / ()东/, / ()南/, / ()西/, / ()北/, / ()白/, / ()发/, / ()中/] let offset = [-1, 8, 17, 27, 28, 29, 30, 31, 32, 33] From e7afb1b80e5271eff2776686d8a56c2a9397994d Mon Sep 17 00:00:00 2001 From: Wang Chengke Date: Mon, 13 Apr 2020 12:46:20 +0800 Subject: [PATCH 07/10] =?UTF-8?q?[fix]=20=E6=98=BE=E7=A4=BA=E8=BF=9B?= =?UTF-8?q?=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapi/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapi/core.js b/webapi/core.js index 04b3239..4218764 100644 --- a/webapi/core.js +++ b/webapi/core.js @@ -67,7 +67,7 @@ function inline_img(line) { return s.replace(/(\d+)(\w)/g, function(_, s, t) { var result = ""; for (var i = 0; i < s.length; i++) { - result += img_tag(parseInt(s[i]) + offset[t]); + result += img_tag(parseInt(s[i]) - 1 + offset[t]); } return result; }) From 843ab863f62b3669f1738f751bccf56ee4bf7f1d Mon Sep 17 00:00:00 2001 From: Wang Chengke Date: Mon, 13 Apr 2020 13:11:41 +0800 Subject: [PATCH 08/10] =?UTF-8?q?[fix]=20=E8=A7=A3=E5=86=B3=E9=B8=A3?= =?UTF-8?q?=E7=89=8C=E6=97=B6=E5=80=99=E9=94=99=E8=AF=AF=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapi/core.js | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/webapi/core.js b/webapi/core.js index 4218764..7c6865f 100644 --- a/webapi/core.js +++ b/webapi/core.js @@ -42,38 +42,43 @@ function show_tiles(data) { function inline_img(line) { function img_tag(index) { - return `` + return ``; } - let pattern = [/(\d)万/g, /(\d)饼/g, /(\d)索/g, - / ()东/, / ()南/, / ()西/, / ()北/, - / ()白/, / ()发/, / ()中/] - let offset = [-1, 8, 17, 27, 28, 29, 30, 31, 32, 33] + let pattern = [/ ()东/, / ()南/, / ()西/, / ()北/, + / ()白/, / ()发/, / ()中/]; + let offset_p = [27, 28, 29, 30, 31, 32, 33]; for (let i = 0; i < pattern.length; i++) { line = line.replace(pattern[i], function(_, j) { - return img_tag(offset[i] + (parseInt(j) || 0)) + return img_tag(offset_p[i] + (parseInt(j) || 0)) }); } + let offset = { + 'm': 0, + 'p': 9, + 's': 18, + 'z': 27, + '万': 0, + '饼': 9, + '索': 18, + }; + + var keys = ""; + for (const [key, _] of Object.entries(offset)) { + keys = keys + key; + } - line = line.replace(/\[[\dmpsz ]*\]$/, function (s) { - let offset = { - 'm': 0, - 'p': 9, - 's': 18, - 'z': 27, - }; - return s.replace(/(\d+)(\w)/g, function(_, s, t) { - var result = ""; - for (var i = 0; i < s.length; i++) { - result += img_tag(parseInt(s[i]) - 1 + offset[t]); - } - return result; - }) - }); + let reg = new RegExp(`(\\d+)([${keys}])`, 'g'); - return line; + return line.replace(reg, function(_, s, t) { + var result = ""; + for (var i = 0; i < s.length; i++) { + result += img_tag(parseInt(s[i]) - 1 + offset[t]); + } + return result; + }); } function show_outputs(outputs) { From cc185002781f95c36ad03a0b5695ce9dda72ddbe Mon Sep 17 00:00:00 2001 From: Wang Chengke Date: Mon, 13 Apr 2020 15:46:58 +0800 Subject: [PATCH 09/10] =?UTF-8?q?=E7=94=A8=E4=B8=8D=E5=90=8C=E7=9A=84?= =?UTF-8?q?=E9=A2=9C=E8=89=B2=E8=A1=A8=E7=A4=BA=E5=8D=B1=E9=99=A9=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapi/core.js | 115 ++++++++++++++++++++++++++++++++++++++++++++-- webapi/index.html | 1 + 2 files changed, 113 insertions(+), 3 deletions(-) diff --git a/webapi/core.js b/webapi/core.js index 7c6865f..2557bad 100644 --- a/webapi/core.js +++ b/webapi/core.js @@ -1,5 +1,115 @@ "use strict"; +let maj_risk = (function() { + +// https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c + +/** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. + * + * @param {number} h The hue + * @param {number} s The saturation + * @param {number} l The lightness + * @return {Array} The RGB representation + */ +function hslToRgb(h, s, l){ + var r, g, b; + + if(s == 0){ + r = g = b = l; // achromatic + }else{ + var hue2rgb = function hue2rgb(p, q, t){ + if(t < 0) t += 1; + if(t > 1) t -= 1; + if(t < 1/6) return p + (q - p) * 6 * t; + if(t < 1/2) return q; + if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; + return p; + } + + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3); + } + + return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; +} + +/** + * Converts an RGB color value to HSL. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes r, g, and b are contained in the set [0, 255] and + * returns h, s, and l in the set [0, 1]. + * + * @param {number} r The red color value + * @param {number} g The green color value + * @param {number} b The blue color value + * @return {Array} The HSL representation + */ +function rgbToHsl(r, g, b){ + r /= 255, g /= 255, b /= 255; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min){ + h = s = 0; // achromatic + }else{ + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max){ + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + + return [h, s, l]; +} + +let gradient = [ + { risk: 0.0 , color: [255, 255, 255] }, // 绝安,白色 + { risk: 1e-5 , color: [131, 179, 17] }, // 只要有一点风险,鸭绿色 + { risk: 8 , color: [250, 195, 0] }, // 还可以冲一冲, 橙黄色 + { risk: 16 , color: [253, 99, 0] }, // 相当危险,粉色 + { risk: 25.0, color: [253, 0, 135] }, // 绝对危险, 红色 +]; + +// https://stackoverflow.com/questions/4856717/javascript-equivalent-of-pythons-zip-function +let zip = rows=>rows[0].map((_,c)=>rows.map(row=>row[c])); + +return { + get_rist_color(risk) { + risk = Math.min(risk, gradient[gradient.length-1].risk); + + for (let i = 0; i + 1 < gradient.length; i++) { + if (risk <= gradient[i + 1].risk) { + // let left = rgbToHsl.apply(null, gradient[i].color); + // let right = rgbToHsl.apply(null, gradient[i + 1].color); + let left = gradient[i].color; + let right = gradient[i+1].color; + // interpolation in RGB color space + // HSL 效果似乎并不如人意 + let ratio = (risk - gradient[i].risk) / (gradient[i + 1].risk - gradient[i].risk); + let result = zip([left, right]).map(([x, y]) => x + (y - x) * ratio); + + // let rgba = hslToRgb.apply(null, (result)).join(','); + let rgba = result; + return `rgba(${rgba})`; + } + } + + throw "can not find a color for the risk " + risk; + } +}; + +})(); // closure for maj_risk + function tile_img_url(index) { function label(index) { let offset = [0, 9, 18, 27, 34]; @@ -27,14 +137,13 @@ function show_tiles(data) { for (let i = 0; i < 34; i++) { var risk = data["risk"] === null ? 0 : data["risk"][i]; - risk = risk / 25; - risk = Math.min(risk, 1.0); + let count = data["counts"][i]; for (let c = 0; c < count; c++) { let img = document.createElement("img"); img.src = tile_img_url(i); img.classList.add("tile"); - img.style.border = `solid 3px rgba(255, 0, 0, ${risk})`; + img.style.border = `solid 3px ${maj_risk.get_rist_color(risk)}`; container.appendChild(img); } } diff --git a/webapi/index.html b/webapi/index.html index 66ca070..2b0d181 100644 --- a/webapi/index.html +++ b/webapi/index.html @@ -5,6 +5,7 @@