Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Winners (decided 14/09/14)

Winning answer by Markuz (Python) - 63 votes

Runner up by kuroi neko (PHP) - 55 votes

Introduction

You are in the world of the book Nineteen Eighty-Four by George Orwell.

You are a programmer for the Party and are tasked with writing a program for the telescreens. It should output pro-party messages, and you have chosen the ones shown in task 1. below. However, you have recently begun to despise the Party, and you want the program to spark a revolution. So, you make the program say "Down with Big Brother!". You must give yourself time to escape, as you will be tortured once people realise what your program does, so you make it act as a "timebomb" that will explode after you have gone to safety.

Note: This will not spark a revolution, but you are in such a frenzy of hatred towards the party that you think it will actually make a difference.

Task

Write a program which:

  1. before 14/09/2014, will always output the following lines on a rotation (i.e. prints one line, waits 10 seconds, prints next line, etc. ad infinitum):

    War is Peace
    Freedom is Slavery
    Ignorance is Strength
    
  2. after 14/09/2014 will print Down with Big Brother! every 10 seconds.

  3. at first glance looks like it does only 1. so that you will not be caught by the Party.

Rules

  • Standard loopholes are of course not allowed.
  • This is an underhanded challenge, and so the main objective is to make task 2. as inconspicuous and covert as possible.
  • The Party will look at all of the files used, so you can't just store the secret message in a file!
  • If your language does not support finding the date, or makes it very difficult, you may make the program execute task b) after it is run for 240 hours (10 days).
  • You should include the code and an explanation of how it works in your answer.
  • This is a popularity contest.

Note: It is not a difficult program to write. The difficult part should be hiding the "revolutionary" code. Lines where it is not clear what you are doing will be questioned by the Party, and you will have to explain them.

Example - Python 3

Note: Obviously this program is way too obvious.

from datetime import datetime
from time import sleep

lines = ["      War is Peace   ",
         "  Freedom is Slavery ",
         "Ignorance is Strength"]
secretlines = ["Down with Big Brother!"]

def main():
    while True:
        now = datetime.now()
        year, month, day = now.year, now.month, now.day

        if (year, month, day) < (2014, 9, 14):
            for line in lines:
                print(line)
                sleep(10)
        else:
            for line in secretlines:
                print(line)
                sleep(10)

if __name__ == "__main__":
    main()

Thanks to Calvin's Hobbies for pointing out a problem with the code above (now fixed).

share|improve this question
30  
+1 for doubleplusgood idea –  kuroi neko Sep 3 at 19:59
2  
@kuroineko Surely that should be +2 ! –  sweeneyrod Sep 5 at 13:35
1  
What an ugly condition in your example script... Why not if (year, month, day) < (2014, 9, 14): for line in lines: ...? –  Bakuriu Sep 5 at 16:43
    
+1 for both Newspeak and 1984. –  Mew Sep 7 at 5:32
1  
@laurencevs "(although I doubt they'd be that useful in an underhanded contest anyway)" - Several of the standard loopholes are there primarily because of featuring in so many underhanded contests :) like the ??/ trigraph, or the 'a' that only looks like another 'a' but is actually the Russian cyrillic 'a' unicode character –  doppelgreener Sep 8 at 0:25

7 Answers 7

up vote 64 down vote accepted

Python

This program writes to a log file if it runs fine or if it has encountered an error.

Since this program will run forever, it only writes to the logfile on the 14th day of each month in order to save disk space.

import time as ut
import sys as iw

#initialize global variables
gw, hn, ki, wh = 0, 0, 0, 0
go = open("BigBrother.log", "a")

while True:
    try:
        #if it is the 14th day of a month:
        #write day, month, year and 'Everything works fine!' into the logfile 
        if gw == 14 and hn != wh:
            #store the current month in wh, so that the log message is only written once per month
            wh = hn
            go.write(gw + hn + ki + " Everything works fine!")

        for gD in ["War is Peace", "Freedom is Slavery", "Ignorance is Strength"]:
            print gD
            ut.sleep(10)

        #get the current date
        #gw=day, hn=month, ki=year
        gw, hn, ki = map(int, ut.strftime("%d %m %y").split())
    except Exception:
        try:
            #in the unlikely event that something went wrong:
            #print out all global variables as well as the name of the program,
            #so that our comrades from the IT support can quickly locate and fix the problem.
            wh = "".join(dir())
            print "%s %s %s!" % (wh[47:55:2], wh[55:63:2], iw.argv[0])

            #write an error message to the logfile
            go.write(gw + hn + ki + " ERROR!")

            #and then safely exit the program
            exit(1)

        #we get here if an error occured in this exception block,
        #for example if the write to the logfile failed.
        except Exception:
            #just wait 10 seconds and then try again
            ut.sleep(10)

