Piem validator programme

11

0

Write a program that defines a function that can check if a string variable called "anything you want or inputted by the user" is or not a piem. (piem = a story or poem in which the word lengths represent the digits of π (from Wikipedia))

Some examples:

myfunction("I am clearly wrong") # False
myfunction("How I want a drink, alcoholic of course, after the heavy lectures involving quantum mechanics") #True (Taken from Wikipedia)
myfunction("Law ' s fine") # True

You should delete any kind of punctuation or newline before processing. Pure code golf, the shortest wins

End date: evening of 1/10/2014

Various answers

  • How many digits do we need to handle? More than 10
  • As a matter of interest, how should 0's in PI be interpreted? Skipped or 10 letter words? As 10 letters words
  • "a variable called piem" – so the name of the parameter must be piem? No, it hasn't, question text corrected
  • A fun bonus might be a solution that is itself a piem If your solution is a piem you get *0.5 bonus
  • For the sake of argument, is _ always punctuation? You can decide if it is punctuation or if it isn't
  • It's unclear what is meant by "any kind of punctuation" I mean ,.'"?!;;()
  • So digits should be counted? And Law's fine would be false? Digits should be treated as letters, Law's fine = False; Law ' s fine = True

Comments

  • The APL solution should be counted in Bytes
  • If your solution works for 100+ digits of pi you get *0.8 bonus
  • Because of the great interest the end date is one day more in the future.

Caridorc

Posted 2014-09-28T09:14:05.830

Reputation: 2 254

6How many digits do we need to handle? – marinus – 2014-09-28T09:18:47.960

1So digits should be counted? And Law's fine would be false? – Martin Ender – 2014-09-28T09:21:31.550

5"a variable called piem" – so the name of the parameter must be piem? That renders all current answers incorrect. – Ingo Bürk – 2014-09-28T11:37:57.367

Also, should new lines really be removed instead of treated like spaces. Because that means that How\nI\nwant yields false but A\nB\nC yields true. – Martin Ender – 2014-09-28T13:08:24.690

2A fun bonus might be a solution that is itself a piem. – britishtea – 2014-09-28T13:36:46.417

Validating for length (i.e. [3,1,4,1,5,9,2,6,...]) is interesting and a good challenge, but validating a piem, I think, requires that the string actually be a story or a poem. i.e. something with some sense or memorability to it. It will be interesting to see how that requirement is handled. For example, this, despite having appropriate length words, is not a piem in my opinion: "Bob I door I fence parameter an yellow fence red" – Darren Stone – 2014-09-28T20:24:25.360

I didn't mean to be overly negative in my previous comment -- I actually think this is a great challenge, particularly if the number of digits of pi is unconstrained. I just think this isn't really about piems, which require some degree of sense to be memorable. e.g. also not a piem: "aaa a aaaa a aaaaa aaaaaaaaa aa aaaaaa aaaaa aaa" – Darren Stone – 2014-09-28T20:32:55.063

5As a matter of interest, how should 0's in PI be interpreted? Skipped or 10 letter words? – MickyT – 2014-09-29T01:38:51.183

1I don't see any mention of Unicode in the puzzle description... – Almo – 2014-09-29T13:42:47.433

3It's kind of a shame that you don't reply to very important questions, yet you already edited in an end date. – Ingo Bürk – 2014-09-29T14:53:25.543

@IngoBürk I now replied, look the question. – Caridorc – 2014-09-29T19:21:15.993

Answers

3

APL (39)

{N≡(≢N←≢¨('\w+'⎕S'\0')⍵)↑⍎¨'_. '~⍨99⍕○1}

It uses all the digits the APL interpreter's pi constant provides, to a limit of 99. In my case (Dyalog APL 14 32-bit) that was 16 digits. The 64-bit version likely has more digits. 16 digits is enough for the given examples to work, though.

Strings that have more than that amount of words will fail, even if all the digits it could check were true. (The same is true of other posts, as of this writing.) For example, if there were only 10 digits, the 'How I want a drink' one would fail. This can be fixed, but at the cost of 14 characters:

