Chaining autograms

8

3

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 previous 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>

CJ Dennis

Posted 2015-06-04T12:07:45.357

Reputation: 4 104

Surely there are a finite number of autograms? – feersum – 2015-06-04T12:11:46.693

1@feersum When you chain them together there are an infinite number. – CJ Dennis – 2015-06-04T12:20:25.987

What's the largest number name we need to support theoretically? – Martin Ender – 2015-06-04T12:33:58.857

I doubt you'll get to one thousand after only ten times but I'm pretty sure you'll get over one hundred. Take a look at the example autogram. It uses 28 "E"s, 25 "S"s and 23 "T"s for n=1. – CJ Dennis – 2015-06-04T12:38:36.763

1You 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. – Reto Koradi – 2015-06-04T14:40:28.070

so... no hyphens for, e.g., twenty-eight? – Not that Charles – 2015-06-04T16:34:26.747

@NotthatCharles You can use hyphens if you want. Both twenty eight and twenty-eight will be considered valid. – CJ Dennis – 2015-06-05T01:02:14.460

2There 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 – Arnaud – 2015-07-24T11:17:39.160

No answers