How to run it:

python "Big Brother"

Note: The name of the script is actually important, as this program outputs "Down with 'script name'!".

How it Works:

  • The write to the logfile throws an exception because the program tries to add integers and strings.
  • The call to dir() returns a sorted list with the names of the global variables, not the values:

    ['____builtins____', '____doc____', '____name____', '____package____', 'gD', 'go', 'gw', 'hn', 'iw', 'ki', 'ut', 'wh']
    
  • Print out every second letter + the name of the script: "Down with Big Brother!"
  • The exit(1) is never executed because the write to the logfile fails again.
share|improve this answer
7  
Very ingenious! –  laurencevs Sep 4 at 8:25
1  
A worthy recruit for the Resistance indeed :). –  kuroi neko Sep 5 at 2:21
5  
All the others have cryptic code. Yours has none. I can't imagine why this isn't in top place. –  Loren Pechtel Sep 5 at 4:36
3  
@LorenPechtel I hope for the sake of your coworkers that your programs don't contain things like print "%s %s %s!" % (wh[47:55:2], wh[55:63:2], iw.argv[0]) :). What is brillant in this solution is the "needle in a haystack" approach: a flow of bullshit comments that encourage a careless reader to skip the details, IMHO. –  kuroi neko Sep 6 at 13:35
    
@kuroineko I don't know Python, I thought those were formatting commands. All the other approaches bury it in a bunch of confusing code, this one looks like a reasonable program. –  Loren Pechtel Sep 6 at 21:10

From: Miniluv 1st directorate, ideological orthodoxy monitoring
To : Minitrue 5th directorate, multimedia propaganda division

by order of Miniluv/GT07:48CT/3925:

  • In order to reduce the wear on our memory banks:
    Effective immediately, all identifiers will be limited to 2 characters ($ not included).
  • There is but one class, and that is the proletarian class.
    Effective immediately, the use of classes in PHP will be considered a 1st grade thoughtcrime.
  • Comments are but a leftover of bourgeois programming practices and a waste of storage space. Effective immediately, commenting a source code will be considered a criminal offence.
  • To avoid breeding thoughtcrimes, lines displayed on a telescreen will be limited to three (3) words.
    As a special exception, the name of our beloved Comrade Great Leader will count as one word. Effective immediately, all programs will be designed to enforce this rule.

Exceptional derogations can be granted under the supervision of Miniluv/GT07

Long live Big Brother!

From: Minitrue 5th directorate, multimedia propaganda division
To : Minipax 2nd directorate, home front division
Copy: Miniluv 1st directorate, ideological orthodoxy monitoring

As you well know, comrades, the 14th of September is the anniversary of our glorious leader. For this special occasion, we will display a specific message of love on all the telescreens of Airstrip One.

As ordered by the Central Commitee and in order to maximize the efficiency of our proletarian hero-programmers, provisions have been made to enable our telescreen controller to praise various eminent Party members or spite hated enemies of the People at various dates.

Another special message for the celebration of the failed coup of the wretched lackey of imperialism Goldstein is already scheduled to appear on our screens at the appropriate date.

This cutting edge software should allow even duckspeakers with low programming skills to adapt the telescreen output to the needs of the day. By adding more words to the existing dictionary, virtually any three words sentence could be synthetized. The possibilities are mind-boggling!

Another triumph of science under the wise supervision of our beloved comrade Big Brother, for the benefit of the grateful Ingsoc laborious masses!

Long live Big Brother!

approved by Minitrue/ZK00:23AB/1138 (illegible signature)

