56
\$\begingroup\$

Some time ago, the following question was asked: GolfScript, CJam, or Pyth? Based on the title only, I thought that it would be a very nice challenge, but unfortunately, it turned out to be a question asking for tips. Here is the challenge I wanted to read:

Who said golfing languages were not used in the Real World? As everybody knows, the ratio of bugs per line of code is the same independently of the programming language being used, so there is a clear opportunity to reduce debugging and maintenance costs with those languages. Your company finally saw the light and decided to use Golfscript, CJam and Pyth to develop its products.

Unfortunately, after a couple of months, your hard drives are cluttered with snippets of code and you don't even know which ones are written in which languages (you even suspect some of your programmers of using Perl).

You must write a tool to detect which of CJam, Golfscript or Pyth is the language in which a program is written. The situation is critical, you can use any language you want, but please keep it short (data storage is expensive: the more bytes we use, the more it costs).

General

  • Shortest code win
  • Standard loopholes, etc.
  • Don't use an online interpreter
  • You can write a function or a program
  • You can use eval to detect your own language

Input

  • Your input is taken from the standard input stream or as a string
  • Input contains only ASCII printable characters and linefeeds
  • The size of the input is up to 256 bytes long

Output

  • Output is printed to output stream or returned as a sequence of strings/symbols
  • If the input is without doubt a valid X program, print or return X, X ∈ {CJam, Pyth, Golfscript}

    Remark: "without a doubt" does not mean that you are allowed to answer with a dumb analyzer that consistently fails to detect any language. For Pyth, I expect Simple Programs to be recognized (but no hardcoding). The same goes for CJam (cheat sheet, examples) and Golfscript (examples). The previous links point to each language's specifications. If you use a fuzzy/bayesian approach, "without a doubt" means with a high-level of confidence (you score 99% with your classification, for example). See below for the actual test suite.

  • If the input is valid in multiple languages, each detected language should be printed/returned. When printed, there must be a separator between multiple outputs (e.g. space, newline, comma...).

  • The order in which languages are tried does not matter
  • I do not care about case (CJam, cjam, CJAM, SPAM) [1]
  • If none of the above language is detected, print "Probably Perl". Thanks to this comment from mbomb007, in the above case you can also output "Seriously" for a penalty of 4 bytes (the difference between both strings).

[1] Just to be clear, SPAM is invalid

Examples

  • Input

    "Crime predicted: --
    Calling: 1--555-
    
    "30*{_5<{iAa*:mr}&}/
    
  • Output (example of multiple return values)

    ["Golfscript", "Cjam"]
    
  • Input

    3
    
  • Output (example on standard output)

    golfscript
    cjam
    pyth
    
  • Input

    if {} aazd
    
  • Output

    Probably Perl
    

In the last case, the input program produces an error With All Three online interpreters.

Scoring, winning criterion

Shortest code win. Add 4 bytes if you output "Seriously". Then, apply bonuses.

Failing tests

The following are snippets that must not be recognized as any of the three languages above.

