13
\$\begingroup\$

A reflexicon is a self-descriptive word list that describes its own letter counts. Take for example the one found by Ed Miller in 1985 in English:

Sixteen e’s, six f’s, one g, three h’s, nine i’s, nine n’s, five o’s, five r’s, sixteen s’s, five t’s, three u’s, four v’s, one w, four x’s

This reflexicon contains exactly what it says it does as per the definition. These are pretty computationally intensive but your job is to find all the possible reflexicons using roman numerals; there are way fewer letters involved (I V X L C D M) which is why the search space is reduced. Notice the English reflexicon containing "one g" - we can call it "dummy text" and it is allowed. Our reduced alphabet only contains letters used in numerals. A reflexicon using roman numerals would be of the form:

XII I, IV V, II X

The counts (12 I's, 4 V's, 2 X's) are not correct - this just illustrates the format (notice no plural 's). A letter is completely omitted if its count is 0 (there is no L in this case).

Here is a list of roman numerals [1..40] for convenience (doubtful you need any more than this):

I II III IV V VI VII VIII IX X
XI XII XIII XIV XV XVI XVII XVIII XIX XX
XXI XXII XXIII XXIV XXV XXVI XXVII XXVIII XXIX XXX
XXXI XXXII XXXIII XXXIV XXXV XXXVI XXXVII XXXVIII XXXIX XL

These are all valid reflexicons (but these are not all!):

IV I, II V

V I, I L, II V, I X

V I, II V, I X, I L

Standard code-golf rules apply - find all reflexicons using roman numerals! One per line

\$\endgroup\$
5
  • 2
    \$\begingroup\$ I think it will be helpful if you include a few examples of valid reflexicons in the post. Here are some that should be valid to my understanding. \$\endgroup\$
    – ovs
    Dec 19, 2021 at 11:14
  • \$\begingroup\$ How strict is the output format? Is printing nested lists like [["IV", "I"], ["II", "V"]] fine? \$\endgroup\$
    – ovs
    Dec 19, 2021 at 11:32
  • 1
    \$\begingroup\$ @ovs The output format is strict, as per the examples. IV I, II V in that case \$\endgroup\$
    – adrianton3
    Dec 19, 2021 at 11:39
  • 11
    \$\begingroup\$ For future challenges, please consider relaxing your I/O format. There's a reason why cumbersome I/O formats is the most upvoted thing to avoid. \$\endgroup\$
    – Arnauld
    Dec 19, 2021 at 12:34
  • \$\begingroup\$ @Arnauld I have to think about it in the future; I honestly can't tell right now what's more fair; I know formatting is the least interesting bit and some langs make it easier/harder but then it should be considered when the language is chosen; this is probably a discussion for another time/place \$\endgroup\$
    – adrianton3
    Dec 19, 2021 at 21:34

6 Answers 6

8
\$\begingroup\$

Charcoal, 84 bytes

