5
\$\begingroup\$

Mahjong is a tabletop game played using tiles. It features three "number" suits (pins, sous, mans, represented as p, s and m) from 1 to 9, and one "honor" suit z of seven distinct tiles. Note that contrary to western card games, tiles are not unique.

https://user-images.githubusercontent.com/5595067/33491135-4ac4b4e6-d6f4-11e7-8df6-038f113fcef9.png

To complete a hand and win, the 13 tiles in your hand are combined with 1 newly drawn tile and must result in one of the following winning configurations:

  • 4 sets and 1 pair, self-explanatory
  • seven pairs, where all pairs are distinct (twice the same pair wouldn't qualify)
  • kokushi musou: one of each of the 1 and 9 of each number suit, one of every seven honors, the remaining tile forming a pair (e.g. 19m19p19s11234567z)

A pair is any of the two same tiles: 11m, 33s, 44p, 55z, etc.

A set consists of 3 tiles of the same suit. It can either be a run: 3 number tiles (p, s or m) in a connected run like 123s or 234s, but not 1m 2p 3s or 234z; or a triplet of any suit, not necessarily numbers, like 111z, 222m.

So honor tiles (non-numbers, represented by z) can only form pairs or triplets, but not runs. 567z is not a set, 555z is a valid set, 55z is a valid pair.

A single tile can only be counted as part of one set or pair: there is no sharing or reusing.

Given a sorted hand of 13 tiles and one tile, check whether the 14 tiles make up a completed hand.

Input & Output

  • You are given a sequence of numbers and letters, a space, then a tile of a number and a letter
  • Output True/1 if the set is a match, else False/0

Others:

  • You are allowed to input the sequence and tile+letter as a list/array

Test Cases:

Truthy

222888m444p2277z 7z
234m45789p45688s 6p
11m4477p8899s116z 6z
19m19p19s1234567z 6z
123345567789m3p 3p

Falsey

1122335778899m 1m
888m55s11222333z 4z
234m2233445566p 4p
19m139p19s123567z 4z
11m4477p8899s666z 6z

Credits to Unihedron for the puzzle!

Scoring

This is code-golf, so shortest code wins!

\$\endgroup\$
8
  • \$\begingroup\$ Can we take input as 1m 2m 3m etc? \$\endgroup\$
    – emanresu A
    Feb 9 at 4:32
  • \$\begingroup\$ yes you can although im not sure it that changes the challenge too much \$\endgroup\$
    – DialFrost
    Feb 9 at 4:36
  • \$\begingroup\$ Borderline dupe of mahjong solver, since the main task is to check if a 14-tile set is a winning hand (the linked challenge just requires to do the same thing for every possible 14th tile). FYI, there has been four different mahjong-related challenges already. \$\endgroup\$
    – Bubbler
    Feb 9 at 6:30
  • \$\begingroup\$ Since points (fan / han) related rules are not considered in this question. Is there any reason to place the last tile independently from the others? \$\endgroup\$
    – tsh
    Feb 9 at 7:08
  • 1
    \$\begingroup\$ @Bubbler The linked question have a slightly different rules: This one includes 7 pairs and 13 orphans while that one don't. The shantin question seems using a similar rule, while it could be more complex than the one you linked. \$\endgroup\$
    – tsh
    Feb 9 at 8:38

3 Answers 3

5
\$\begingroup\$

JavaScript (Node.js), 248 246 245 bytes

s=>s.sort().every((t,i)=>t==s[i^1]&t!=s[n=12,i+2])|A(s)|[...new Set(s)].length>n
A=y=>y.some(t=>R(y,t,t,t)|t[n+=t>'2'&t<'9'&t[1]<A,1]<A&R(y,t,t[0]-1+t[1],t[0]-2+t[1]))|y[0]==y[1]&!y[2]
R=(s,p,q,r,z=0,k=s.filter(y=>y!=p||z++))=>p?z&&R(k,q,r):A(s)

Try it online!

Every answer is in js...

f is the main function, relying on A modifying n for non-1919191234567 check

A check if it's 3+3+3+3+2

R removes some triplet and go on Aing

\$\endgroup\$
3
\$\begingroup\$

Javascript (SpiderMonkey), 807 bytes

[a,[b,c]]=readline(j=m=0).split` `
d=[...h='mpsz'].map(k=>!~(i=a.indexOf(k))?'':a.slice([j,j=i+1][0],i))
d[i=h.indexOf(c)]=[...d[i]].concat(b).sort().join``
if(~(''+d).search`(1+9+,){3}1+2+3+4+5+6+7`|d.every(k=>/^(?:(.)\1(?!\1))*$/.test(k)))print(1);else A:{a=/(.)(\1*)/g;e=d.pop();while(n=a.exec(e))if(!n[2]){print(0);break A}else if(n[2].length==1)if(m){print(0);break A}else m=1
f=l=>{if(!l.length)return;var[h,n,b]=l;if((a=n-h)>1)return 1;i=l.indexOf(+n+1);if(a==1)return!~i?1:f(l.slice(2,i)+l.slice(i+1));if(~i){c=l.slice(1,i)+l.slice(i+1,i=l.indexOf(+n+2))+l.slice(i+1);if(~i&&!f(c))return}return n-b||f(l.slice(3))};m=d.filter(k=>{if(!(c=k.length%3))return f(k);else if(c==2){r=/(.)\1/g;while(n=r.exec(k))if(!f(k.slice(0,n.index)+k.slice(r.lastIndex)))return m=1,0}return 1}).length?0:m
print(m?1:0)}

Try it online!

First js post!

\$\endgroup\$
1
  • 5
    \$\begingroup\$ Not a big deal, but the typical etiquette is to wait a week or more before answering your own question. \$\endgroup\$
    – Jonah
    Feb 9 at 5:43
1
\$\begingroup\$

JavaScript, 348 bytes

a=>[[(P=f=>w=>f(w)&&1-w.some((n,i)=>n>1&!f(W=[...w],W[i]-=2))/2)(w=>w.some(n=>([p,q]=[q,(n-p-q)%3],1/q<0),p=q=0)),P(w=>w.some(n=>n%3)),],[w=>w.some(n=>n&-3)],[w=>w.some((n,i)=>i%8==1^n>0),w=>w.some((n,i)=>0<i&i<8^n>0)]].some(([i,I=i])=>i(n`m`)+i(n`p`)+i(n`s`)+I(n`z`)<1,n=t=>[...a.matchAll(`\\d(?=\\d*${t})`)].map(i=>s[i]++,s=Array(12).fill(0))&&s)

Passed all testcases. Though it may still be buggy. Comment any failed testcases, and I will try to fix them.

a=>[[
  // given count of each tiles in same suit
  // return 1 if it is not a valid hand
  // return 0.5 if it is a valid hand with a pair
  // return 0 if it is a valid hand without a pair
  (P=f=>w=>f(w)&&1-w.some((n,i)=>n>1&!f(W=[...w],W[i]-=2))/2)
  // for m, p, s
   (w=>w.some(n=>([p,q]=[q,(n-p-q)%3],1/q<0),p=q=0)),
  // for z
  P(w=>w.some(n=>n%3)),
],[
  // for 7 pairs rule
  w=>w.some(n=>n&-3)
],[
  // for 13 orphan rule
  w=>w.some((n,i)=>i%8==1^n>0),
  w=>w.some((n,i)=>0<i&i<8^n>0)
]].some(([i,I=i])=>i(n`m`)+i(n`p`)+i(n`s`)+I(n`z`)<1,
  // Parse `112233456666m` -> `[0, 2, 2, 2, 1, 1, 4, 0, 0, 0, 0, 0]`
  n=t=>[...a.matchAll(`\\d(?=\\d*${t})`)].map(i=>s[i]++,s=Array(12).fill(0))&&s
);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.