+140
-132
@@ -1,29 +0,32 @@ | ||
| 'use strict' | ||
| const assert = require('assert') | ||
| const sum = (arr)=>{ | ||
| let s = 0 | ||
| for (let i in arr) | ||
| s += arr[i] | ||
| return s | ||
| } | ||
| const check7 = (haiArr)=>{ | ||
| let arr = haiArr[0].concat(haiArr[1]).concat(haiArr[2]).concat(haiArr[3]) | ||
| let s = 0 | ||
| for (let i in arr) { | ||
| if (arr[i] && arr[i] != 2) return false | ||
| s += arr[i] | ||
| /* | ||
| * @Copyright https://github.com/takayama-lily/agari | ||
| */ | ||
| (()=>{ | ||
| 'use strict' | ||
| const sum = (arr)=>{ | ||
| let s = 0 | ||
| for (let i = 0; i < arr.length; i++) | ||
| s += arr[i] | ||
| return s | ||
| } | ||
| return s == 14 | ||
| } | ||
| const check13 = (haiArr)=>{ | ||
| let arr = [haiArr[0][0], haiArr[0][8], haiArr[1][0], haiArr[1][8], haiArr[2][0], haiArr[2][8]].concat(haiArr[3]) | ||
| return arr.indexOf(0) == -1 && sum(arr) == 14 | ||
| } | ||
| const check = (haiArr)=>{ | ||
| const _check = (e, isJihai = false)=>{ | ||
| let arr = e.concat() | ||
| if (!sum(arr)) | ||
| const check7 = (hai_arr)=>{ | ||
| let arr = [...hai_arr[0], ...hai_arr[1], ...hai_arr[2], ...hai_arr[3]] | ||
| let s = 0 | ||
| for (let i = 0; i < arr.length; i++) { | ||
| if (arr[i] && arr[i] != 2) return false | ||
| s += arr[i] | ||
| } | ||
| return s == 14 | ||
| } | ||
| const check13 = (hai_arr)=>{ | ||
| let arr = [hai_arr[0][0], hai_arr[0][8], hai_arr[1][0], hai_arr[1][8], hai_arr[2][0], hai_arr[2][8], ...hai_arr[3]] | ||
| return !arr.includes(0) && sum(arr) == 14 | ||
| } | ||
| const _check = (arr, is_jihai = false)=>{ | ||
| arr = [...arr] | ||
| let s = sum(arr) | ||
| if (s === 0) | ||
| return true | ||
| if (sum(arr) % 3 == 2) { | ||
| for (let i in arr) { | ||
| if (s % 3 == 2) { | ||
| for (let i = 0; i < arr.length; i++) { | ||
| if (arr[i] >= 2) | ||
@@ -33,3 +36,3 @@ arr[i] -= 2 | ||
| continue | ||
| if (!_check(arr, isJihai)) | ||
| if (!_check(arr, is_jihai)) | ||
| arr[i] += 2 | ||
@@ -41,14 +44,13 @@ else | ||
| } | ||
| for (let i in arr) { | ||
| if (!arr[i]) { | ||
| for (let i = 0; i < arr.length; i++) { | ||
| if (arr[i] === 0) { | ||
| continue | ||
| } else if (arr[i] == 3) { | ||
| } else if (arr[i] === 3) { | ||
| delete arr[i] | ||
| continue | ||
| } else { | ||
| if (isJihai || i >= 7) | ||
| if (is_jihai || i >= 7) | ||
| return false | ||
| if (arr[i] == 4) | ||
| if (arr[i] === 4) | ||
| arr[i] -= 3 | ||
| i = parseInt(i) | ||
| arr[i+1] -= arr[i] | ||
@@ -63,35 +65,32 @@ arr[i+2] -= arr[i] | ||
| } | ||
| let j = 0 | ||
| for (let i in haiArr) { | ||
| if (sum(haiArr[i]) % 3 == 1) | ||
| return false | ||
| j += sum(haiArr[i]) % 3 == 2 | ||
| const check = (hai_arr)=>{ | ||
| let j = 0 | ||
| for (let i = 0; i < hai_arr.length; i++) { | ||
| if (sum(hai_arr[i]) % 3 === 1) | ||
| return false | ||
| j += sum(hai_arr[i]) % 3 === 2 | ||
| } | ||
| return j === 1 && _check(hai_arr[3], true) && _check(hai_arr[0]) && _check(hai_arr[1]) && _check(hai_arr[2]) | ||
| } | ||
| return j == 1 && _check(haiArr[3], true) && _check(haiArr[0]) && _check(haiArr[1]) && _check(haiArr[2]) | ||
| } | ||
| const checkAll = (haiArr)=>{ | ||
| return check7(haiArr) || check13(haiArr) || check(haiArr) | ||
| } | ||
| const findAllAgariPatterns = (haiArr)=>{ | ||
| const checkAll = (hai_arr)=>{ | ||
| return check7(hai_arr) || check13(hai_arr) || check(hai_arr) | ||
| } | ||
| const MPSZ = ['m','p','s','z'] | ||
| haiArr = JSON.parse(JSON.stringify(haiArr)) | ||
| let res = [] | ||
| const sumAll = (haiArr)=>{ | ||
| const sumAll = (hai_arr)=>{ | ||
| let s = 0 | ||
| for (let arr of haiArr) | ||
| for (let arr of hai_arr) | ||
| s += sum(arr) | ||
| return s | ||
| } | ||
| const findKotsu = (haiArr)=>{ | ||
| const findKotsu = (hai_arr)=>{ | ||
| let res = [] | ||
| for (let i in haiArr) { | ||
| i = parseInt(i) | ||
| for (let ii in haiArr[i]) { | ||
| ii = parseInt(ii) | ||
| if (haiArr[i][ii] >= 3) { | ||
| haiArr[i][ii] -= 3 | ||
| if (check(haiArr)) { | ||
| for (let i = 0; i < hai_arr.length; i++) { | ||
| for (let ii = 0; ii < hai_arr[i].length; ii++) { | ||
| if (hai_arr[i][ii] >= 3) { | ||
| hai_arr[i][ii] -= 3 | ||
| if (check(hai_arr)) { | ||
| res.push([ii+1+MPSZ[i]]) | ||
| } else { | ||
| haiArr[i][ii] += 3 | ||
| hai_arr[i][ii] += 3 | ||
| } | ||
@@ -103,20 +102,18 @@ } | ||
| } | ||
| const findJyuntsu = (haiArr)=>{ | ||
| const findJyuntsu = (hai_arr)=>{ | ||
| let res = [] | ||
| for (let i in haiArr) { | ||
| i = parseInt(i) | ||
| for (let i = 0; i < hai_arr.length; i++) { | ||
| if (i === 3) | ||
| break | ||
| for (let ii in haiArr[i]) { | ||
| ii = parseInt(ii) | ||
| while (haiArr[i][ii] >= 1 && haiArr[i][ii+1] >= 1 && haiArr[i][ii+2] >= 1) { | ||
| haiArr[i][ii]-- | ||
| haiArr[i][ii+1]-- | ||
| haiArr[i][ii+2]-- | ||
| if (check(haiArr)) { | ||
| for (let ii = 0; ii < hai_arr[i].length; ii++) { | ||
| while (hai_arr[i][ii] >= 1 && hai_arr[i][ii+1] >= 1 && hai_arr[i][ii+2] >= 1) { | ||
| hai_arr[i][ii]-- | ||
| hai_arr[i][ii+1]-- | ||
| hai_arr[i][ii+2]-- | ||
| if (check(hai_arr)) { | ||
| res.push([ii+1+MPSZ[i], ii+2+MPSZ[i], ii+3+MPSZ[i]]) | ||
| } else { | ||
| haiArr[i][ii]++ | ||
| haiArr[i][ii+1]++ | ||
| haiArr[i][ii+2]++ | ||
| hai_arr[i][ii]++ | ||
| hai_arr[i][ii+1]++ | ||
| hai_arr[i][ii+2]++ | ||
| break | ||
@@ -130,6 +127,4 @@ } | ||
| const findJyanto = (haiArr)=>{ | ||
| for (let i in haiArr) { | ||
| i = parseInt(i) | ||
| for (let ii in haiArr[i]) { | ||
| ii = parseInt(ii) | ||
| for (let i = 0; i < hai_arr.length; i++) { | ||
| for (let ii = 0; ii < hai_arr[i].length; ii++) { | ||
| if (haiArr[i][ii] >= 2) { | ||
@@ -141,69 +136,82 @@ return ii+1+MPSZ[i] | ||
| } | ||
| const calc = (haiArr, j)=> { | ||
| let tmpHaiArr = JSON.parse(JSON.stringify(haiArr)) | ||
| let firstRes = findKotsu(tmpHaiArr).concat(j) | ||
| if (sumAll(tmpHaiArr) === 2) { | ||
| res.push(firstRes.sort()) | ||
| } else if (firstRes.length > 0) { | ||
| firstRes = firstRes.concat(findJyuntsu(tmpHaiArr)) | ||
| res.push(firstRes.sort()) | ||
| let res = [] | ||
| const calc = (hai_arr, j)=> { | ||
| let tmp_hai_arr = [[...hai_arr[0]], [...hai_arr[1]], [...hai_arr[2]], [...hai_arr[3]]] | ||
| let first_res = findKotsu(tmp_hai_arr).concat(j) | ||
| if (sumAll(tmp_hai_arr) === 2) { | ||
| res.push(first_res.sort()) | ||
| } else if (first_res.length > 0) { | ||
| first_res = first_res.concat(findJyuntsu(tmp_hai_arr)) | ||
| res.push(first_res.sort()) | ||
| } | ||
| tmpHaiArr = JSON.parse(JSON.stringify(haiArr)) | ||
| let secondRes = findJyuntsu(tmpHaiArr).concat(j) | ||
| if (sumAll(tmpHaiArr) === 2) { | ||
| res.push(secondRes.sort()) | ||
| tmp_hai_arr = [[...hai_arr[0]], [...hai_arr[1]], [...hai_arr[2]], [...hai_arr[3]]] | ||
| let second_res = findJyuntsu(tmp_hai_arr).concat(j) | ||
| if (sumAll(tmp_hai_arr) === 2) { | ||
| res.push(second_res.sort()) | ||
| } else { | ||
| secondRes = secondRes.concat(findKotsu(tmpHaiArr)) | ||
| res.push(secondRes.sort()) | ||
| second_res = second_res.concat(findKotsu(tmp_hai_arr)) | ||
| res.push(second_res.sort()) | ||
| } | ||
| } | ||
| if (!check(haiArr)) { | ||
| return res | ||
| } | ||
| if (sumAll(haiArr) === 2) { | ||
| res.push([findJyanto(haiArr)]) | ||
| return res | ||
| } | ||
| let j | ||
| for (let i in haiArr[3]) { | ||
| i = parseInt(i) | ||
| if (!haiArr[3][i]) { | ||
| haiArr[3][i] += 2 | ||
| j = i | ||
| break | ||
| const findAllAgariPatterns = (hai_arr)=>{ | ||
| hai_arr = [[...hai_arr[0]], [...hai_arr[1]], [...hai_arr[2]], [...hai_arr[3]]] | ||
| res = [] | ||
| if (!check(hai_arr)) { | ||
| return res | ||
| } | ||
| } | ||
| for (let i in haiArr) { | ||
| i = parseInt(i) | ||
| for (let ii in haiArr[i]) { | ||
| ii = parseInt(ii) | ||
| if (i === 3 && ii === j) | ||
| continue | ||
| if (haiArr[i][ii] >= 2) { | ||
| haiArr[i][ii] -= 2 | ||
| if (check(haiArr)) { | ||
| calc(haiArr, ii+1+MPSZ[i]) | ||
| if (sumAll(hai_arr) === 2) { | ||
| res.push([findJyanto(hai_arr)]) | ||
| return res | ||
| } | ||
| let j | ||
| for (let i = 0; i < hai_arr[3].length; i++) { | ||
| if (hai_arr[3][i] === 0) { | ||
| hai_arr[3][i] += 2 | ||
| j = i | ||
| break | ||
| } | ||
| } | ||
| for (let i = 0; i < hai_arr.length; i++) { | ||
| for (let ii = 0; ii < hai_arr[i].length; ii++) { | ||
| if (i === 3 && ii === j) | ||
| continue | ||
| if (hai_arr[i][ii] >= 2) { | ||
| hai_arr[i][ii] -= 2 | ||
| if (check(hai_arr)) | ||
| calc(hai_arr, ii+1+MPSZ[i]) | ||
| hai_arr[i][ii] += 2 | ||
| } | ||
| haiArr[i][ii] += 2 | ||
| } | ||
| } | ||
| } | ||
| let finalRes = [] | ||
| for (let v of res) { | ||
| let isDouble = false | ||
| for (let vv of finalRes) { | ||
| try { | ||
| assert.deepStrictEqual(v, vv) | ||
| isDouble = true | ||
| } catch(e) {} | ||
| let final_res = [] | ||
| for (let v of res) { | ||
| let is_duplicate = false | ||
| for (let vv of final_res) { | ||
| if (JSON.stringify(v) === JSON.stringify(vv)) | ||
| is_duplicate = true | ||
| } | ||
| if (!is_duplicate) | ||
| final_res.push(v) | ||
| } | ||
| if (!isDouble) | ||
| finalRes.push(v) | ||
| return final_res | ||
| } | ||
| return finalRes | ||
| } | ||
| module.exports = findAllAgariPatterns //一般形限定 | ||
| module.exports.check = check //一般形 | ||
| module.exports.check7 = check7 //七対子形 | ||
| module.exports.check13 = check13 //国士形 | ||
| module.exports.checkAll = checkAll //全部形 | ||
| const exports = findAllAgariPatterns //全和了pattern(一般形限定) | ||
| exports.check = check //一般形 | ||
| exports.check7 = check7 //七対子形 | ||
| exports.check13 = check13 //国士形 | ||
| exports.checkAll = checkAll //全形 | ||
| if (typeof module === 'object' && module && module.exports) { | ||
| module.exports = exports | ||
| } | ||
| else if (typeof define === 'function' && define.amd) { | ||
| define(()=>{ | ||
| return exports | ||
| }) | ||
| } | ||
| else if (typeof self === 'object' && self) { | ||
| self.agari = exports | ||
| } | ||
| })() |
+3
-6
| { | ||
| "name": "agari", | ||
| "version": "0.0.1", | ||
| "description": "Japanese riichi mahjong hand agari calculation", | ||
| "version": "1.0.0", | ||
| "description": "Japanese riichi mahjong agari calculation", | ||
| "main": "index.js", | ||
@@ -16,6 +16,3 @@ "scripts": { | ||
| "mahjong", | ||
| "agari", | ||
| "hand", | ||
| "calculation", | ||
| "Japan" | ||
| "agari" | ||
| ], | ||
@@ -22,0 +19,0 @@ "author": "takayama <takayama@foxmail.com>", |
+20
-5
| ## Agari | ||
| 麻雀アガリ和了形計算 | ||
@@ -6,9 +7,18 @@ Japanese riichi mahjong hand agari calculation | ||
| **Install with npm:** | ||
| ```shell | ||
| # npm i agari | ||
| ``` | ||
| $ npm i agari | ||
| **Use in browser:** | ||
| ```html | ||
| <script src="https://cdn.jsdelivr.net/npm/agari/index.js"></script> | ||
| ``` | ||
| **Usage:** | ||
| ```js | ||
| const agari = require('agari') | ||
| let haiArr = [ | ||
| let hai = [ | ||
| [3,1,1,3,0,0,0,0,0], //萬子 | ||
@@ -19,7 +29,10 @@ [3,0,0,0,0,0,0,0,0], //筒子 | ||
| ] | ||
| console.log(agari(haiArr)) | ||
| console.log(agari(hai)) | ||
| ``` | ||
| Output: | ||
| ```js | ||
| [ | ||
| //和了形1 | ||
| [ | ||
@@ -32,2 +45,3 @@ '1m', //雀頭 | ||
| ], | ||
| //和了形2 | ||
| [ | ||
@@ -42,3 +56,3 @@ [ '1m' ], //刻子 | ||
| ``` | ||
| You will get an array result includes all the patterns of the agari. | ||
| "m,p,s,z" means "萬子,筒子,索子,字牌" | ||
@@ -48,2 +62,3 @@ "1z-7z" means "東南西北白發中" | ||
| **Check only:** | ||
| ```js | ||
@@ -78,7 +93,7 @@ const agari = require('agari') | ||
| agari.checkAll([ | ||
| [1,1,1,1,1,0,0,0,0], | ||
| [0,0,0,0,0,0,0,0,0], | ||
| [0,0,0,0,0,0,0,0,0], | ||
| [0,0,0,0,0,0,0,0,0], | ||
| [0,0,0,0,0,0,0] | ||
| ]) //return boolean | ||
| ``` |
+21
-21
| 'use strict' | ||
| const assert = require('assert') | ||
| const agari = require('./index') | ||
| const testCases = [ | ||
| const test_cases = [ | ||
| [ | ||
@@ -31,25 +31,25 @@ [2,2,0,2,0,0,2,2,2], | ||
| assert.deepStrictEqual(agari.check(testCases[0]), false) | ||
| assert.deepStrictEqual(agari.check(testCases[1]), false) | ||
| assert.deepStrictEqual(agari.check(testCases[2]), true) | ||
| assert.deepStrictEqual(agari.check(testCases[3]), true) | ||
| assert.deepStrictEqual(agari.check(test_cases[0]), false) | ||
| assert.deepStrictEqual(agari.check(test_cases[1]), false) | ||
| assert.deepStrictEqual(agari.check(test_cases[2]), true) | ||
| assert.deepStrictEqual(agari.check(test_cases[3]), true) | ||
| assert.deepStrictEqual(agari.check7(testCases[0]), true) | ||
| assert.deepStrictEqual(agari.check7(testCases[1]), false) | ||
| assert.deepStrictEqual(agari.check7(testCases[2]), false) | ||
| assert.deepStrictEqual(agari.check7(testCases[3]), true) | ||
| assert.deepStrictEqual(agari.check7(test_cases[0]), true) | ||
| assert.deepStrictEqual(agari.check7(test_cases[1]), false) | ||
| assert.deepStrictEqual(agari.check7(test_cases[2]), false) | ||
| assert.deepStrictEqual(agari.check7(test_cases[3]), true) | ||
| assert.deepStrictEqual(agari.check13(testCases[0]), false) | ||
| assert.deepStrictEqual(agari.check13(testCases[1]), true) | ||
| assert.deepStrictEqual(agari.check13(testCases[0]), false) | ||
| assert.deepStrictEqual(agari.check13(testCases[1]), true) | ||
| assert.deepStrictEqual(agari.check13(test_cases[0]), false) | ||
| assert.deepStrictEqual(agari.check13(test_cases[1]), true) | ||
| assert.deepStrictEqual(agari.check13(test_cases[0]), false) | ||
| assert.deepStrictEqual(agari.check13(test_cases[1]), true) | ||
| assert.deepStrictEqual(agari.checkAll(testCases[0]), true) | ||
| assert.deepStrictEqual(agari.checkAll(testCases[1]), true) | ||
| assert.deepStrictEqual(agari.checkAll(testCases[0]), true) | ||
| assert.deepStrictEqual(agari.checkAll(testCases[1]), true) | ||
| assert.deepStrictEqual(agari.checkAll(test_cases[0]), true) | ||
| assert.deepStrictEqual(agari.checkAll(test_cases[1]), true) | ||
| assert.deepStrictEqual(agari.checkAll(test_cases[0]), true) | ||
| assert.deepStrictEqual(agari.checkAll(test_cases[1]), true) | ||
| assert.deepStrictEqual(agari(testCases[0]), []) | ||
| assert.deepStrictEqual(agari(testCases[1]), []) | ||
| assert.deepStrictEqual(agari(testCases[2]), [ [ '3s', | ||
| assert.deepStrictEqual(agari(test_cases[0]), []) | ||
| assert.deepStrictEqual(agari(test_cases[1]), []) | ||
| assert.deepStrictEqual(agari(test_cases[2]), [ [ '3s', | ||
| [ '6m', '7m', '8m' ], | ||
@@ -60,3 +60,3 @@ [ '6m', '7m', '8m' ], | ||
| assert.deepStrictEqual(agari(testCases[3]), [ [ '1m', | ||
| assert.deepStrictEqual(agari(test_cases[3]), [ [ '1m', | ||
| [ '2m', '3m', '4m' ], | ||
@@ -63,0 +63,0 @@ [ '2m', '3m', '4m' ], |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
13393
6.8%328
1.23%0
-100%94
18.99%