≔⪪”{⊞‴ΣAº⧴θπ⪪λpAz” θΦE×¹⁶φ⪫Φ⁺E⮌↨﹪κφχ∧λ⁺⁺§θλ §IVXμE⮌↨÷κφ²×λ⁺I §LCDMμλ, ∧κ⁼﹪κφI⭆XVI№ιλ

Try it online! Link is to verbose version of code. Explanation:

≔⪪”{⊞‴ΣAº⧴θπ⪪λpAz” θ

Split the compressed string I II III IV V VI VII VIII IX on spaces. Since there are only seven different Roman numerals, an description string can only have 22 of any one letter. However, this means that the letters L, C, D and M can only appear once, limiting the number to just 14 Is in the description string. I'm not convinced that you can actually get above 9 Is, and using base 10 makes the following loop somewhat golfier.

ΦE×¹⁶φ⪫Φ⁺E⮌↨﹪κφχ∧λ⁺⁺§θλ §IVXμE⮌↨÷κφ²×λ⁺I §LCDMμλ, ∧κ⁼﹪κφI⭆XVI№ιλ

Get the base 10 digits of the numbers up to 1000, then use base 2 for the higher order bits, generate the description string represented by the number, count the number of times each Roman numeral appears, treat the digits as base 10, and output those description strings where this equals the original number. Note that I don't have to count the number of occurrences of L, D, C and M since they will always appear the correct number of times and only exist to inflate the count of Is.

\$\endgroup\$
6
  • \$\begingroup\$ @ovs correct; I will add a clarification \$\endgroup\$
    – adrianton3
    Dec 19, 2021 at 11:14
  • \$\begingroup\$ @ovs Better now? \$\endgroup\$
    – Neil
    Dec 19, 2021 at 11:36
  • \$\begingroup\$ @Neil Yes that is as many as I found \$\endgroup\$
    – ovs
    Dec 19, 2021 at 11:39
  • 1
    \$\begingroup\$ Note that there are also at most 4 V and 4 X, which means at most 2 X, which means at most 13 I and 3 V, which means at most 3 total X and V, which means at most 10 I. Also, X and IX don't have enough Is to reach those numbers. \$\endgroup\$
    – Nitrodon
    Dec 20, 2021 at 18:07
  • 1
    \$\begingroup\$ Okay, so IX is actually possible (I keep forgetting to count the letter itself and not just the numbers.) The rest should still hold. \$\endgroup\$
    – Nitrodon
    Dec 20, 2021 at 19:16
7
\$\begingroup\$

05AB1E, 47 46 44 bytes

-2 bytes thanks to Kevin Cruijssen!

Quite inefficient version that only finds the first reflexicon in 60 seconds.

₂ENÝ7ãDONQÏεŽ6ˆ.XRøʒ¬Ā}©.XDS{®ø`×S{Qiðý„, ý,

Try it online!

The builtin .X (Convert from integer to roman numeral string) does help quite a bit.

Commented:

₂E                 # for N in 1 .. 26:
  NÝ               #   range from 0 to N
    7ã             #   7th cartesian power - all 7-tuples with values in [0..N]
      DONQÏ        #   keep those that sum to N
  ε                #   map over the tuples                                       example: [4,2,0,0,0,0,0]
   Ž6ˆ             #     compressed integer 1666                                  [4,2,0,0,0,0,0], 1666
      .XR          #     convert to Roman numeral and reverse                     [4,2,0,0,0,0,0], "IVXLCDM"
         ø         #     zip this string with the current tuple                   [[4,"I"],[2,"V"],[0,"X"],[0,"L"],[0,"C"],[0,"D"],[0,"M"]]
          ʒ¬Ā}     #     keep only the pairs with a number larger than 0          [[4,"I"],[2,"V"]]
   ©               #     store the list in the register                           [[4,"I"],[2,"V"]]
    .X             #     convert all numbers in the list to Roman numerals        [["IV","I"],["II","V"]]
      f            #     make a copy of the resulting list ...                    [["IV","I"],["II","V"]], [["IV","I"],["II","V"]]
       S{          #     ... and flatten and sort it                              [["IV","I"],["II","V"]], ["I","I","I","I","V","V"]
         ®         #     get the list with the integers still in it               [["IV","I"],["II","V"]], ["I","I","I","I","V","V"], [[4,"I"],[2,"V"]]
          ø`×      #     and repeat Roman digit the corresponding number of times [["IV","I"],["II","V"]], ["I","I","I","I","V","V"], ["IIII","VV"]
              S{   #     flatten and sort this                                    [["IV","I"],["II","V"]], ["I","I","I","I","V","V"], ["I","I","I","I","V","V"]
                Q  #     are the two sorted lists of characters equal?            [["IV","I"],["II","V"]], 1
   i               #     if that is the case:
     ðý            #       join inner pairs with spaces                           ["IV I","II V"]
       „, ý        #       join by ", "                                           "IV I, II V"
           ,       #       and print

With some optimization we can find all of them reasonably fast:

16EN¸2Å2«4Å1«Ý.«â€˜DONQÏεŽ6ˆ.XRøʒ¬Ā}D.X©JJ{sε`×}J{Qi®ðý„, ý,

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ D.X©S{sε`×}S{Qi® to ©.XDS{®ø`×S{Qi for -2 \$\endgroup\$ Dec 20, 2021 at 15:02
2
\$\begingroup\$

JavaScript (ES6), 162 bytes

The strict output format prompted me to try a approach. This is based on the output of Neil's answer.

This is obviously very fast, and I think it's rather competitive (size-wise) compared to some code that would actually compute the strings.

_=>`IV I, II V${"XLXCLCXDLDCDXMLMCMDM".replace(/../g,a=>[i=`
V`,0,0,0].map(n=>i+" I, II V0"+a[i+='I',0]+0+a[1]).join``)}
IX I0V, II X0L0C0D0M`.split`0`.join`, I `

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Python3, 785 bytes:

import itertools as i
d={'I':1,'II':2,'III':3,'IV':4,'V':5,'VI':6,'VII':7,'VIII':8,'IX':9,'X':10,'XI':11,'XII':12,'XIII':13,'XIV':14,'XV':15,'XVI':16,'XVII':17,'XVIII':18,'XIX':19,'XX':20,'XXI':21,'XXII':22,'XXIII':23,'XXIV':24,'XXV':25,'XXVI':26,'XXVII':27,'XXVIII':28,'XXIX':29,'XXX':30,'XXXI':31,'XXXII':32,'XXXIII':33,'XXXIV':34,'XXXV':35,'XXXVI':36,'XXXVII':37,'XXXVIII':38,'XXXIX':39,'XL':40}
q=lambda p,s:all(d[a]==s.count(b)for a,b in p)and all(any(m==j for _,m in p)for b,_ in p for j in b)
def g(s):
 k=[1 if not(m:=max(h.count(i)for h in d))else sum([m]*len(s))for i in s]
 yield from i.product(*[[j for j in d if d[j]<=a]for a in k])
f=lambda s:{n for b in range(1,len(s)+1)for m in i.combinations(s,b)for j in g(m)if q(u:=[*zip(j,m)],(n:=','.join(a+' '+b for a, b in u)))}

Try it online!

Code is able to crunch the reflexicons in about 0.4 seconds. The crux of the logic is, for every character in the "base" Roman numeral input (i.e IV, IVX, VXMC, etc) is first to find the maximum number of times that character can occur (e.g I occurs a maximum of 3 times, while M does not occur), take the maximum (if the letter does not occur, set maximum to 1), and then multiply the maximum by the length of the base input, thus producing an upper bound for the range of each Roman numeral, drastically reducing the total number of Cartesian Products that have to be produced.

I am sure this solution can be golfed further - the Roman numeral lookup table takes up an incredible amount of space.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You don't need any roman numerals over 9. \$\endgroup\$
    – att
    Dec 20, 2021 at 21:05
1
\$\begingroup\$

Wolfram Language (Mathematica), 136 135 bytes

Pick[StringRiffle[s=Pick[{RomanNumeral@#,d=Characters@"IVXLCDM"},Sign@#,1],","," "],StringCount[""<>s,#]&/@d,#]&/@0~Range~9~Tuples~7

Searches \$10^7\$ possibilities, so quite slow. Does not finish in a reasonable time.
Check with better upper bounds on character occurences: Try it online!

Includes the empty string containing zero symbols.

Any single roman numeral contains at most one (each) VLD, and at most three (each) IXCM. Thus there are at most 8 (each) VLD (7*1+1), and at most 22 (each) IXCM (7*3+1). But the maximum possible number of any symbol is only 22, so LCDM can only occur at most once each, as "dummy text".

From here we can just run the program and see what the maximum encountered values of IVX are. Their maximum counts are 9, 2, and 2, respectively.

\$\endgroup\$
1
\$\begingroup\$

Scala, 149 bytes

"IV I,II V\nIX I,I V,II X,I L,I C,I D,I M"+{for{i<-0 to 3;j<-"DMCMCDLMLDLCXMXDXCXL"grouped 2}yield s"\nV${"I"*i} I,II V"+j.flatMap(",I "+_)}.mkString

By the findings of others here, we know already that there are exactly 42 (sic!) valid reflexicons. So one solution strategy is to generate these 42 lines by as small as possible code. While doing so, I realized that my solution became very similar to Arnauld's answer. However, his trick of further saving some bytes by temporarily substituting the multiple occurences of ,I via 0 does not seem to save additional bytes in the Scala approach taken here.

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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