10
\$\begingroup\$

Write a program that takes one integer input n and one format letter and outputs n autograms in the format This sentence contains ? "A"s, ? "B"s ... and ? "Z"s.

  • Each question mark ? represents the number of times the the following letter appears in the text
  • All numbers will be written as text. To make it equally unfair for Americans and Brits your program has to be able to print either system! Pass a format letter in to choose which system, A for American and B for British. This will not matter for the first few sentences as they will have fewer than one hundred of each letter but will definitely be needed by the time you get to ten sentences
    • American: one hundred twenty three, etc.
    • British: one hundred and twenty three, etc.
  • The integer (let's call it n) is used to vary the number of sentences produced. When n is greater than 1 each subsequent sentence will start with two newlines and then the following text: The preceding text plus this sentence contain ... where the ellipsis ... represents the count of each letter that appears
  • You do not have to include a letter if it doesn't otherwise appear, although if you do choose to, it might simplify the challenge. I don't know, though, it might make it harder so it's your call! If you include all twenty six letters your answer will also be a pangram!
  • You can't say zero "Y"s because you have to use a Y to say it!
  • You can only say one "Y" if Y doesn't appear anywhere else in the text
  • You can't repeat a letter and its count within each sentence, i.e. three "N"s, three "N"s is not allowed
  • Your output must use good English! Any appearance of ... "X"s, one "Y"s..., for example, will invalidate your answer!
  • In each sentence you must enumerate the letters in alphabetical order
  • Only letters A-Z will be counted, not symbols, punctuation or spaces
  • The letters will be counted case-insensitively, i.e. A will be equivalent to a

Since the level n output also contains the output for each lower level to n-1 you only need to show your source code and the output for level 10. There may be multiple solutions so your answer might be different from someone else's answer!

An example (n=1) is:

This sentence employs two a’s, two c’s, two d’s, twenty-eight e’s, five f’s, three g’s, eight h’s, eleven i’s, three l’s, two m’s, thirteen n’s, nine o’s, two p’s, five r’s, twenty-five s’s, twenty-three t’s, six v’s, ten w’s, two x’s, five y’s, and one z.

Note, however, that my requirements are slightly different! You must use contains, not employs and surround each letter (in capitals) with double quotes ". It's your choice whether you use hyphens - or not between the words of the numbers.

Your final output will look something like this. Note that the first sentence uses contains but the subsequent sentences use contain:

This sentence contains ten "A"s, ...

The preceding text plus this sentence contain twenty "A"s, ...

The preceding text plus this sentence contain thirty "A"s, ...

...

The preceding text plus this sentence contain one hundred "A"s, ...

You can use the following snippet to check your output.

// Apologies for the hugeness of this snippet. It's my first!
word = {
  1: 'one',
  2: 'two',
  3: 'three',
  4: 'four',
  5: 'five',
  6: 'six',
  7: 'seven',
  8: 'eight',
  9: 'nine',
  10: 'ten',
  11: 'eleven',
  12: 'twelve',
  13: 'thirteen',
  14: 'fourteen',
  15: 'fifteen',
  16: 'sixteen',
  17: 'seventeen',
  18: 'eighteen',
  19: 'nineteen',
  20: 'twenty',
  30: 'thirty',
  40: 'forty',
  50: 'fifty',
  60: 'sixty',
  70: 'seventy',
  80: 'eighty',
  90: 'ninety',
  100: 'hundred',
  1000: 'thousand',
}

var format;

function count_letters() {
  var check_text = [];
  var text = document.getElementById("golf").value;
  text = text.replace(/-/g, " ");
  text = text.replace(/\r\n?/g, "\n");
  format = text.match(/\w\w and /)? 'B': 'A';
  var lines = text.split(/\n\n/);
  var let_count = {};
  for (n = 0; n < lines.length; ++n) {
    var keys = [];
    var sentence = '';
    var letters = lines[n].toUpperCase().match(/[A-Z]/g);
    for (var i = 0; i < letters.length; ++i) {
      if (!(letters[i] in let_count)) {
        let_count[letters[i]] = 0;
      }
      let_count[letters[i]]++;
    }
    for (i in let_count) {
      if (let_count.hasOwnProperty(i)) {
        keys.push(i);
      }
    }
    keys.sort();
    for (i = 0; i < keys.length - 1; ++i) {
      if (sentence) {
        sentence += ", ";
      }
      var num_text = number(let_count[keys[i]], format);
      sentence += num_text + ' "' + keys[i] + '"';
      if (let_count[keys[i]] > 1) {
        sentence += "s";
      }
    }
    num_text = number(let_count[keys[i]], format);
    sentence += " and " + num_text + ' "' + keys[i] + '"';
    if (let_count[keys[i]] > 1) {
      sentence += "s";
    }
    sentence = check_text.length == 0? "This sentence contains " + sentence + ".": "The preceding text plus this sentence contain " + sentence + ".";
    check_text.push(sentence);
  }
  document.getElementById("output").value = check_text.join("\n\n");

  for (n = 0; n < lines.length; ++n) {
    if (check_text[n] != lines[n]) {
      break;
    }
  }
  document.getElementById("correct").innerText = n;
}

function number(num, format) {
  num = (num + "").split("").reverse().join("");
  digit = num.match(/\d/g);
  text = "";

  // Thousands
  if (digit[3]) {
    text += word[digit[3]] + " " + word[1000];
    // Hundreds
    if (digit[2] > 0) {
      text += " ";
    }
    // Tens and units
    else if ((digit[1] + digit[0]) * 1 > 0) {
      text += " and ";
    }
  }

  // Hundreds
  if (digit[2] > 0) {
    text += word[digit[2]] + " " + word[100];
    // Tens and units
    if ((digit[1] + digit[0]) * 1 > 0) {
      text += " and ";
    }
  }
  if (typeof(digit[1]) == "undefined") {
    digit[1] = 0;
  }
  if (digit[1] < 2) {
    if ((digit[1] + digit[0]) * 1) {
      text += word[(digit[1] + digit[0]) * 1];
    }
  }
  else {
    text += word[digit[1] * 10];
    if (digit[0] > 0) {
      text += " " + word[digit[0]];
    }
  }

  if (format != 'B') {
    text = text.replace(/ and /g, format == 'A'? " ": " ! ");
  }

  return text;
}
<textarea id="golf" cols="80" rows="25">
This sentence employs two "A"s, two "C"s, two "D"s, twenty-eight "E"s, five "F"s, three "G"s, eight "H"s, eleven "I"s, three "L"s, two "M"s, thirteen "N"s, nine "O"s, two "P"s, five "R"s, twenty-five "S"s, twenty-three "T"s, six "V"s, ten "W"s, two "X"s, five "Y"s, and one z.</textarea><br/>
<input type="button" value="Count the letters!" onclick="count_letters()"/><br/>
<textarea id="output" cols="80" rows="10">
</textarea><br/>
Number of correct sentences: <span id="correct"></span>

\$\endgroup\$
8
  • \$\begingroup\$ Surely there are a finite number of autograms? \$\endgroup\$
    – feersum
    Commented Jun 4, 2015 at 12:11
  • 2
    \$\begingroup\$ @feersum When you chain them together there are an infinite number. \$\endgroup\$
    – CJ Dennis
    Commented Jun 4, 2015 at 12:20
  • \$\begingroup\$ What's the largest number name we need to support theoretically? \$\endgroup\$ Commented Jun 4, 2015 at 12:33
  • 1
    \$\begingroup\$ You mention in the first sentence that one input is a "format letter". But I can't find anything describing how that input is used, and I also don't see a value specified for the example. \$\endgroup\$ Commented Jun 4, 2015 at 14:40
  • 3
    \$\begingroup\$ There seems to be a problem with your code snippet. For the sentences >= 2, It contains the string The previous text while the code golf specifies The preceding text \$\endgroup\$
    – Arnaud
    Commented Jul 24, 2015 at 11:17

1 Answer 1

2
\$\begingroup\$

Haskell, 2161 bytes

-- https://codegolf.stackexchange.com/questions/51264/chaining-autograms
-- https://www.leesallows.com/files/Reflexicons%20NEW(4c).pdf

import Data.Char
import Data.List
import Data.Array

import System.IO.Unsafe
import System.Random

pick []=[]
pick pool=[pool!!(unsafePerformIO.randomRIO)(0,length pool-1)]

instance (Num a, Ix i) => Num(Array i a) where
 a+b=accum(+)a(assocs b)
 a-b=accum(-)a(assocs b)
 (*)=undefined;fromInteger=undefined;signum=undefined;abs=undefined

azarra=accumArray(+)0('A','Z')::[(Char,Int)]->Array Char Int
squeeze=azarra.map(\c->(toUpper c,1)).filter isLetter
 
autogram n b = let
 band
  |b=='B'=" and "
  |b=='A'=" "
 name 0="zero";
 name 1="one"
 name 2="two"
 name 3="three"
 name 4="four"
 name 5="five"
 name 6="six"
 name 7="seven"
 name 8="eight"
 name 9="nine"
 name 10="ten"
 name 11="eleven"
 name 12="twelve"
 name 13="thirteen"
 name 14="fourteen"
 name 15="fifteen"
 name 16="sixteen"
 name 17="seventeen"
 name 18="eighteen"
 name 19="nineteen"
 name 20="twenty"
 name 30="thirty"
 name 40="forty"
 name 50="fifty"
 name 60="sixty"
 name 70="seventy"
 name 80="eighty"
 name 90="ninety"
 name n|n<100=name(10*div n 10)++'-':name(mod n 10)
 name n|n<1000&&mod n 100==0=name(div n 100)++" hundred"
 name n|n<1000=name(100*div n 100)++band++name(mod n 100)
 name n|mod n 1000==0=name(div n 1000)++" thousand"
 name n=name(1000*div n 1000)++" "++name(mod n 1000)

 endr=9999
 nam2 0=""
 nam2 i='s':name(1+i)
 wtwo(i,v)=if v>0 then tail$nam2 v++" \""++[i]++"\"s" else ""
 repr=listArray(0,endr)$map(squeeze.nam2)[0..endr]
 self=foldl1(+).map(repr!).filter(>0).elems

 solv pret=let 
  fixall guess=pret+self guess
  deficit guess=fixall guess-guess
  fixone guess=accum(+)guess$pick.filter((/=0).snd).assocs.deficit$guess
  terminate(a:b:c)|a==b=a|True=terminate(b:c)
  in terminate$iterate(fixone.fixall)pret

 solve prepent=
  (prepent++).(++".\n").
  intercalate", ".(\s->init s++["and "++last s]).map wtwo.
  filter((>0).snd).assocs.solv.squeeze$prepent++"and"

 in solve$if n==1 then "This sentence contains " 
  else autogram(n-1)b++"The preceding text plus this sentence contain "

main=putStrLn $ autogram 2 'B'

Try it online!

This sentence contains three "A"s, three "C"s, two "D"s, twenty-seven "E"s, four "F"s, two "G"s, ten "H"s, eight "I"s, thirteen "N"s, six "O"s, ten "R"s, twenty-five "S"s, twenty-three "T"s, three "U"s, three "V"s, six "W"s, three "X"s, and four "Y"s.
The preceding text plus this sentence contain six "A"s, seven "C"s, five "D"s, sixty-four "E"s, thirteen "F"s, six "G"s, eighteen "H"s, twenty-six "I"s, four "L"s, thirty-three "N"s, eleven "O"s, three "P"s, nineteen "R"s, fifty-five "S"s, forty-five "T"s, seven "U"s, eleven "V"s, eight "W"s, nine "X"s, and ten "Y"s.
The preceding text plus this sentence contain ten "A"s, eleven "C"s, eleven "D"s, one hundred and fourteen "E"s, nineteen "F"s, ten "G"s, twenty-six "H"s, forty-two "I"s, nine "L"s, sixty-seven "N"s, eighteen "O"s, six "P"s, twenty-five "R"s, eighty-six "S"s, seventy-one "T"s, eleven "U"s, nineteen "V"s, thirteen "W"s, fifteen "X"s, and seventeen "Y"s.
The preceding text plus this sentence contain seventeen "A"s, fifteen "C"s, twenty-six "D"s, one hundred and sixty-three "E"s, twenty-eight "F"s, fifteen "G"s, thirty-nine "H"s, sixty-two "I"s, twelve "L"s, one hundred and eight "N"s, twenty-seven "O"s, nine "P"s, thirty-five "R"s, one hundred and fifteen "S"s, one hundred and nine "T"s, eighteen "U"s, twenty-four "V"s, twenty-two "W"s, twenty "X"s, and twenty-nine "Y"s.
The preceding text plus this sentence contain twenty-four "A"s, nineteen "C"s, forty-one "D"s, two hundred and eight "E"s, forty-five "F"s, nineteen "G"s, fifty-two "H"s, seventy-eight "I"s, fifteen "L"s, one hundred and forty-two "N"s, forty-seven "O"s, twelve "P"s, fifty-four "R"s, one hundred and forty-three "S"s, one hundred and forty-seven "T"s, twenty-six "U"s, thirty-one "V"s, thirty-one "W"s, twenty-three "X"s, and forty-five "Y"s.
The preceding text plus this sentence contain thirty-two "A"s, twenty-three "C"s, fifty-nine "D"s, two hundred and fifty-six "E"s, fifty-nine "F"s, twenty-seven "G"s, seventy-two "H"s, one hundred and six "I"s, seventeen "L"s, one hundred and eighty-one "N"s, fifty-eight "O"s, fifteen "P"s, sixty-eight "R"s, one hundred and seventy-five "S"s, one hundred and eighty-nine "T"s, thirty-four "U"s, thirty-eight "V"s, thirty-eight "W"s, twenty-nine "X"s, and sixty-three "Y"s.
The preceding text plus this sentence contain forty "A"s, twenty-seven "C"s, seventy-seven "D"s, three hundred and eight "E"s, sixty-seven "F"s, thirty-five "G"s, ninety "H"s, one hundred and twenty-five "I"s, nineteen "L"s, two hundred and eighteen "N"s, seventy "O"s, eighteen "P"s, eighty-four "R"s, two hundred and eight "S"s, two hundred and twenty-eight "T"s, forty-two "U"s, forty-seven "V"s, forty-six "W"s, thirty-three "X"s, and seventy-nine "Y"s.
The preceding text plus this sentence contain fifty-one "A"s, thirty-one "C"s, one hundred and four "D"s, three hundred and forty-nine "E"s, eighty-five "F"s, forty "G"s, one hundred and eight "H"s, one hundred and forty-nine "I"s, twenty-one "L"s, two hundred and sixty-one "N"s, ninety-two "O"s, twenty-one "P"s, one hundred and four "R"s, two hundred and thirty-six "S"s, two hundred and sixty-five "T"s, fifty-five "U"s, fifty-two "V"s, fifty-four "W"s, thirty-eight "X"s, and ninety-seven "Y"s.
The preceding text plus this sentence contain sixty-four "A"s, thirty-five "C"s, one hundred and thirty-seven "D"s, four hundred and six "E"s, ninety-four "F"s, forty-three "G"s, one hundred and twenty-nine "H"s, one hundred and sixty-seven "I"s, twenty-five "L"s, three hundred and eleven "N"s, one hundred and eleven "O"s, twenty-four "P"s, one hundred and twenty-eight "R"s, two hundred and seventy "S"s, three hundred and two "T"s, seventy-one "U"s, sixty-one "V"s, sixty-two "W"s, forty-six "X"s, and one hundred and thirteen "Y"s.
The preceding text plus this sentence contain seventy-eight "A"s, thirty-nine "C"s, one hundred and seventy-three "D"s, four hundred and seventy "E"s, one hundred and seven "F"s, fifty-one "G"s, one hundred and fifty-five "H"s, one hundred and eighty-eight "I"s, twenty-seven "L"s, three hundred and sixty-two "N"s, one hundred and twenty-eight "O"s, twenty-seven "P"s, one hundred and fifty-one "R"s, three hundred and four "S"s, three hundred and forty-three "T"s, eighty-six "U"s, seventy "V"s, sixty-eight "W"s, fifty-one "X"s, and one hundred and thirty-two "Y"s.
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Very good! No, really truly excellent! But it doesn't exactly meet the requirements (I realise now I could have been a bit more specific). 'This sentence contains two "A"s, three "C"s, [...], three "X"s, and three "Y"s.' There should be an "and" before the final letter and its count. Can you make that modification? \$\endgroup\$
    – CJ Dennis
    Commented Jan 21, 2023 at 10:04
  • \$\begingroup\$ Yes. Inserted the and. \$\endgroup\$ Commented Jan 21, 2023 at 22:57

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