30
\$\begingroup\$

Good Evening Golf Agents,

Your mission is on behalf of notorious entertainment giant Eviltronic Arts. As part of their nefarious plan for world enslavement and entertainment, they must sell as many copies of SimStation V as possible. This means that the software must mysteriously stop working, after starting it a few times.

Your goal is to write a program that counts the amount of times it has been run. The program must do nothing other then write the integer to stdout. The first time it is run, it should return "1". The next "2" and so on. The program must be able to at least reach the number "14", but there is no required upper limit.

However, your program must not write any new files. Accessing itself, or the registry, or even the internet is absolutely OK. But some of our users are suspicious of new files, and will merely overwrite them! The nerve! Defeating the limitations on software they legitimately purchased!

The program can not assume a stable interpreter or shell - the program must still work if the entire interpreter nay shell nay computer is restarted between running.

As it must be as undetectable as possible, the shortest source code will win.

Good luck agents. The entertainment industry is counting on you.

\$\endgroup\$
  • \$\begingroup\$ Related. \$\endgroup\$ – user62131 May 9 '17 at 7:28

23 Answers 23

21
\$\begingroup\$

bash script, 39,37,21 18

wc -l<$0;echo>>$0

Short and sweet, my first submission in code golf :)

\$\endgroup\$
  • 1
    \$\begingroup\$ Replace echo with id :D \$\endgroup\$ – thejh Mar 31 '13 at 15:14
  • \$\begingroup\$ it appends unnecessary output to file, which will be redirected to stderr \$\endgroup\$ – Rozuur Mar 31 '13 at 15:16
  • \$\begingroup\$ Huh? There's nothing here that interacts with stderr. But right, it makes the file grow larger over time. \$\endgroup\$ – thejh Mar 31 '13 at 15:20
  • \$\begingroup\$ can be golfed to 17: Replace the ; with newline and remove the trailing newline. It will even look a lot nicer :-) \$\endgroup\$ – Tomas Feb 2 '14 at 15:24
  • \$\begingroup\$ Is only the starting size of the script relevant? Considering that this will increase in size every run. \$\endgroup\$ – unclemeat Feb 3 '14 at 2:42
18
\$\begingroup\$

Python, 40, 39, 38 characters

Also there is no such upper limit on the runtime:

open(__file__,'a').write("+1");print 1

As you can see, the size of the program gradually increases but there was no such restriction in the original problem. I believe, size of the submitted program is all what matters

\$\endgroup\$
  • \$\begingroup\$ I don't think you need to put a+, a should work fine. \$\endgroup\$ – beary605 Mar 31 '13 at 15:46
  • \$\begingroup\$ @beary605: Thanks for the Tip \$\endgroup\$ – Abhijit Mar 31 '13 at 15:54
10
\$\begingroup\$

PHP 48 bytes

<?=$n=1 ;fputs(fopen(__FILE__,c),'<?=$n='.++$n);

A simple self modifying approach. After running 99 times, it will crash spectacularly.

$ php increment.php
1
$ php increment.php
2
$ php increment.php
3

$ php increment.php
97
$ php increment.php
98
$ php increment.php
99
$ php increment.php
PHP Parse error:  syntax error, unexpected T_STRING, expecting ',' or ';' in increment.php on line 1
\$\endgroup\$
  • \$\begingroup\$ isn't the single whitespace unneccessary? \$\endgroup\$ – John Dvorak Mar 31 '13 at 5:41
  • 1
    \$\begingroup\$ @JanDvorak The single whitespace is necessary in the program, otherwise it would crash after just 10 executions, which doesn't meet the specification. After the 100th execution the semicolon is overwritten, which causes the syntax error. \$\endgroup\$ – primo Mar 31 '13 at 6:00
  • \$\begingroup\$ Got PHP solution for 35 chars, wanna beat me? :) \$\endgroup\$ – Tomas Feb 2 '14 at 15:18
7
\$\begingroup\$

bash script, 37

n=1;echo $n;sed -ie s/$n/$((n+1))/ $0
\$\endgroup\$
5
\$\begingroup\$

Ruby: 31 21 characters