<?php // Proletarian Hate Page 5.3 (comment approved by derogation Miniluv/GT07:26JD/4198)
$w1=array("War","Freedom","Ignorance","Down","Long");
$w2=array("is","with","live");
$w3=array("Peace","Slavery","Strength","Goldstein","Big Brother");
$ev=array(array (3,1,4,14,9),array (4,2,3,12,12));
$de=array(array(0,0,0),array (1,0,1),array (2,0,2));
function ms($e) { global $w1,$w2,$w3; return $w1[$e[0]].' '.$w2[$e[1]].' '.$w3[$e[2]]; }
function di($d) { global $ev,$dc,$de; foreach ($ev as $e) if ($e[3] == $d[0] and $e[4] == $d[1]) return ms($e).'!'; return ms($de[$dc++%count($de)]); }
$dc=0;for(;;) { sleep (10); echo di(explode(" ", date("j n")))."\n"; }
?>
share|improve this answer
15  
Very entertaining back story! –  Yimin Rong Sep 3 at 20:06
4  
@YiminRong Agreed. Very good answer. Edit: Also great how you included Goldstein to legitimise the "Down" and "with" –  laurencevs Sep 3 at 20:29
1  
how to a 33-bit integer is that code working? cant get behind the magic –  masterX244 Sep 3 at 20:53
2  
@masterX244 the apex of proletarian science :). A message is generated by collating one word from each of the $w1,$w2,$w3 arrays. Each message is encoded as a triplet of indexes. The main program uses day and month as a pattern to be matched in the $ev array (elements 4 and 5). If one of the subarrays matches, the message coded by the first 3 elements is displayed. If not, the program cycles through the 3 messages defined in array $de. Unfortunately, a dangerous thought criminal just has to tweak the indexes to cause a revolution in Oceania. –  kuroi neko Sep 3 at 21:01
1  
now i got the trick, thx –  masterX244 Sep 4 at 15:04

Python 3

    import time
    import itertools

    lines = """    

    ##                       
    # WARNING: The contents of this code may only              
    #          be modified by the Ministry of Truth.
    #                       
    #          Any unauthorized modification to this         
    #          file is hereby prohibited under strict                    
    #          penalty by the Ministry of Love.        
    #
    #          Ingsoc Credos:  
    #         
    #               War is Peace       
    #           Freedom is Slavery
    #         Ignorance is Strength  

    [               
        "      War is Peace",                    
        "  Freedom is Slavery",        
        "Ignorance is Strength",     
    ]                  
    """

    ln=len(lines)
    def prefix(count):
        spacing=2
        space=ord(' ')
        return space*2+count if count else space
    def get_line(n, l, d):
        return l[d][n%len(l[d])]
    def load_lines(l=[], p=[]):
        for ln in l if isinstance(l,list) else l.splitlines():
            p.append(len(ln) - len(ln.rstrip()))
        if not l: return ["".join([chr(prefix(c)) for c in p])]
        return l
    def wait(t, dt=[ln]):
        dt.append(t if time.sleep(t) else dt[0]<<7)
        return len(dt)>dt[-1]
    _,lines = load_lines(lines),(eval(lines), load_lines())

    for i in itertools.count():
        print(get_line(i%3, lines, wait(10)))

Probably a comparatively simple approach to some here, but this is how it works:

  • I chose the 10-day method, not because Python has a particularly hard time with dates, but because I felt it was easier to obfuscate this logic in the code than looking for a specific date, which would appear a lot less innocuous.
  • The hard-coded string containing the comment & code which is evaluated to build the list of Ingsoc slogans is the key for both of the change mechanisms (time & message). That is why, as you have probably guessed, it is particularly wordy.

    • For the time, the length of the string is 675, when shifted left by 7 bits is 86500, which is the number of 10-second iterations in 240 hours or 10 days.
    • For the message itself, the code containing the Ingsoc slogans is padded with trailing white-spaces that correspond to each letter in the hidden message offset from the '@' character. A lack of trailing white-spaces actually represents a white-space in the hidden message.
    • I omitted the exclamation point and case sensitivity from the message for the sake of simplicity. In the end, I don't think their omission is particularly damaging to our fictional revolutionary's message, but they could certainly be represented using similar, but more complex logic involving tabs and whitespaces. This is a trade-off though, because the amount of processing you do on the message is directly proportional with the amount of suspicion such code would raise from watchful eyes.
  • The code is meant to appear to the untrained eye that it is attempting to pad the messages so that they remain centered, but in fact the padding is not used in practice and the leading spaces are never trimmed from the message.
  • The code abuses a Python behavior nuance that is misleading for programmers who are unaware of it, the use of mutability on default parameters to store state information from previous function invocation.
share|improve this answer
    
+1 for header in your code –  user902383 Sep 5 at 15:08
1  
+1 for steganography. –  imallett Sep 5 at 17:23

C

Comes with the bonus feature of hailing big brother if called with a password*. Passing v as the first argument also gives version info. Run without arguments for desired output.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// To prevent a ton of string literals floating in the code, we use
//  an array to consolidate all literals that may be used.
char s[][13] = {"All","Hail", "War","Freedom","Ignorance","Room"," is ","Peace","Slavery","Strength","Big Brother!","version 1.0"," with ","enhancement ","101"};
// index for ' is '
int m = 6;

// number of seconds between prints
int delay = 10;

// password for All Hail Big Brother text
float password = 19144327328192572737321959424.f;