One-liners (i.e. one entry per line)
$^X=~/([a-z]+)[^\/]+$/;print$1,$/
<>;map($s-=(-1)**$_/(2*$_-1),1..$_),$s=!print$s,$/for<>
((THIS IS LISP HAIKU) (TRULY THIS IS LISP HAIKU) (THIS IS LISP HAIKU))
(format t"~@(~{~R~^, ~}~).~%~:*~@(~{~:R~^, ~}~)."(loop for i to 99 collect(1+ i)))
print sum(ord(c) for c in 'Happy new year to you!')
Brainfuck
>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.
++++++++++++++++++++++++++++++++++++++++++++++++.
-----------------.
++++++++.
+++++.
--------.
+++++++++++++++.
------------------.
++++++++.
Perl
@list=( "aaaa", 
        "aaaaaaaa", 
        "aaaaaaaaaaaaaaa", 
        "aaaaaaaaaaaaaaaa", 
        "aaaaaaaaaaaaaaaaaaaaaaa", 
        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");

while (@list) {
    for($i=0;$i<6;$i++){
        print length($list[$i])." ";
    }
    print "\n";
}
Fish
#ifndef __linux
#include "x.h"
#define X/*\
a=1 set -e
+++++++++++++++++++++_+++++++++++++....Hello World!?:Q:
#endif
    echo "Hello, World!"
    int m(){}

Basic test suite

Those are tests which must pass. Belows are one-liners for each language where your program must detect the language it is being written in (I did not check which of those are polyglot).

Pyth

*2Q
FNrZTN
FNrZhTN
FNUhTN
VhTN
FNr1hQN
=N5N
K5K
K1FNr1hQ=K*KN
K1FNr1hQ=K*KNK
K1FNr1hQ=K*KN;K
DhZK*3ZRK
L?b*bytb1yQ
A(Z1)VQHA(H+HG

Golfscript

;'2706 410'~{.@\%.}do;
;''6666,-2%{2+.2/@*\/10.3??2*+}*`50<~\;
'Hello, world!'
1 2 [\]

CJam

"Hello, world"
{`"_~"}_~
"`_~"`_~
T1{_2$+}A*]`
{__'`>\'x>26*2-*-}/
Y38#
N/s:X,8-,{X>9<__{'a<},,\4%{'Z>},,*I={4=}{;}?}/

Silver bonus: byte-count * 0.6

All previous tests must pass, as well as the following one-liners. All those snippets are taken from actual CodeGolf answers.

Pyth

VzJ:zZhZpkJ~Zhy}rJ0-G"aeoui
Vzjdm?@zd}N,dt-lzd\ Uz
jd.iSQs*RtQ,\?":0
rsXOtQmO*-GJ"aeiou"J/Q2*%Q2O"hy"4
VhQIq`N_`NN
s["$$\\varphi=1+"*Q"\cfrac1{1+"\\<\dQ"dots"*Q\}"$$
@c"weak trick fair"d-!JlfhT-M.:us_cG.u+NYtKrH7-52hK.zU52 2>J26