(This is a rewrite of Abhijit's Python solution. If you like the base idea, upvote his answer, like I did.)

open($0,?a)<<"+1";p 1

Sample run:

bash-4.2$ ruby increment.rb 
1

bash-4.2$ ruby increment.rb 
2

bash-4.2$ ruby increment.rb 
3
\$\endgroup\$
  • 1
    \$\begingroup\$ Using << you can save some chars: ` open($0,?a)<<"+1";p 1\ ` \$\endgroup\$ – steenslag Dec 29 '13 at 18:20
  • \$\begingroup\$ Doh. The good old habit of ensuring the data files get closed… :( Thank you, @steenslag. \$\endgroup\$ – manatwork Dec 29 '13 at 18:40
5
\$\begingroup\$

*sh, 17

curl -L x.co/z7Uk

Using a web service, a different approach than the other existing solutions so far. Limit: The memory of my machine.


JavaScript, 40

alert(localStorage.a=~~localStorage.a+1)

Hardly counts as a program, but it's quite long anyways. Does not work in Firefox in a local file. Limit: 2^31.

\$\endgroup\$
  • \$\begingroup\$ Why not alert(localStorage.a=~~localStorage.a+1) 41 and technically speaking the javascript program would be without the script tags which would be only 33 \$\endgroup\$ – David Mulder Dec 30 '13 at 16:46
  • \$\begingroup\$ @DavidMulder Oh, right \$\endgroup\$ – copy Dec 31 '13 at 1:49
  • 2
    \$\begingroup\$ Down to 33: alert((l=localStorage).a=~~l.a+1) \$\endgroup\$ – nitro2k01 Dec 31 '13 at 9:38
  • \$\begingroup\$ @nitro2k01: Seems I copied the wrong stuff, cause that was the 33 I was talking about O:) 41 was the same thing including script tags~ (well, I did the decleration before the alert, cause it's just as long: a=localStorage;alert(a.b=~~a.b+1) though yours looks nicer :D \$\endgroup\$ – David Mulder Dec 31 '13 at 10:42
  • 1
    \$\begingroup\$ @WallyWest Nope, it's actually bitwise invert and abuses JavaScript's weird type conversion rules \$\endgroup\$ – copy Feb 2 '14 at 23:20
4
\$\begingroup\$

PHP 31 37 characters

Self modifying. It counts in unary. Be careful that your text editor doesn't try to be helpful and insert a newline character after the 1. It will only work (properly) in PHP < 5.3.2 because it relies on php to close open file descriptors on shutdown. Or is it acceptable to leak file descriptors?

<?fputs(fopen(__FILE__,a),1)?>1

Original version (36 chars), all PHP versions:

<?file_put_contents(__FILE__,1,8)?>1
\$\endgroup\$
  • 2
    \$\begingroup\$ "It counts in unary"... Best Golf Hack I've seen for a long time! \$\endgroup\$ – lochok Jan 6 '14 at 0:56
  • \$\begingroup\$ I challenge you. PHP solution for 35 chars, and it's in decimal :) \$\endgroup\$ – Tomas Feb 2 '14 at 15:18
  • 1
    \$\begingroup\$ Wow, I see you have beaten me with your own method! Congratulations! :-) And thanks for the improvement of my method. I have included it in my answer and gave you a credit for that. \$\endgroup\$ – Tomas Feb 2 '14 at 21:18
  • \$\begingroup\$ @Tomas I owe you credit. If you hadn't challenged me, I wouldn't have looked at this answer again. \$\endgroup\$ – Tim Seguine Feb 2 '14 at 21:22
  • \$\begingroup\$ Tim, that's exactly the joy and excitement of challenging each other! :) \$\endgroup\$ – Tomas Feb 2 '14 at 21:24
2
\$\begingroup\$

Python, 50

n=1;
print n
open(__file__,'r+').write("n="+`n+1`)

It uses the same approach as primo's answer and similarly crashes on the 100th run.

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

J (58)

You need to run this as a script, it will not work from the J command line obviously.

echo m=.1
exit(;:^:_1(<":m+1)(<3)};:1!:1[k)1!:2[k=.1{ARGV

In J, the tokenizer that the interpreter uses is available as the ;: function, so if x contains J code, ;:x contains the J tokens, i.e.:

    ;: 'echo 1 2 3+4 5 6'
+----+-----+-+-----+
|echo|1 2 3|+|4 5 6|
+----+-----+-+-----+

So:

  • echo m=.1: set m to 1, and write it to the screen
  • k=.1{ARGV: store the 2nd element in ARGV (the script name) in k.
  • ...1!:2[k: write the following string to the file in k:
  • ;:1!:1[k: read k, the current script, and tokenize
  • (<":m+1)(<3)}: replace the 3rd token by the string representation of m + 1
  • ;:^:_1: run the tokenizer in reverse, producing a string
  • exit: exit the interpreter (it doesn't do that by itself even if you run a script)
\$\endgroup\$
2
\$\begingroup\$

PHP, 34 33 chars

<?=$_SESSION[A]+=session_start();

Thanks to Tim for the update! My old solution:

<?=session_start()+$_SESSION[A]++;

The problem is that $_SESSION[A] is "" - empty string - in first iteration, but as session_start() returns 1, you can add it and kill two or three flies in one shot!

Solution with correct syntax (35 chars):

<?=session_start()+$_SESSION[A]++?>
\$\endgroup\$
  • \$\begingroup\$ I will hold of judgement for a second for two reasons. "However, your program must not write any new files.": I am not sure if this isn't a problem for this solution, since opening a session creates a temporary file. Also the default session gc happens after 24 minutes. Does that really count as "over multiple sessions" then? Maybe the OP can comment. \$\endgroup\$ – Tim Seguine Feb 2 '14 at 19:05
  • \$\begingroup\$ Tim, the program doesn't write any files. I am not responsible for what the interpreter does. It's the same as HTML page is not responsible for browser creating some files in the cache, sql query is not responsible for created temporary tables on disk etc. As for the timeout, it was not specified in the rules :) Anyway, I am not sure why but on my machine the counter still holds for more than several hours!!! \$\endgroup\$ – Tomas Feb 2 '14 at 19:27
  • \$\begingroup\$ Yeah, that's why I am saying I will wait to see what the OP thinks. You definitely found a very grey area. You don't need the closing php tag btw. so your 34 char version is sufficient. I have an idea for an improvement, but I will need to test it first. \$\endgroup\$ – Tim Seguine Feb 2 '14 at 19:32
  • \$\begingroup\$ Okay, I got it down to 33 chars. I dare you to do better. ;) \$\endgroup\$ – Tim Seguine Feb 2 '14 at 19:39
  • \$\begingroup\$ @TimSeguine Aaaah, what a change in your tone! :-) Now you don't care about the rules in my post so much! :-D \$\endgroup\$ – Tomas Feb 2 '14 at 19:43
2
\$\begingroup\$

Haskell - 36 bytes

main=do appendFile"a.hs""+1";print$1

Simply adds +1 to the end of the source file, which is assumed to be named a.hs. The .hs extension is mandatory in both ghc and ghci.

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

TI-Basic, 9 chars

:X+1->X:X
\$\endgroup\$
1
\$\begingroup\$

Batch - 41

Given the example use case I probably wouldn't assume that this technique is a viable one - It renames the .bat file containing the script -

@set/aa=%~n0+1
@echo %a%&@ren %0 %a%.bat

Save this to a file called 0.bat - and call using 0.bat 2>nul. 2>nul redirects stderr to nul which is necessary because this script will rename the file containing the script, once it does that cmd can obviously no longer see the script (before it hits EOF) and will return the error The batch file cannot be found.

Each consecutive call of the script will of course have to be 1.bat 2>nul ... 2.bat 2>nul ... 3.bat 2>nul ... etc ...

\$\endgroup\$
  • \$\begingroup\$ Based on this idea, you can do a variation of my php answer of counting in unary and I think it is even shorter than this. \$\endgroup\$ – Tim Seguine Aug 1 '18 at 12:01
1
\$\begingroup\$

mIRC script, 28/22 bytes

If put in "aliases" tab, "alias " can be omitted making 22 bytes.

alias x inc %i | echo -ag %i
\$\endgroup\$
1
\$\begingroup\$

Python, 49 48 characters

I realized this will only be 48 chars on Windows due to the \r\n. Otherwise it should be 49.

n=1

print n;print>>open(__file__,'r+'),"n=",n+1

A cheap ripoff of the method by @grc

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

C, 190 Characters . Works only on Win NT

#include <stdio.h>
int main(int c,char *v[]){
char f[100];sprintf(f,"%s:s",v[0]);
if (FILE *fp=fopen(f,"r"))fscanf(fp,"%d",&c);
FILE *fp=fopen(f,"w");printf("%d",c-1);fprintf(fp,"%d",++c);
}
\$\endgroup\$
  • \$\begingroup\$ I think its pretty simple how its working, but still if required I can add an explanation :-) \$\endgroup\$ – Abhijit Apr 1 '13 at 7:30
1
\$\begingroup\$

C#, 142 characters

int v=(Microsoft.Win32.Registry.CurrentUser.GetValue("c") as int?)??0+1;Console.Write(v);Microsoft.Win32.Registry.CurrentUser.SetValue("c",v);
\$\endgroup\$
  • \$\begingroup\$ You could use a shorter name like z, would get you a few chars down. \$\endgroup\$ – It'sNotALie. Apr 18 '13 at 20:51
  • \$\begingroup\$ You should also remove the whitespace. \$\endgroup\$ – Timtech Dec 29 '13 at 1:38
  • 1
    \$\begingroup\$ Instead of calling long API name each time, store it in a variable like: var a = Microsoft.Win32.Registry.CurrentUser; a.GetValue(); a.SetValue(); \$\endgroup\$ – Xantix Feb 2 '14 at 22:17
1
\$\begingroup\$

Tcl, 63 or 73 bytes

  • With some web service it's 73:

    package require http
    puts [set [http::geturl http://example.com/c](data)]
    
  • modifying itself is 63:

    proc a a {puts [string le $a]};puts -nonewline [open $argv0 a] a; a a
    
\$\endgroup\$
1
\$\begingroup\$

C# - 201 239 234 chars

Works for the first 255 times, then wraps over to 0. It won't output anything on the first execution.

namespace System.IO{class s{static void Main (string[]a){char f='|';if(f!='|'){Console.Write (255);}string p=Reflection.Assembly.GetCallingAssembly().Location;byte[]d=File.ReadAllBytes(p);d[769]++;d[780]++;File.WriteAllBytes(p,d);}}}

Save as Main.cs, compile with

gmcs Main.cs

Tested with gmcs 2.10.8.1 and Mono runtime 2.10.8.1-5ubuntu2

\$\endgroup\$
  • 1
    \$\begingroup\$ Actually - I did. "The program must be able to at least reach the number 14" \$\endgroup\$ – lochok Feb 2 '14 at 22:53
  • \$\begingroup\$ It works now for 255 times. \$\endgroup\$ – user3188175 Feb 5 '14 at 21:09
1
\$\begingroup\$

Powershell, 47 Bytes

assumes script is named a.ps1

0
[int]$n,$t=(gc a.ps1)[0..1];,(++$n),$t>a.ps1

The script will overwrite itself replacing the 0 on the first line with 1,2,3 and so on.

could also save another 8 bytes by replaceing both instances of a.ps1 with 1 and saving the script as a file named 1 although this is a bit far out for me.

Replace second line with this if the file is not saved as 'a.ps1'.

[int]$n,$t=(gc($s=$MyInvocation.MyCommand.Name))[0..1];,(++$n),$t>$s

0 on first line to initialize the count

Linebreak provides the easiest way to split the file in two

[int]$n,$t=(gc a.ps1)[0..1]

this takes the file 'a.ps1' and reads it in as an array of lines, we then iterate through it with [0..1] and set that to the variables $n which is cast as [int] and $t respectively, so that the 0 on the first line becomes $n and the 'code' on the second line becomes $t

,(++$n),$t>a.ps1

This used the ,1,2 array notation, to create an array of two elements, one being the number stored in $n pre-incremented and outputted to stdout by the use of implicit brackets, the second being the second line of text from the file, and then also output it to the file named 'a.ps1'

as both input and output are arrays of strings there is minimal formatting required, and almost everything is assumed by the interpreter.

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

Zsh (no coreutils), 32 bytes

a=`<$0`
<<<$[$#a/2-15]
>>$0<<<:

(Note the trailing newline) Uses the length of the script. On each invocation, the last line shown above will append : (identical to true) and a newline to the script, hence the /2.

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Rust / cargo-script, 283 bytes

Oneliner:

use std::fs::File;use std::io::Write;fn main(){let c=     0; let mut v = vec![];::std::io::Read::read_to_end(&mut File::open("w").unwrap(),&mut v);let mut q=&mut File::create("w").unwrap();q.write(&v[..53]);q.write(format!("{:6}",c+1).as_bytes());q.write(&v[59..]);println!("{}",c);}

Save as w and run with cargo-script:

$ cargo-script script w
   Compiling w v0.1.0 (file:///home/vi/.cargo/script-cache/file-w-b4d6541706fabb11)
    (warnings skipped...)
    Finished release [optimized] target(s) in 1.47 secs
0
$ cargo-script script w
    (compilation output skipped)
1
$ cargo-script script w
...
2
$ cargo-script script w 2> /dev/null
3
$ cargo-script script w 2> /dev/null
4
$ cargo-script script w 2> /dev/null
5
$ cargo-script script w 2> /dev/null
6
$ cargo-script script w 2> /dev/null
7
$ cargo-script script w 2> /dev/null
8
$ cargo-script script w 2> /dev/null
9
$ cargo-script script w 2> /dev/null
10
$ cargo-script script w 2> /dev/null
11

Don't iterate too fast or it'll get stuck.

Partially ungolfed:

use std::fs::File;use std::io::Write;fn main(){let c=     0;
    let mut v = vec![];
    ::std::io::Read::read_to_end(&mut File::open("w").unwrap(),&mut v);
    let mut q = &mut File::create("w").unwrap();
    q.write(&v[..53]);
    q.write(format!("{:6}",c+1).as_bytes());
    q.write(&v[59..]);
    println!("{}", c);
}

Will break after 99999;

\$\endgroup\$
0
\$\begingroup\$

GNU sed, 13 + 1(n flag) = 14 bytes

$=;$eecho>>s

Run: sed -nf s s

The assumption is that the source filename is called s. A trailing newline is needed after the code, which was counted in the bytes total. Explanation:

$=           # print the number of lines of the input file
$eecho>>s    # a shell echo call that appends an empty line to the source file 's'
\$\endgroup\$

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.