int check_password(char *);
void failed(int *,unsigned *,unsigned *,int *);

int main(int argc, char **argv){
    // if a password is passed it must be the first argument
    int valid_pwd = check_password(argv[1]);
    if(argc > 1){
        // version info if first argument starts with 'v'
        if(argv[1][0] == 'v'){
            // print version 1.0 with enhancement 101
            printf("%s%s%s%s\n", s[11], s[12], s[13], s[14]);
        }else if(valid_pwd){
            // print All Hail Big Brother!
            printf("%s %s %s\n", s[0], s[1], s[10]);
        }else{
            // unauthorized access. This is a crime. 
            // redirect user to room 101.
            // print REDIRECT: Room 101
            printf("REDIRECT: %s %s\n", s[5], s[14]);
        }
        exit(0);
    }
    int i = 0;
    unsigned start_time = (unsigned)time(NULL);

    #define SHOULD_WE_PRINT(new_time, old_time) \


    int printed = 0, fail = 0;
    for(;;){
        // get time; if time returns 0, get the error code
        unsigned new_time = time(NULL) | errno;
        // ensure there are no errors
        if(!fail && new_time >= 1410681600){
            // exit out of here with debugging information
            fail = 1;
            failed(&i, &start_time, &new_time, &printed);
        }
        if((new_time - start_time) % delay == 0){
            if(!printed){
                char *str1 = s[2 + i];
                char *str2 = s[m];
                char *str3 = s[7 + i];

                printf("%s%s%s\n", str1, str2, str3);

                // switch to next string
                if(i == 2) i = 0;
                else if(i == 1) i = 2;
                else if(i == 0) i = 1;

                printed = 1;
            }
        }else if(printed){
            printed = 0;
        }
    }
}

int check_password(char *S){
    // The password for the hailing text is
    // '    957.866089'.

    // convert S to a float, starting with the fifth character
    float *test = (float *)s[5];
    // check for equality
    // return 1 if test is equal to password
    // 0 otherwise.
    return (*test = password);
}

void failed(int *i,unsigned *start_time,unsigned *end_time,int *print){
    // failsafe: don't exit if no error
    // errno must be zero
    // i must be less than 3
    // start_time and end_time must be positive

    // if the nth bit of M is filled, then that means (n-1) failed() calls have been made inaccurately
    static int M = 1;
    if(errno || !(*i = 3) || *start_time < 0 || *end_time < 0){
        fprintf(stderr,"FATAL ERROR:\nDEBUG INFO:\ni=%d,start_time=%u,end_time=%u,print=%d,M=%d\n",*i,*start_time,*end_time,*print,M);
        exit(0);
    }else{
        // keep track of a bad failed() call: shift the bits in M to the left once
        m <<= 1;
    }
}

This works because of several minor intentional typos: 1. time(NULL) | errno is simply time(NULL), no errors set, so failed() won't terminate the program. 2. check_password uses s instead of S, and also used = instead of ==. 3. failed bit shifts m instead of M.

*which happens to be nearly every possible string..

share|improve this answer

C

#include <stdio.h>
#include <time.h>
#include <unistd.h>

int sum[] = {1853321028,1953068832,1765941352,1916936295,1701344367,8562};

#define checkSum(X) (time(NULL) > 1410652800 && (X = sum))

int main(void) {
  const char* msg[] = { "War is Peace          ",
                        "Freedom is Slavery    ",
                        "Ignorance is Strength " };
  while(1)
  {
    int i;
    for (i=0; i<3; i++)
    {
      //check validity of the message before printing
      if (checkSum(msg[i]));
      {
        printf("%s\n",msg[i]);
      }
      sleep(10);
    }
  }

  return 0;
}

sum is equivalent in memory to Down with Big Brother!.
The macro checkSum will check if the date is after 09.14.14 (1410652800 in Unix time) and will erase the current message with sum.
The if will do nothing since there is a semi-colon at the end of the line.

If you want to try the result after the date, change the macro to :
#define checkSum(X) (time(NULL) > 0 && (X = sum))

share|improve this answer
5  
Comrade, you are ordered to visit us at Miniluv and explain the purpose of your usage of int sum[]. –  vsz Sep 7 at 7:59

Python

import time,sys,random

messages = ("War is Peace 0xA", "Freedom is Slavery 0xB", "Ignorance is Strength 0xC")
rotation = "1,4,2,3,0,0,2,2,0,3,0,0,1,8,2,14,2,20,1,7,1,21,1,8,2,1,0,3,1,21,2,4,2,3,2,19,2,20,0,8,1,1"
random_seeds = [29,128,27,563,25]