{(≢¨('\w+'⎕S'\0')⍵){∧/(⌊/≢¨⍺⍵)↑∨⌿⍺∘.=⍵}⍎¨'_. '~⍨99⍕○1}

That version will accept any string where the first N digits are correct.

marinus

Posted 2014-09-28T09:14:05.830

Reputation: 30 224

Your code is the shortes but it is not Unicode... I'll have to think about if you deserve the win or not, the javascript version is just a little bit longer than this... Anyway I upvoted this answer. – Caridorc – 2014-09-29T11:56:09.217

@Caridorc a) Do you mean it's not ASCII? Because I'm pretty sure it's Unicode. b) What does the character encoding have to do with anything? APL is as valid a language as any other, it just uses an unconventional set of characters. The more relevant question is whether supporting only a limited amount of digits is valid or not, but you haven't replied to any requests for clarification on the actual challenge. – Martin Ender – 2014-09-29T13:46:27.317

1@marinus The question doesn't specify whether submissions should be scored by characters or bytes, but the default is bytes (as per the tag wiki), so I think your score is closer to 60. – Martin Ender – 2014-09-29T13:48:29.580

1Given the right encoding it's 1 byte per character. APL predates Unicode by decades after all. – marinus – 2014-09-29T13:51:16.197

1@marinus Fair point! Do you know any particular (existing) encoding in which that would actually work? – Martin Ender – 2014-09-29T14:16:10.347

2@MartinBüttner: IBM codepage 907 is one, but there are loads. – marinus – 2014-09-29T17:10:45.260

7

JavaScript (169)(140)(137)(135) (63)for 17 digits of pi

In my version Law's fine and Law ' s fine return both true.

Newest Version (63) by Ingo Bürk and hsl

f=s=>!s.split(/\W+/).some((x,i)=>x.length-(Math.PI*1e16+'')[i])

New Version (135) for 17 digits of pi (Thanks to Ingo Bürk):