Golfscript

);:|;{0):0;|$:§-1%" - "§" = ""0"4$~§~-+-4>:|n|6174`=!}do"Iterations: "0"."
'-+,/'{)))))}%
4:echo(2+2);
#undef X;A!"$%&'()*+-[,.]/0123456789:<=>?@BCDEFGHIJKLMNOPQRSTUVWYZ\^_`abcghijklmopqrstvwxyz{|}~
{`),32>^.}.~
"126,32>''+".~\-'.~\-"'-
"),@`^^32>#.~".~
...[[]]{{}}&%%++++5i
  *++..0011125::::;;;?bbbbcccc{}
"This program wasn't written in "o"GolfScript"", it was built for ""CJam"oo"!"

CJam

"Q"c("ASSW"1$("aRD"(((T1
%\@_@){;_0}*__*)\15
"This program wasn't written in "o"GolfScript"", it was built for ""CJam"oo"!"
"P2"1e3K51_,1>K*$K*~]N*
li__,\mf:i2m1+:*/fb:+
ri:B__(^2/):G/,{_BBG/@-(#G@*G(B2/*+*}/]:+
{1$+S@]_1=4+1$`,-S*"2$~"}21D2$~
[S'-26*N]:Z[S'|:PS24*PN]:RR'(PS5*qi:XD=X0<-X2%2*+:Y[" ^ "_" > ""(O)"" - "__]=S8*Y[" ^ ""   "" < ""(O)"" - "__]=S5*P')NRRXD=[SPS7*'oA*S7*PN]:QR?Y[[SPS5*'oSC*'oS5*PN]:T_R[SPS7*'oS8*'oS7*PN]RRR]=QY2=TR?RRZ
li4H#+2bW%32<2b
q~:R100:H*\d:T/i){R-H*HT-/m]}6*_H)<*
"JamesBdo,"YZ+/)BA*c+Y*Y%:BS@SB)))[JW:Z____)ci+*]U*

Gold bonus: previous-score * 0.8

Pyth

Compare
jdm@cd)._-FQcj"
is
equal greater less
to than
"Qb
Snowman
M@GCHgc"  ___

  ___
   _"bhzgc" (_*_)
 _===_
 .....
  /_\\"bhzs[g"  \ "@z4\(g"-.oO"@z2g" ,._"@z1g"-.oO"@z3\)g"  / "@z5)s[g" < /"@z4\(gc"   
 : 
] [
> <"b@z6\)g" > \\"@z5)++" ("gc"   
 : 
\" \"
___"bez\)

CJam

Big
rri:Hri:Vri:Q[q~]3/_Qa3*a+_|$W%:Pf{\a#}:AH/:B0ff*
P,,[AHAW%HBz:+_W%V\V]2/
ff{~@@f=/::|1#}0Ua4*t:R;
P0f<
V{H{BI=J=_2$=
0R{"I>! I+V<J>! J+H<"4/+4/z{~~}%:&1$*\)}%);2$-|t
}fJ}fI
[P,{_La#\1$0t1$f-}*;;]
{:TR=2/~\~V\-,>\f{\_3$=@~H\-,>{Tt}/t}~}/
:~Pf=:~
~]S*N
Snowman
q:Q;SS"
 _===_,___
 ....., _
  /_\,___
 (_*_)"',/0{Q=~(=}:G~N" \ "4G'(".oO-"_2G",._ "1G@3G')" / "5GN"< / "4G'(" : ] [> <   "3/6G')"> \ "5GNS'(" : \" \"___   "3/7G')

Golfscript

Lorem Ipsum
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras imperdiet est ut sem commodo scelerisque. Sed ut ultricies enim. Nam eget lectus suscipit, gravida turpis a, volutpat tellus. Cras efficitur luctus neque, at semper massa condimentum at posuere.
Digital clock
:*{32' _':$@'14'{?~!=}:&~32}%n*{:x' |':|\'1237'&$x'017'&|x'56'&}%n*{:x|\'134579'&$x'147'&|x'2'&}%
Happy birthday
4,{"Happy Birthday "["To You""Dear GolfScript"]@2==n}%
Farey sequence
~:c[,{){.}c(*}%.c/zip{+}*]zip{~{.@\%.}do;1=},{~<},{~\10c?*\/}${'/'*}%', '*'F'c`+' = {0/1, '+\', 1/1}'
\$\endgroup\$
  • 54
    \$\begingroup\$ From the title, I was hoping this included a new esoteric language called "Seriously". \$\endgroup\$ – mbomb007 Sep 23 '15 at 15:21
  • 17
    \$\begingroup\$ @mbomb007 Seriously: a language that runs result of the source interpreted in Golfscript as Pyth, then pushes the newline separated values onto a CJam stack and finally outputs to STDOUT from there. Twice as easy to use as perl :^) \$\endgroup\$ – FryAmTheEggman Sep 23 '15 at 15:27
  • 3
    \$\begingroup\$ @mbomb007 I feel your disappointment. May I suggest to ask your own question? "Not so long ago, the following question was asked..." \$\endgroup\$ – coredump Sep 23 '15 at 15:58
  • 31
    \$\begingroup\$ And this, my friends, is why shebangs were invented. \$\endgroup\$ – primo Sep 25 '15 at 8:29
  • 6
    \$\begingroup\$ I will give a 150 rep bounty to the first solution that is eligible for the gold bonus and validates inputs based on pattern matching, rather than my simple solution of running the programs through the interpreters. \$\endgroup\$ – Mego Oct 31 '15 at 20:21
2
\$\begingroup\$

Ruby, (135 + 4) * 0.6 * 0.8 = 66.72

This runs on Windows and I'm too tired to shorten it by running on Unix.

(a=[%w(javaw -jar cjam),%w(python pyth),%w(rubyw golfscript)].map{|c|c[-1]if system(*c,?f,'> NUL','2>','NUL')}-[nil])==[]?'Seriously':a

I did these things but I'm not sure if they're allowed:

  • Rename cjam-[version].jar to cjam, pyth.py to pyth, golfscript.rb to golfscript.
  • Read from file f instead of getting input. (Add IO.write(?f,gets); to the beginning to fix that, and the new length is (153 + 4) * 0.6 * 0.8 = 75.36)
\$\endgroup\$
  • \$\begingroup\$ Unfortunately, I can't test it (a combination of Windows and a lack of time). It looks good and your score is lower, so I am moving the checkmark. \$\endgroup\$ – coredump Apr 26 '18 at 4:30
39
+150
\$\begingroup\$

Python 2, 332 * 0.6 * 0.8 = 159.36

import os
from subprocess import*
from tempfile import*
f,n,a=NamedTemporaryFile(delete=0),open(os.devnull,'w'),''
f.write(os.read(0,256))
f.close()
for l in["CJam","java","-jar","cjam.jar"],["Pyth","./pyth.py"],["Golfscript","./golfscript.rb"]:a+=(l[0]+' ')*(call(args=l[1:]+[f.name],stdout=n,stderr=n)>0)
print a or'Probably Perl'

As far as I'm aware, this is within the rules. Requires the Pyth, CJam, and Golfscript interpreters (pyth.py, cjam.jar, and golfscript.rb) in the current directory, and Python 3, Java, and Ruby installed. Simple test: try running the program. If it returns with 0, we're good. If not, it's invalid. A named temporary file (e.g. a file created in $TMP) is created to hold the program, since CJam doesn't have a script option. The delete=False flag is necessary to prevent the file from being deleted when it is closed (the OS will take care of it for us). The file has to be closed before attempting to read from it (though manually flushing the file should also work, but this is simpler). stdout and stderr are redirected to /dev/null to suppress output/errors (note that this makes it only work on *NIX systems).

Extra fun: try running the given code in all 4 languages, to see what we get:

import sys
from subprocess import*
from tempfile import*
c=["Cjam","java","-jar","cjam.jar"]
p=["Pyth","./pyth.py"]
g=["Golfscript","./golfscript.rb"]
e=["Perl","perl"]
f=NamedTemporaryFile(delete=False)
s=sys.stdin.read()
f.write(s)
f.close()
n=open('/dev/null','w+')
a=''
for l in [c,p,g,e]:
    try:
        print '%s: %s'%(l[0],check_output(args=l[1:]+[f.name],stderr=n))
    except:
        continue
n.close()
\$\endgroup\$
  • 11
    \$\begingroup\$ +1 Nice answer. And it only requires 6 interpreters to run, well done ;-) \$\endgroup\$ – coredump Oct 16 '15 at 18:00
  • 1
    \$\begingroup\$ bash, Python 2, Python 3, Ruby, Java, CJam, Pyth, Golfscript - I count 8. \$\endgroup\$ – Mego Oct 16 '15 at 18:25
  • 2
    \$\begingroup\$ That's right. And with the right input file, it can even wipe your home directory. Anyway, this is a valid approach, I don't mind. \$\endgroup\$ – coredump Oct 16 '15 at 18:40
  • \$\begingroup\$ Just let's hope you get no programs with endless loops, or returning non-zero. \$\endgroup\$ – Paŭlo Ebermann Oct 17 '15 at 22:41
  • \$\begingroup\$ @Mego if a program itself fails for some reason (like when opening a file which does not exist – or when it is expecting arguments, which I suspect might happen more often for actually productively used programs), it should return a non-zero value according to that decade-old standard. This doesn't mean it doesn't belong to that language. (It might be none of the test cases are actually of that type, though.) Another case might be waiting for input, like a cat program ... maybe you should at least try to redirect /dev/null also to the input? \$\endgroup\$ – Paŭlo Ebermann Oct 17 '15 at 23:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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