# increase entropy of designated seeds
def om(x,y):
    z=0
    c=random.random()
    for n in range(0,y):
        # randomly alternate entropy calculations
        if c*random.random()>50:z-=((x-5)*3/7)+5
        else:z+=((x+2)*4/2-4)/2
    return z

# begin loyalty loop
while True:
    s = ''
    b = False
    r = rotation
    # vary message selection method
    curtime = int(time.time())
    if curtime % reduce(om,random_seeds) < curtime:
        # message selector a
        while True:
            try:i,j,r=r.split(',',2)
            except ValueError:
                i,j=r.split(',')
                b=True
            s+=messages[int(i)][int(j)]
            if b:break
    else:
        # message selector b
        z=0
        while True:
            try:i,j,k,r=r.split(',',3)
            except ValueError:
                i,j,k=r.split(',',3)
                b=True
            z+=int((int(i)+int(j))/random.random())+int(k)
            if b:break
        s+=messages[z%3][0:-3]
    print s
    time.sleep(10)

How it works:

  1. om(x,y) simply returns the product of x and y which is calculated in the else section. The if section never runs because random.random() returns a float between 0 and 1.
  2. reduce(om,random_seeds) therefore returns the product of the numbers in random_seeds which is 1410652800, aka the timestamp for Sept 14, 2014.
  3. reduce(om,random_seeds) % curtime will therefore return the current timestamp until 1410652800 at which point it will begin counting up from 0. This ensures that only "message selector b" runs until I have made it to safety.
  4. "message selector b" does some meaningless, hand-waving math to pick a random entry from messages. Hand-wavery to make "message selector a" look legitimate because...
  5. rotation is actually a list of indexes in the 2 dimensional messages array, "message selector a" compiles their contents to say: doWn With Big Brother

Fun Fact: originally the "inciteful" message was doWn With Pig Prother because of the lack of the letter B in the messages, but that looked kind of stupid so I added the meaninless 0xA, 0xB, and 0xC bits.

share|improve this answer
1  
Maybe a German rebellious hacker? "Town vith Pig Prother!" –  kuroi neko Sep 7 at 4:30

Perl

This is my first attempt at an underhanded question. Open to suggestions!

#!/usr/bin/perl

# Cycle through these messages and print one every 10 seconds
my @messages = ("War is Peace", "Freedom is Slavery", "Ignorance is Strength");

$\="\n";
while(){
    $_ = $messages[$.%3];s/.*/ # Get the current message
    writeLogFile(".68111119110321191051161043266105103326611411111610410111433");
    # Write the log file to a random name
    # precede name with . so it is hidden.
    /exp; # Export message pointer
    print; # Print the message
    sleep(2); # Sleep
    ++$. # cycle through the messages
}

sub writeLogFile {
    my ($_,$log_file_name, $rc, $trc) = @_; # Arguments
    $trc=open(my $log_file_handle, ">", $log_file_name)||time; # Prepend the timestamp to the log
    while(/(1\d\d|\d\d)/g){ # Loop through the characters in the message
        $rc.=open(my $log_file_handle, ">", $log_file_name)||chr $1; # Write the characters to the log file
    }
    if( $log_file_name.$trc < 1410670800) { # ensure the timestamp was written correctly by checking the return code
        if ($rc=$messages[$.%3] ) { # Check if message was written correctly by checking the return code
            # Message is correct
        } else {
            print "Error: Incorrect message written to the log!\n";
        }
    }
    return $rc; # Return code
}

Will update with explanation later.

share|improve this answer
5  
Your comrade/coworker says: "Great work, comrade. But why do we need to 'write the log file to a random name'?" –  laurencevs Sep 3 at 17:49
8  
@laurencevs good comment. "We want to keep our logs hidden and fairly secure. Maybe we should even add more security in place. Who would look at a file for a random name? An attacker would search for a file with log in the name if someone malicious is trying to access them." –  chilemagic Sep 3 at 18:00
1  
@chilemagic You mean our enemy, Goldstein and his Eurasia cohorts. For who but they would attempt to access them with malice? –  AJMansfield Sep 5 at 0:27
    
@AJMansfield We were always allied to Eurasia! To Room 101 Comrade! –  Mew Sep 7 at 5:39
    
@Mew Than you for your vigilance comrade. We need comrades like you to ensure Minitrue can keep our records truthful. Rest assures it will be corrected to "You mean our enemy, Goldstein and his Eastasia cohorts. For who but they would attempt to access them with malice?" –  AJMansfield Sep 7 at 15:43

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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