f=(s)=>{
s=s.split(/[!"#$%&'()*+, \-.\/:;<=>?@[\\\]^_`{|}~]+/);
p=Math.PI*1e16+'';
    r=0;
    for(a=s.length;a--;)r+=s[a].length!=p[a];
    return !r
}

Old version (169) for 32 digits of pi:

f=(s)=>{
s=s.split(/[!"#$%&'()*+, \-.\/:;<=>?@[\\\]^_`{|}~]+/);
p="31415926535897932384626433832795".split('');
    r=1;
    for(a=s.length;a--;)if(s[a].length!=p[a]){r=0};
    return r;
}

flawr

Posted 2014-09-28T09:14:05.830

Reputation: 40 560

You can save 3 bytes with: 1e15*Math.PI+"2384626433832795" – xem – 2014-09-28T11:25:17.670

Thanks=) In meantime i changed it using this idea but now only using the first 17 digits. – flawr – 2014-09-28T11:41:07.137

@IngoBürk Thank you very much, just checking what works. – flawr – 2014-09-28T11:41:57.743

Sorry, never mind. That doesn't seem to work. :/ The for loop can't be added this way. – Ingo Bürk – 2014-09-28T11:43:18.607

But what does work is initializing r=0 and then just looping over r+=s[a].length!=p[a] (you can omit the ; in the end). Then, return !r. – Ingo Bürk – 2014-09-28T11:49:02.083

I was just able to improve this, but you are right this willa gain save me 2 bytes I think. – flawr – 2014-09-28T11:51:12.243

It will probably be shorter to use s.some(…) instead of a for loop, too. – Ingo Bürk – 2014-09-28T11:53:07.193

114 bytes: f=(s)=>{p=Math.PI1e16+'';return !s.split(/[!"#$%&'()+, -./:;<=>?@[\]^_`{|}~]+/).some((x,i)=>x.length!=p[i])} – Ingo Bürk – 2014-09-28T11:55:31.020

And 103 bytes: f=(s)=>!s.split(/[!"#$%&'()+, -./:;<=>?@[\]^_`{|}~]+/).some((x,i)=>x.length!=(Math.PI1e16+'')[i]) – Ingo Bürk – 2014-09-28T11:57:29.647

(Alternatively, omit the !, change != to == and use every – same byte count) – Ingo Bürk – 2014-09-28T12:00:40.080

I just tried it myself (it is commented now) and your last version, but it does not seem to work as expected? (I was not familiar with the some function: http://jsfiddle.net/dfk8k39L/1/

– flawr – 2014-09-28T12:00:40.793

The backslashes got messed up. Take it from here: http://jsfiddle.net/dfk8k39L/2/

– Ingo Bürk – 2014-09-28T12:04:34.007

And finally 102 bytes. I don't think I can do any better now (except for the regexp): http://jsfiddle.net/dfk8k39L/3/

– Ingo Bürk – 2014-09-28T12:20:51.343

Any reason you can't use [^a-zA-Z0-9]+ for the split regex? Also, you can remove the parentheses around s in the function definition. – NinjaBearMonkey – 2014-09-28T13:23:29.767

With @hsl's improvements this now comes down to 73 bytes: http://jsfiddle.net/dfk8k39L/4/

– Ingo Bürk – 2014-09-28T13:27:45.550

And using character classes, we get 63: http://jsfiddle.net/dfk8k39L/6/

– Ingo Bürk – 2014-09-28T13:35:15.280

I just add my answer using character classes and 'some'. All these comments were too much too read. – edc65 – 2014-09-28T14:48:12.240

w00t, this is insane=) Thank you! – flawr – 2014-09-28T15:10:49.787

7

Ruby, 113 101 79 (98 * 0.8)

require"bigdecimal/math"
x=->p{!(BigMath.PI(999).to_s[2..-1]!~/^#{p.scan(/\w+/).map(&:size)*''}/)}

Explanation

  • Input is taken as the argument to a lambda. It expects a String.
  • Pi is calculated up to 999 decimals and turned into a String with the . removed.
  • Punctuation marks are removed from the poem and it is split into individual words. "Let's" is counted as two words: "Let" and "s".
  • Use Array#map to convert each word to the size of the word, concatenate them into a String.
  • Using a Regexp, check if the two created Strings begin with the same characters.

I have applied the bonus for handling 100+ digits. _ is not handled as punctuation in this solution.

britishtea

Posted 2014-09-28T09:14:05.830

Reputation: 1 189

Note that you're not treating _ as punctuation. – Martin Ender – 2014-09-28T13:24:15.407

Well spotted. For the sake of argument, is _ always punctuation? What about sentences such as My nickname on Stack Overflow is britishtea_500. – britishtea – 2014-09-28T13:30:31.740

It was just an observation. The OP isn't exactly specific about the details here. – Martin Ender – 2014-09-28T13:31:52.377

Fair enough. I'll leave the answer up for now until it's specified in the problem :) – britishtea – 2014-09-28T13:36:21.377

Using bigdecimal you have no limit on PI digits? Nice (+1) – edc65 – 2014-09-28T14:45:35.177

You can specify the number of digits (it's a method, not a constant). I chose a limit of 999, so the program would execute reasonably fast and still be able to deal with bigger poems. – britishtea – 2014-09-28T15:44:23.367

4

Mathematica, 123 bytes * 0.8 = 98.4

f=#&@@RealDigits[Pi,10,Length[d=StringLength/@StringSplit@StringReplace[#,RegularExpression@"[!-.:-?]
"->""]/. 10->0]]==d&;

Almost the longest submission so far, but:

  • It works for any number of digits of Pi.
  • It removes all the required ASCII characters and the line break, without splitting the words in those places.
  • It handles 0-digits in Pi correctly (as 10-letter words)

Martin Ender

Posted 2014-09-28T09:14:05.830

Reputation: 184 808

if it works for number of digits of Pi you get a 0.8 bonus – Caridorc – 2014-09-30T11:50:15.620

1

Python 3 - 129

Doesn't account for punctuation:

import math
f=lambda p:all(1if len(p.split(' ')[i])!=int(str(math.pi).replace('.','')[i])else 1for i in range(len(p.split(' '))))

Beta Decay

Posted 2014-09-28T09:14:05.830

Reputation: 21 478

1

Python - 130 127 116 - 17 digits of pi

As in @flawr 's answer, Law ' s fine and Law's fine both return True.

Thanks to @Emil for removing 12 characters from the program.

import re
f=lambda x:all(j==int("31415926535897932"[i])for i,j in enumerate([len(s)for s in re.findall("[\w]+",x)]))

monopole

Posted 2014-09-28T09:14:05.830

Reputation: 1 559

You can save 12 characters by not saving l in a variable and by defining the function using lambda. – Emil – 2014-09-28T12:26:25.637

1

Java, 185

boolean f(String...s){s=s[0].replaceAll("\\W","~").replaceAll("~+","~").split("~");for(int i=0;i<s.length;){if(s[i].length()!=(int)(Math.PI*Math.pow(10,i++)%10))return 0>1;}return 1>0;}

Ypnypn

Posted 2014-09-28T09:14:05.830

Reputation: 10 485

1

python 3, 17 digits of pi, 104

import re;f=lambda s:all(map(int.__eq__, map(int, '31415926535897932'), map(len,re.findall('[\w]+',s))))

pgy

Posted 2014-09-28T09:14:05.830

Reputation: 830

You can replace the ; with a newline for readability. Also, a number of spaces can be removed. – tomsmeding – 2014-10-02T11:11:46.137

0

T-SQL 488 383

And now for a large T-SQL solution :)

CREATE FUNCTION F(@s VARCHAR(MAX))RETURNS CHAR(6) AS BEGIN DECLARE @ CHAR='T',@p VARCHAR(50)='31415926535897932384626433832795028841971693993751',@i INT=0WHILE @='T'AND @s<>''BEGIN SET @i=PATINDEX('%[^a-z0-9]%',@s)IF @i=0RETURN'#True'IF @i-1<>LEFT(@p,1)RETURN'#False'SET @p=STUFF(@p,1,1,'')SET @s=STUFF(@s,1,@i,'')SET @s=STUFF(@s,1,PATINDEX('%[a-z0-9]%',@s)-1,'')END RETURN'#True'END

This creates an inline table valued function that uses a recursive CTE to detect word boundaries.

Creates a scalar function that chews it's way through the words and PI to 31 decimals (first 0). It is called in the following way

SELECT dbo.f('SQL I golf, a large procedure is normal. Hefty not terse') --#True

MickyT

Posted 2014-09-28T09:14:05.830

Reputation: 11 735

0

CJam, 40

"
,.'\"?!;:"{-}/S%{,PAV#*iA%=V):V}/]0#)!

It's unclear what is meant by "any kind of punctuation"; this solution removes the ,.'"?!;; characters.

Ypnypn

Posted 2014-09-28T09:14:05.830

Reputation: 10 485

0

Bash and unix tools, 111

f() { grep ^"$(echo "$@"|grep -Po '[\w]+'|xargs -n1 sh -c 'echo ${#0}'|xargs|tr -d ' ')"<<<31415926535897932; 

pgy

Posted 2014-09-28T09:14:05.830

Reputation: 830

0

NodeJS 32 digits 230 Bytes

I can't get it shorter with JS :D

var p = "31415926535897932384626433832795", i = 0;
console.log(process.argv[2].split(/[\s,.]+/).every(function(w) {
    if (parseInt(p.charAt(i)) !== w.length) {
        return false;
    }
    i++;
    return true;
}) ? 'True' : 'False');

Wikunia

Posted 2014-09-28T09:14:05.830

Reputation: 196

remove whitespace. – Rohan Jhunjhunwala – 2017-01-02T01:49:54.030