¿xu ti te gismytermorna? (Is it a valid gismu?)
Ruby, 302 252 bytes
c='[cjsztdpbfvkgxmnlr]'
v=c+'[aeiou]'
z=!1
n=/#{c+v+v}/=~(s=gets.chop)*2
(n==0||n==2)&&289.times{|k|q=[i=k%17,j=k/17].max
z||=(x=s[n,2])==c[j+1]+c[i+1]&&['UeUeJOJOJOJOETJ
:'[i].ord-69>>j&1-j/14>0,i!=j&&q>3&&(k%2<1||q>12)&&!'mzxcxkx'.index(x)][n/2]}
p z
A few more bytes could be saved as follows:
Initialize z
to false using z=!c='[cjsztdpbfvkgxmnlr]'
. This works but gives the warning warning: found = in conditional, should be ==
.
Change from a program to a function (I left it as a program because according to the question, shortest "program" in bytes wins.)
Summary of changes from first post
Major overhaul of regex/matching part.
Constant 72 changed to 69 so that the lowest ASCII code in the magic string is 10 instead of 13. This enables a literal newline to be used in the golfed version instead of an escape sequence.
Magic string 'mzxcxkx'
replaces arithmetic rules for the 5 prohibited characters in the CVCCV type table.
ungolfed version
added whitespace and changed newline in magic string to a \n
c='[cjsztdpbfvkgxmnlr]' #c=consonants
v=c+'[aeiou]' #v=consonant+vowel
z=!1 #Set z to false (everything is truthy in Ruby except nil and false.)
n=/#{c+v+v}/=~(s=gets.chop)*2 #Get input and duplicate it. do regex match, n becomes the index of the double consonant.
(n==0||n==2)&& #If n==0 (ccvcv) or n==2 (cvccv)
289.times{|k| #iterate 17*17 times
q=[i=k%17,j=k/17].max #generate row and column, find their maximum.
z||= #OR z with the following expression:
(x=s[n,2])==c[j+1]+c[i+1]&& #double consonant == the pair corresponding to j,i AND either
["UeUeJOJOJOJOETJ\n:"[i].ord-69>>j&1-j/14>0, #this expression or
i!=j&&q>3&&(k%2<1||q>12)&&!'mzxcxkx'.index(x)][n/2]#this expresson, depending on the value of n/2
}
p z #print output
Explanation of matching
The two characters in the input string s[n,2]
are compared with the character pair of the iterating loop. If they match and the consonant-vowel regex pattern is correct, the row and column values i,j
are checked for validity. Careful ordering of the consonants helps here.
For CVCCV:
i!=j It is forbidden for both consonants to be the same
(k%2<1||q>12) It is forbidden for one consonant to be voiced and the other unvoiced. The consonants “l”, “m”, “n”, and “r” are exempt from this restriction. As a result, “bf” is forbidden, and so is “sd”, but both “fl” and “vl”, and both “ls” and “lz”, are permitted.
q>3 It is forbidden for both consonants to be drawn from the set “c”, “j”, “s”, “z”.
!'mzxcxkx'.index(x) The specific pairs “cx”, “kx”, “xc”, “xk”, and “mz” are forbidden.
For CCVCV
A bitmap for each column of the table below is encoded into the magic string, from which 69 is subtracted. For all columns except the last two, only 6 bits are required. For the last two, the higher order bits need to be 1, so a negative number is generated (characters \n
and :
) in order to have leading 1's instead of leading zeroes. We don't want to include the last three rows of the table though, so instead of rightshift and ANDing by 1, we rightshift and AND by 1-j/14
which normally evaluates to 1, but evaluates to 0 for the last 3 rows.
The following program (with the same expressions as the submission) was used to generate the tables below (uncomment whichever if
line is required for the table you want.
c='[cjsztdpbfvkgxmnlr]'
z=0
289.times{|k|
q=[i=k%17,j=k/17].max
r=c[j+1]+c[i+1]
#if i!=j && q>3 && (k%2<1||q>12) && !'mzxcxkx'.index(r)
#if "UeUeJOJOJOJOETJ\n:"[i].ord-69>>j&1-j/14>0
print r,' '
z+=1
else
print ' '
end
i==16&&puts
}
puts z
ct cp cf ck cm cn cl cr
jd jb jv jg jm jn jl jr
st sp sf sk sx sm sn sl sr
zd zb zv zg zm zn zl zr
tc ts tp tf tk tx tm tn tl tr
dj dz db dv dg dm dn dl dr
pc ps pt pf pk px pm pn pl pr
bj bz bd bv bg bm bn bl br
fc fs ft fp fk fx fm fn fl fr
vj vz vd vb vg vm vn vl vr
kc ks kt kp kf km kn kl kr
gj gz gd gb gv gm gn gl gr
xs xt xp xf xm xn xl xr
mc mj ms mt md mp mb mf mv mk mg mx mn ml mr
nc nj ns nz nt nd np nb nf nv nk ng nx nm nl nr
lc lj ls lz lt ld lp lb lf lv lk lg lx lm ln lr
rc rj rs rz rt rd rp rb rf rv rk rg rx rm rn rl
179
ct cp cf ck cm cn cl cr
jd jb jv jg jm
st sp sf sk sm sn sl sr
zd zb zv zg zm
tc ts tr
dj dz dr
pl pr
bl br
fl fr
vl vr
kl kr
gl gr
xl xr
ml mr
48
JavaScript (ES6), 366 352 bytes
g=>((q=3,w=2,r=0,f="mzcscjzjxcxkx",c="bdgvjzptkfcsxlmnr",d=[...c],v="aeiou")[m="match"](g[1])?d.map((a,i)=>d.map((b,j)=>a==b|(i<6&j>5&j<13|j<6&i>5&i<13)||f[m](a+b)||(p+=","+a+b)),p="",q=0,r=w--)&&p:"jbl,zbr,tstcl,cmr,cn,cr,jdr,cfl,sfr,jgl,zgr,zdjml,ckl,skr,cpl,spr,sl,sm,sn,sr,ctr,jvl,zvr,xl,xr,dzm")[m](g[r]+g[r+1])&&c[m](g[q])&&v[m](g[w])&&v[m](g[4])
Explanation
Returns an array containing the last letter (truthy) if it is a valid gismu or null
if it is not.
A lot of the size comes from the hard-coded CCVCV
pairs (even after condensing them). It might be possible to find a pattern to generate them but I've spent way too much time on this already! xD
g=>
(
// Save the positions to check for the consonant, vowel and pair respectively
(q=3,w=2,r=0, // default = CCVCV format
f="mzcscjzjxcxkx", // f = all forbidden pairs for CVCCV pairs
c="bdgvjzptkfcsxlmnr", // c = consonants
d=[...c], // d = array of consonants
v="aeiou") // v = vowels
[m="match"](g[1])? // if the second character is a vowel
// Generate CC pairs of CVCCV
d.map((a,i)=> // iterate over every possible pair of consonants
d.map((b,j)=>
a==b| // rule 1: consonants cannot be the same
(i<6&j>5&j<13|j<6&i>5&i<13)|| // rule 2: pair cannot be voiced and unvoiced
f[m](a+b)|| // rule 3 & 4: certain pairs are forbidden
(p+=","+a+b) // if it follows all the rules add the pair
),
p="", // p = comma-delimited valid CVCCV pairs
q=0,r=w-- // update the match positions to CVCCV format
)&&p
:
// CC pairs of CCVCV (condensed so that valid pairs like "jb", "bl" and
// "zb" can be matched in this string but invalid pairs like "lz" cannot)
"jbl,zbr,tstcl,cmr,cn,cr,jdr,cfl,sfr,jgl,zgr,zdjml,ckl,skr,cpl,spr,sl,sm,sn,sr,ctr,jvl,zvr,xl,xr,dzm"
// Match the required format
)[m](g[r]+g[r+1])&&c[m](g[q])&&v[m](g[w])&&v[m](g[4])
Test
var solution = g=>((q=3,w=2,r=0,f="mzcscjzjxcxkx",c="bdgvjzptkfcsxlmnr",d=[...c],v="aeiou")[m="match"](g[1])?d.map((a,i)=>d.map((b,j)=>a==b|(i<6&j>5&j<13|j<6&i>5&i<13)||f[m](a+b)||(p+=","+a+b)),p="",q=0,r=w--)&&p:"jbl,zbr,tstcl,cmr,cn,cr,jdr,cfl,sfr,jgl,zgr,zdjml,ckl,skr,cpl,spr,sl,sm,sn,sr,ctr,jvl,zvr,xl,xr,dzm")[m](g[r]+g[r+1])&&c[m](g[q])&&v[m](g[w])&&v[m](g[4])
<input type="text" id="input" value="gismu" />
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>