22
\$\begingroup\$

Thanks for all the entries, the deadline has now passed and the final scores are at the end of the question.
Congratulations to PhiNotPi on a fairly comprehensive victory.

This is a challenge, the aim of which is to create a program which wins more often than any of its opponents in a lowest unique bid auction.

Input

As input the program will receive all the previous rounds' bidding, one round per line, all bids separated by spaces as follows:

10 4 12 11 12 4 7 3 3
1 2 9 15 1 15 15 9 3
3 21 6 4 3 8 6 13 1

Each column of the input represents the bidding of one bot. The first column is the receiving program's bids, while the rest are in a randomly generated order. Thanks to hammar and Peter Taylor for their input.

Input is provided as the one and only command-line (multi-line) argument to your program:

./test1 '1 2
3 4
5 6
1 2'

This means that your program will need to be runnable from the command-line. Please give an example of invocation as part of your answer.

In the first round only as a means of letting you know how many bots you're up against, the input will be a line of 0s - one for each bot.

Output

Your program should output its bid as an integer in the range 1 to 100 (inclusive).

Scorer Program

This is my scoring program - any suggestions for additions, improvements or bug fixes would be welcomed.

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

#define NUMROUNDS 10
#define NUMBOTS 4
#define MAXINPUTSIZE 10000
#define MAXFILENAMESIZE 100

int main()
{
    int i,j,a,b,winner;
    FILE *fp;
    char bots[NUMBOTS][MAXFILENAMESIZE]={"onesconfident","random100","random20","random5"};
    char openstring[MAXFILENAMESIZE+MAXINPUTSIZE+3];
    char input[MAXINPUTSIZE];
    char buff[5];
    int shuffle[NUMBOTS],auction[100],lowestbid[NUMBOTS]={[0 ... NUMBOTS-1]=101};
    static int guesses[NUMBOTS][NUMROUNDS];
    static int scores[NUMBOTS],totalwinbids[NUMBOTS];

    srand(time(NULL));

    for(i=0;i<NUMROUNDS;i++)
    {
        /*blank the auction bids for the next round */
        for(a=0;a<100;a++)
        {
            auction[a]=9999;
        }

        /*loop through the bots sending the input and storing their output */
        for(j=0;j<NUMBOTS;j++)
        {
            /*Fisher-Yates shuffle */
            for(b=0;b<NUMBOTS;b++)
            {
                shuffle[b]=(b+j)%NUMBOTS;/*put current bot at index 0 */
            }
            for(b=NUMBOTS-1;b>1;b--)
            {
                int z=rand()%(b-1)+1;/*make sure shuffle leaves index 0 alone */
                int t=shuffle[b];
                shuffle[b]=shuffle[z];
                shuffle[z]=t;
            }

            /*generate the input for the bots */
            strcpy(input,"'");
            if(i==0)
            {
                for(b=0;b<NUMBOTS;b++)
                {
                    if(b!=0)
                        sprintf(input,"%s 0",input);
                    else
                        sprintf(input,"%s0",input);
                }
            }
            else
            {
                for(a=0;a<i;a++)
                {
                    for(b=0;b<NUMBOTS;b++)
                    {
                        if(b!=0)
                            sprintf(input,"%s %d",input,guesses[shuffle[b]][a]);
                        else
                            sprintf(input,"%s%d",input,guesses[shuffle[b]][a]);
                    }
                    if(a!=i-1)
                        strcat(input,"\n");
                }
            }
            strcat(input,"'");

            sprintf(openstring,"%s %s",bots[j],input);
            fp=popen(openstring,"r");

            fgets(buff,3,fp);
            fflush(NULL);
            pclose(fp);
            guesses[j][i]=atoi(buff);

            /*add the bid to the auction, eliminating any duplicates */
            if(auction[atoi(buff)-1]!=9999)
                auction[atoi(buff)-1]=9998;
            else
                auction[atoi(buff)-1]=j;
        }

        winner=9999;
        /*add one to the score of the winning bot */
        for(a=0;a<100;a++)
        {
            if(auction[a]!=9998 && auction[a]!=9999)
            {
                winner=auction[a];
                scores[winner]+=1;
                totalwinbids[winner]+=guesses[winner][i];
                if(guesses[winner][i]<lowestbid[winner])
                    lowestbid[winner]=guesses[winner][i];
                break;
            }
        }

        /*output this round's bids and the winning bot's name */
        strcpy(input,"");
        for(b=0;b<NUMBOTS;b++)
        {
            if(strcmp(input,"")!=0)
                sprintf(input,"%s %d",input,guesses[b][i]);
            else
                sprintf(input,"%d",guesses[b][i]);
        }
        if(winner!=9999)
            printf("%s %s\n",input,bots[winner]);
        else
            printf("%s No winner\n",input);
    }

    /*output final scores */
    printf("\nResults:\n");
    printf("Bot\tScore\tTotal\tLowest\n");
    for(a=0;a<NUMBOTS;a++)
    {
        printf("%s\t%d\t%d\t%d\n",bots[a],scores[a],totalwinbids[a],lowestbid[a]);
    }

    return 0;
}

Test players

One's confident Always bids 1.

#include <stdio.h>

int main()
{
    printf("1");
    return 0;
}

Random100 Bids at random over the entire range

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

int main()
{
    srand(getpid());
    printf("%d",rand()%100+1);
    return 0;
}

Random20 Bids at random between 1 and 20

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

int main()
{
    srand(getpid());
    printf("%d",rand()%20+1);
    return 0;
}

Random5 Bids at random between 1 and 5

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

int main()
{
    srand(getpid());
    printf("%d",rand()%5+1);
    return 0;
}

Example run-through:

1 38 5 2 onesconfident
1 66 13 5 onesconfident
1 94 1 3 random5
1 22 9 1 random20
1 50 17 4 onesconfident
1 78 5 2 onesconfident
1 6 13 5 onesconfident
1 34 1 3 random5
1 62 9 1 random20
1 90 17 4 onesconfident

Results:
Bot Score   Total   Lowest
onesconfident   6   6   1
random100   0   0   101
random20    2   18  9
random5 2   6   3

These players are for testing purposes only. They will NOT be included in the competition. You can enter as many bots as you wish, so if anyone does enter a bot that only guesses 1, you can enter another that does the same to render it useless.

Winner

The winning bot in each round is the one which gives the lowest unique bid. So given a round in which the following bids are made: 1 1 3 5 2 3 6 3 2 8 7 the winner would be the bot that bid 5 because the 1s, 2s and 3s are not unique.

The winner of the competition will be the program which wins the most times after 100 rounds. In case of a tie the total of the winning bids will be used as a tie-breaker, and in the event of that also being a tie, the lowest winning bid will be used as a further tie-breaker. These scoring factors are all output by the scoring program.

I will run the scoring program on all working programs that have been entered 2 weeks from today (18th February now extended to 11pm(GMT) on the 20th of February). I'll upvote all working entries and accept the winner of my scoring run.

Final scoring run

1 9 3 2 1 6 4 3 6 8 7 10 26 6 10 5 26 2 5 8 8 5 7 6 42 1 ./phinotpi2
1 11 4 2 1 4 9 20 6 8 7 6 26 4 8 4 26 2 5 8 8 5 7 7 42 1 ./phinotpi2
1 7 9 2 1 4 3 20 6 8 7 6 7 4 8 9 26 2 5 8 8 5 4 9 42 3 node minitech1.js
1 13 20 2 1 3 3 20 6 8 7 7 9 6 8 20 26 2 5 8 8 5 9 9 42 3 ./dirichlet
1 12 13 2 1 1 3 20 6 8 7 7 9 6 9 13 26 2 5 8 8 5 20 9 42 3 ./dirichlet
1 2 4 2 1 1 3 20 6 8 7 7 9 6 9 12 26 2 5 8 8 5 13 9 42 3 python blazer1.py
1 11 4 2 1 4 3 20 6 8 7 6 7 4 8 4 26 2 5 8 8 5 12 9 42 3 ./celtschk
1 3 4 2 1 1 3 20 6 8 7 6 7 4 8 9 26 2 5 8 8 5 4 9 42 3 node minitech1.js
1 7 4 2 1 1 3 20 6 8 7 9 26 6 7 20 26 2 5 8 8 5 9 9 42 10 ./phinotpi2
1 9 9 2 1 3 4 20 6 8 7 6 7 3 9 3 26 2 5 8 8 5 20 9 42 10 ./phinotpi2
1 13 4 2 1 3 9 20 6 8 7 4 6 3 8 4 26 2 5 8 8 5 3 9 42 10 scala Schwarzenbeck
1 12 20 2 1 1 3 20 6 8 7 6 20 4 8 7 26 2 5 8 8 5 4 9 42 10 ./phinotpi2
1 10 3 2 1 2 4 20 6 8 7 6 9 3 9 3 26 2 5 8 8 5 7 9 42 10 ./phinotpi2
1 6 9 2 1 4 9 20 6 8 7 4 6 3 8 4 26 2 5 8 8 5 3 9 42 10 scala Schwarzenbeck
1 8 4 2 1 3 3 20 6 8 7 6 20 4 8 7 26 2 5 8 8 5 4 9 42 10 ./celtschk
1 2 13 2 1 3 3 20 6 8 7 9 20 6 8 9 26 2 5 8 8 5 7 9 42 10 ruby1.9 strategist.rb
1 2 4 2 1 3 3 20 6 8 7 7 10 6 9 10 26 2 5 8 8 5 9 9 42 10 python blazer1.py
1 3 13 2 1 4 3 20 6 8 7 6 7 4 8 4 26 2 5 8 8 5 10 9 42 10 ./celtschk
1 4 4 2 1 3 3 20 6 8 7 6 7 4 8 9 26 2 5 8 8 5 4 9 42 10 ruby1.9 strategist.rb
1 4 9 2 1 4 3 20 6 8 7 7 9 6 8 10 26 2 5 8 8 5 9 9 42 10 ./phinotpi2
1 11 7 2 1 1 4 20 6 8 7 6 7 3 8 3 26 2 5 8 8 5 10 9 42 10 ./phinotpi2
1 6 4 2 1 3 9 20 6 8 7 4 6 3 8 4 26 2 5 8 8 5 3 9 42 10 scala Schwarzenbeck
1 13 7 2 1 1 3 20 6 8 7 6 20 4 8 7 26 2 5 8 8 5 4 9 42 10 ./phinotpi2
1 7 4 2 1 4 4 20 6 8 7 6 20 3 8 3 26 2 5 8 8 5 7 9 42 10 ./celtschk
1 13 3 2 1 1 4 20 6 8 7 6 7 3 8 9 26 2 5 8 8 5 3 9 42 10 ./phinotpi2
1 3 4 2 1 3 3 20 6 8 7 6 7 4 8 4 26 2 5 8 8 5 9 9 42 10 ruby1.9 strategist.rb
1 5 4 2 1 2 3 20 6 8 7 6 7 4 8 10 26 2 5 8 8 5 4 9 42 10 ./phinotpi2
1 6 3 2 1 3 4 20 6 8 7 6 7 3 8 3 26 2 5 8 8 5 10 9 42 10 ./phinotpi2
1 10 20 2 1 1 9 20 6 8 7 4 6 3 8 4 26 2 5 8 8 5 3 9 42 10 scala Schwarzenbeck
1 10 3 2 1 4 3 20 6 8 7 6 20 4 8 7 26 2 5 8 8 5 4 9 42 10 ./celtschk
1 12 4 2 1 1 3 20 6 8 7 9 20 6 8 9 26 2 5 8 8 5 7 9 42 10 ./phinotpi2
1 5 3 2 1 1 4 20 6 8 7 6 7 3 9 3 26 2 5 8 8 5 9 9 42 10 ./phinotpi2
1 13 3 2 1 4 9 20 6 8 7 4 6 3 8 4 26 2 5 8 8 5 3 9 42 10 scala Schwarzenbeck
1 6 9 2 1 4 3 20 6 8 7 6 20 4 8 7 26 2 5 8 8 5 4 9 42 10 ./phinotpi2
1 5 4 2 1 2 4 20 6 8 7 6 20 3 8 3 26 2 5 8 8 5 7 9 42 10 ./celtschk
1 12 3 2 1 3 4 20 6 8 7 6 7 3 8 9 26 2 5 8 8 5 3 9 42 10 ./phinotpi2
1 10 7 2 1 2 3 20 6 8 7 6 7 4 8 4 26 2 5 8 8 5 9 9 42 10 ./phinotpi2
1 9 10 2 1 4 9 20 6 8 7 4 6 3 8 3 26 2 5 8 8 5 4 9 42 10 scala Schwarzenbeck
1 9 20 2 1 4 4 20 6 8 7 6 20 3 8 7 26 2 5 8 8 5 3 9 42 10 ruby1.9 strategist.rb
1 6 3 2 1 3 3 20 6 8 7 9 10 6 9 10 26 2 5 8 8 5 7 9 42 10 node minitech1.js
1 13 3 2 1 3 3 20 6 8 7 7 10 6 8 20 26 2 5 8 8 5 10 9 42 11 ./celtschk
1 3 3 2 1 1 3 20 6 8 7 7 26 6 9 9 26 2 5 8 8 5 20 9 42 11 ruby1.9 strategist.rb
1 5 20 2 1 2 3 20 6 8 7 7 11 6 9 11 26 2 5 8 8 5 9 9 42 11 ./phinotpi2
1 7 3 2 1 4 4 20 6 8 7 6 7 3 9 3 26 2 5 8 8 5 11 9 42 11 node minitech1.js
1 7 3 2 1 1 4 20 6 8 7 6 7 3 8 20 26 2 5 8 8 5 3 9 42 10 ./phinotpi2
1 8 4 2 1 4 3 20 6 8 7 6 7 4 8 4 26 2 5 8 8 5 20 9 42 10 ./phinotpi2
1 2 3 2 1 3 9 20 6 8 7 4 6 3 8 3 26 2 5 8 8 5 4 9 42 10 scala Schwarzenbeck
1 4 13 2 1 3 4 20 6 8 7 6 20 3 7 7 26 2 5 8 8 5 3 9 42 10 ./celtschk
1 8 3 2 1 3 3 20 6 8 7 9 20 6 8 9 26 2 5 8 8 5 7 9 42 10 ruby1.9 strategist.rb
1 9 10 2 1 2 3 20 6 8 7 7 10 6 9 10 26 2 5 8 8 5 9 9 42 10 ./phinotpi2
1 10 20 2 1 1 4 20 6 8 7 6 7 3 9 3 26 2 5 8 8 5 10 9 42 10 ./phinotpi2
1 9 4 2 1 1 9 20 6 8 7 4 6 3 8 4 26 2 5 8 8 5 3 9 42 10 scala Schwarzenbeck
1 11 20 2 1 4 3 20 6 8 7 6 20 4 8 7 26 2 5 8 8 5 4 9 42 10 ./phinotpi2
1 4 9 2 1 3 4 20 6 8 7 6 9 3 9 3 26 2 5 8 8 5 7 9 42 10 ruby1.9 strategist.rb
1 5 3 2 1 4 4 20 6 8 7 6 7 3 8 10 26 2 5 8 8 5 3 9 42 10 ./celtschk
1 7 4 2 1 3 3 20 6 8 7 7 9 6 8 9 26 2 5 8 8 5 10 9 42 10 python blazer1.py
1 4 9 2 1 1 3 20 6 8 7 6 7 4 8 4 26 2 5 8 8 5 9 9 42 10 ./phinotpi2
1 8 4 2 1 3 9 20 6 8 7 4 6 3 8 3 26 2 5 8 8 5 4 9 42 10 scala Schwarzenbeck
1 10 9 2 1 3 4 20 6 8 7 6 20 3 8 7 26 2 5 8 8 5 3 9 42 10 ./phinotpi2
1 4 20 2 1 1 3 20 6 8 7 6 20 4 8 4 26 2 5 8 8 5 7 9 42 10 ./phinotpi2
1 5 3 2 1 2 9 20 6 8 7 4 6 3 9 3 26 2 5 8 8 5 4 9 42 10 scala Schwarzenbeck
1 2 4 2 1 1 4 20 6 8 7 6 20 3 8 7 26 2 5 8 8 5 3 9 42 10 ./celtschk
1 10 12 2 1 1 3 20 6 8 7 9 20 6 8 9 26 2 5 8 8 5 7 9 42 10 ./phinotpi2
1 9 4 2 1 4 4 20 6 8 7 6 7 3 9 3 26 2 5 8 8 5 9 9 42 10 ruby1.9 strategist.rb
1 11 3 2 1 3 4 20 6 8 7 6 7 3 8 10 26 2 5 8 8 5 3 9 42 10 ./phinotpi2
1 8 4 2 1 1 3 20 6 8 7 6 7 4 8 4 26 2 5 8 8 5 10 9 42 10 ./phinotpi2
1 13 9 2 1 4 9 20 6 8 7 4 6 3 8 3 26 2 5 8 8 5 4 9 42 10 scala Schwarzenbeck
1 2 9 2 1 3 4 20 6 8 7 6 20 3 8 7 26 2 5 8 8 5 3 9 42 10 ./phinotpi2
1 8 3 2 1 2 3 20 6 8 7 6 20 4 8 4 26 2 5 8 8 5 7 9 42 10 ./celtschk
1 3 3 2 1 4 3 20 6 8 7 6 7 4 8 9 26 2 5 8 8 5 4 9 42 10 ruby1.9 strategist.rb
1 10 4 2 1 1 3 20 6 8 7 7 9 6 8 10 26 2 5 8 8 5 9 9 42 10 ./phinotpi2
1 3 9 2 1 4 4 20 6 8 7 6 7 3 8 3 26 2 5 8 8 5 10 9 42 10 node minitech1.js
1 7 11 2 1 4 4 20 6 8 7 6 7 3 8 20 26 2 5 8 8 5 3 9 42 10 ./celtschk
1 8 3 2 1 2 3 20 6 8 7 7 9 6 8 9 26 2 5 8 8 5 20 9 42 10 ruby1.9 strategist.rb
1 3 10 2 1 3 3 20 6 8 7 7 10 6 9 10 26 2 5 8 8 5 9 9 42 10 node minitech1.js
1 8 4 2 1 1 3 20 6 8 7 7 10 6 8 20 26 2 5 8 8 5 10 9 42 11 ./phinotpi2
1 2 4 2 1 2 4 20 6 8 7 6 7 3 9 3 26 2 5 8 8 5 20 9 42 11 ruby1.9 strategist.rb
1 4 9 2 1 4 4 20 6 8 7 6 7 3 8 11 26 2 5 8 8 5 3 9 42 11 node minitech1.js
1 4 9 2 1 1 3 20 6 8 7 7 11 6 8 20 26 2 5 8 8 5 11 9 42 10 ./phinotpi2
1 2 7 2 1 1 4 20 6 8 7 6 7 3 9 3 26 2 5 8 8 5 20 9 42 10 ./phinotpi2
1 9 3 2 1 1 9 20 6 8 7 4 6 3 8 4 26 2 5 8 8 5 3 9 42 10 scala Schwarzenbeck
1 3 9 2 1 2 3 20 6 8 7 6 20 4 8 7 26 2 5 8 8 5 4 9 42 10 ruby1.9 strategist.rb
1 5 7 2 1 3 3 20 6 8 7 10 20 6 8 10 26 2 5 8 8 5 7 9 42 10 ./celtschk
1 8 10 2 1 4 3 20 6 8 7 7 10 6 9 9 26 2 5 8 8 5 10 9 42 10 ./phinotpi2
1 5 4 2 1 4 4 20 6 8 7 6 7 3 9 3 26 2 5 8 8 5 9 9 42 10 ruby1.9 strategist.rb
1 5 20 2 1 3 4 20 6 8 7 6 7 3 8 10 26 2 5 8 8 5 3 9 42 10 ./phinotpi2
1 11 20 2 1 2 3 20 6 8 7 6 7 4 8 4 26 2 5 8 8 5 10 9 42 10 ./phinotpi2
1 12 10 2 1 1 9 20 6 8 7 4 6 3 9 3 26 2 5 8 8 5 4 9 42 10 scala Schwarzenbeck
1 10 3 2 1 1 4 20 6 8 7 6 20 3 8 7 26 2 5 8 8 5 3 9 42 10 ./phinotpi2
1 9 4 2 1 4 3 20 6 8 7 6 20 4 8 4 26 2 5 8 8 5 7 9 42 10 ./phinotpi2
1 5 3 2 1 1 9 20 6 8 7 4 6 3 8 3 26 2 5 8 8 5 4 9 42 10 scala Schwarzenbeck
1 7 4 2 1 1 4 20 6 8 7 6 20 3 7 7 26 2 5 8 8 5 3 9 42 10 ./celtschk
1 11 7 2 1 3 3 20 6 8 7 9 20 6 8 9 26 2 5 8 8 5 7 9 42 10 ruby1.9 strategist.rb
1 13 10 2 1 1 3 20 6 8 7 7 10 6 9 10 26 2 5 8 8 5 9 9 42 10 ./phinotpi2
1 9 9 2 1 1 4 20 6 8 7 6 7 3 9 3 26 2 5 8 8 5 10 9 42 10 ./phinotpi2
1 7 9 2 1 3 9 20 6 8 7 4 6 3 8 4 26 2 5 8 8 5 3 9 42 10 ruby1.9 strategist.rb
1 13 7 2 1 4 3 20 6 8 7 6 7 4 8 10 26 2 5 8 8 5 4 9 42 10 ./phinotpi2
1 8 7 2 1 1 4 20 6 8 7 6 7 3 8 3 26 2 5 8 8 5 10 9 42 10 ./phinotpi2
1 12 3 2 1 1 9 20 6 8 7 4 6 3 8 4 26 2 5 8 8 5 3 9 42 10 scala Schwarzenbeck
1 13 7 2 1 2 3 20 6 8 7 6 20 4 8 7 26 2 5 8 8 5 4 9 42 10 ./phinotpi2

Results:
Bot                 Score   Total   Lowest
perl phinotpi1.pl           0   0   101
./dirichlet                 2   25  12
python blazer1.py           3   12  4
perl chef.pl ilmari2.chef   0   0   101
./brainfuck ilmari1.bf      0   0   101
./christophe1               0   0   101
./phinotpi2                 44  156 3
node minitech1.js           7   140 20
scala Mueller               0   0   101
scala Beckenbauer           0   0   101
scala Schwarzenbeck         15  105 7
./alice                     0   0   101
./bob                       0   0   101
./eve                       0   0   101
python joe.py               0   0   101
python copycat.py           0   0   101
python totalbots.py         0   0   101
perl healthinspector.pl     0   0   101
./mellamokb1                0   0   101
./mellamokb2                0   0   101
php eightscancel.php        0   0   101
php fivescancel.php         0   0   101
python copycat2.py          0   0   101
./celtschk                  14  126 9
./deepthought               0   0   101
ruby1.9 strategist.rb       15  152 10
\$\endgroup\$
36
  • 1
    \$\begingroup\$ Hmm... with the rules written as they are, I could really spoil the game by entering 100 programs that each always bid a given number. \$\endgroup\$ Feb 4, 2012 at 2:23
  • 1
    \$\begingroup\$ Can you say two sentences, how the winning bot is chosen? I don't get it. \$\endgroup\$ Feb 4, 2012 at 5:15
  • \$\begingroup\$ @IlmariKaronen That's true, you could. But I'm trusting that people won't do that. I could limit the number of entries per person I suppose, but I think I'll only resort to that if any spoilers do come along. \$\endgroup\$
    – Gareth
    Feb 4, 2012 at 9:39
  • \$\begingroup\$ @userunknown I've tried to clarify how the auctions rounds work. \$\endgroup\$
    – Gareth
    Feb 4, 2012 at 9:45
  • 1
    \$\begingroup\$ @PhiNotPi: Don't feel guilty. You won within the rules. \$\endgroup\$ Feb 21, 2012 at 17:03

26 Answers 26

9
\$\begingroup\$

Perl

I tried a little harder this time. It's a really simple complex strategy, but I've set up the framework for expansion.

Edit: Complete redo. This thing is in it for the win.

    sub prob{
$_[0]+$_[1]-$_[0]*$_[1]
}

$_=<>;
INPUT:{

tr/ /,/;
@in = eval;
for(1..$#in){
 $bids[$rnum][$in[$_]]++
}
for(0..$#in){
 $tbids[$rnum][$in[$_]]++
}
$rnum++;
$_=<>;
if($_ ne"\n"){redo INPUT}
}

for(0..100){$pre[$_]=0}

dirichlet: for(2..$#in/2+2){    #rough approximation, 
$pre[$_]=prob($pre[$_], 1/int($#in/2+1))
}

CDP:{
    @cdps1=(1,1,1,2,2,3,3,4);
    @cdps2=(-2,-1,0,1,1,2,2,3,3);
    for($a=0;$a<8;$a++){
    for($b=0;$b<9;$b++){
     $sum=$cdps1[$a]+$cdps2[$b];
     if($sum<1){$sum=1};
     $pre[$sum] = prob($pre[$sum], 1/72);
    }
    }
}

blazer: {
for($r=1;$r<$rnum;$r++){
winner: for($pnt=1;$pnt<101;$pnt++){
        if($tbids[$r][$pnt] == 1){
            if($pnt > 2){
                $winnum[$pnt]++;
            $wins++;
            }
        last winner
        }
}
    }
    if($wins==0){
    $pre[3]=prob($pre[3], 1);last blazer
    }
    for(1..100){
    $pre[$_]=prob($pre[$_], $winnum[$_]/$wins);
    }
}

CC1: for($pnt=1;$pnt<101;$pnt++){
    if($tbids[$rnum-1][$pnt] == 1){
        $pre[$pnt] = prob($pre[$pnt], 1);last CC1
    }
    if($pnt==100){
        for($pnt2=1;$pnt2<100;$pnt2++){
        $pre[$pnt2] = prob($pre[$pnt2], $tbids[$rnum-1][$pnt2]/($#in+1));
    }
    }
}

CC2: for($pnt=1;$pnt<101;$pnt++){
    if($rnum-2<0){$pre[7] = prob($pre[7], 1);last CC2}
    if($tbids[$rnum-2][$pnt] == 1){
        $pre[$pnt] = prob($pre[$pnt], 1);last CC2
    }
    if($pnt==100){
        $pre[7] = prob($pre[7], 1);last CC2
    }
}

one: {
$pre[1] = prob($pre[1], 1);
}

two: {
$pre[2] = prob($pre[2], 1);
}

five: {
$pre[5] = prob($pre[5], 1);
}

eight: {
$pre[8] = prob($pre[8], 1);
}

fortytwo: {
$pre[42] = prob($pre[42], 1);
}

mueller: {
    $a=($#in+2)/4;
    $pre[int$a]=prob($pre[int$a], 1)
}

schwarzenbeck: {
    $a=($#in+2)/4+1;
    $pre[int$a]=prob($pre[int$a], 1)
}

beckenbauer: {
    $a=($#in+2)/4+2;
    $pre[int$a]=prob($pre[int$a], 1)
}

totalbots: {
    $pre[$#in+1]=prob($pre[$#in+1], 1)
}

joe: {
$sum=0;
    for(1..100){
    $sum+=$tbids[$rnum-1][$_];
}
    $average=$sum/($#in+1);
    if($average==0){$average=10};
    $pre[$average]=prob($pre[$average], 1);
}

node: {
$max=0;$maxloc=0;
for(1..100){
    if($tbids[$rnum-1][$_]>$max){$max=$tbids[$rnum-1][$_];$maxloc=$_}
}
$maxloc--;
#if($maxloc==0){
$maxloc=20;
#}
if($rnum==1){$maxloc=3}
    $pre[$maxloc]=prob($pre[$maxloc], 1);
}
#print"\n@pre\n\n";

decide: for(1..100){if($pre[$_]<0.5){print; last decide}}

This program takes input one line at a time, followed by two newlines:

perl PhiNotPi2.plx
1 2 3 3 2
2 1 3 1 3
2 1 1 1 3
[empty line]
\$\endgroup\$
5
  • \$\begingroup\$ Ok, this takes metagaming to extremes. \$\endgroup\$ Feb 19, 2012 at 23:19
  • \$\begingroup\$ @petertaylor Am I going too far out of line? Should I revert to my original? \$\endgroup\$
    – PhiNotPi
    Feb 20, 2012 at 0:59
  • 2
    \$\begingroup\$ This is a site notorious for rules lawyers - it's perfectly fair. But I am coming to the conclusion that the stack exchange mechanism might not be the best one for king-of-the-hill competitions. \$\endgroup\$ Feb 20, 2012 at 8:27
  • \$\begingroup\$ I have also come to that conclusion. We need to create a method of hiding the bots from view in future competitions. For all I know, someone is metagaming against my bots right now. \$\endgroup\$
    – PhiNotPi
    Feb 20, 2012 at 12:48
  • \$\begingroup\$ Lol, this was my idea :P. Since you have already implemented, and I'm feeling lazy, I'll let you have it :) Note that the only kind of entry that this cannot easily beat are ones that implement randomness \$\endgroup\$
    – mellamokb
    Feb 20, 2012 at 16:16
8
\$\begingroup\$

Chef

Since always betting 1 is now a losing strategy, the obvious thing to do is to always bet 2 instead. So let me do that. To make this otherwise boring entry a little more interesting, I decided to write it in Chef:

Shirred Eggs.

This recipe prints the number 2 and, in doing so, yields two delicious
shirred eggs.

Ingredients.
2 eggs

Cooking time: 12 minutes.

Pre-heat oven to 175 degrees Celsius.

Method.
Put eggs into mixing bowl. Pour contents of the mixing bowl into the
baking dish. Shirr the eggs. Bake the eggs until shirred.

Serves 1.

As a bonus, the program actually more or less works as a real — if trivial — recipe, even if it does kind of read as if the writer was a bit, um, baked. The Chef grammar seems to make it pretty hard to write anything that involves something more complicated than mixing stuff in a bowl and baking it and still have it work both as a program and as a recipe, especially if any of the verbs one wants to use are even slightly irregular (like "fry" → "fried").

Edit: Changed the recipe from fried to shirred eggs — thanks to Blazer for the suggestion! The cooking time and temperature should be considered advisory only; I haven't actually tried the recipe yet myself, so I can't vouch for their accuracy.

\$\endgroup\$
6
  • \$\begingroup\$ I think this outputs 1: see my comment at codegolf.stackexchange.com/a/4851. \$\endgroup\$
    – msh210
    Feb 6, 2012 at 19:05
  • \$\begingroup\$ It outputs 2, at least using the Acme::Chef interpreter. The final loop is there just for obfuscation, and so that the diners won't have to eat the eggs raw. \$\endgroup\$ Feb 6, 2012 at 19:17
  • \$\begingroup\$ Ah, right, I missed the fact that the eggs were already in the baking dish and that that's not what's decremented. \$\endgroup\$
    – msh210
    Feb 6, 2012 at 19:21
  • 2
    \$\begingroup\$ You call it shirred eggs, which is actually done in a baking dish and that would make the recipe an actual valid cooking recipe and grammatically correct. shirr the eggs. shirr the eggs until shirred. horray for having culinary education under my belt! :) \$\endgroup\$
    – Blazer
    Feb 8, 2012 at 4:06
  • 1
    \$\begingroup\$ the cooking time/temperature seems about right :). of course, always use those as guidelines only, as it is the chef who determines whether something is done or not, not time/temperature itself! \$\endgroup\$
    – Blazer
    Feb 8, 2012 at 23:34
4
\$\begingroup\$

Python (2.6)

Extremely simple, but still I'm curious how it will perform compared to the other approaches.

import sys, random
try:
    s = sys.stdin.readlines()[-2]
    m = min(int(x) for x in s.split())
except IndexError:
    m = random.choice([1,1,1,2,2,3,3,4])
a = random.choice([-2,-1,0,1,1,2,2,3,3])
print max(m + a, 1)

Just pipe in the bids via stdin, e.g. python testbid.py < bids.txt.

EDIT: changed for the 'first round all zeros'

EDIT: changed the 'magic numbers' a bit (a second time)

\$\endgroup\$
3
  • 1
    \$\begingroup\$ shouldn't m = random.choice(1,2,2,3,3,3) be m = random.choice([1,2,2,3,3,3])? \$\endgroup\$
    – Blazer
    Feb 7, 2012 at 6:37
  • \$\begingroup\$ It threw an error where Blazer said it might. I've put in the square brackets for the test run and it appears to have worked. \$\endgroup\$
    – Gareth
    Feb 7, 2012 at 21:19
  • \$\begingroup\$ @Blazer: yes, absolutely (small typo on my part). Thanks for notifying. \$\endgroup\$ Feb 7, 2012 at 23:28
4
\$\begingroup\$

Python (Blazer)

This bot analyzes the previous rounds and records the numbers that win. Winning numbers that appear more often will therefore have a better chance of getting picked. It will then randomly choose numbers from winning numbers (other than 1 or 2). it will choose 2 3 instead if it is the first round.

Input is read one line at a time. simply enter an empty line to stop accepting input

A trick is to just paste (it automatically accepts each line with \n within the paste) and hit enter twice

You may now just runt the script with a filename in the command line:

python bidding.py bidding.txt

file should look like this:

10 4 12 11 12 4 7 3 3
1 2 9 15 1 15 15 9 3
3 21 6 4 3 8 6 13 1

-

import random
import sys

winning = [] # record the winning numbers

content = sys.argv[1].split('\n')  
for each in content:
    x = map(int, each.split())
    if len(x)+sum(x) == 0: 
        continue 

    y = []
    for each in x:
        if x.count(each) == 1:
            y.append(each)
    if len(y) > 0: 
        if min(y) not in [1,2]:  #never choose 1 or 2
            winning.append(min(y))

# choose an output
if len(winning) == 0:
    print 3
else:
    print random.choice(winning)

edit: added or sum(rounds) == 0 to compensate for the recent first-round-all-zeros change

edit: problems in comments fixed, also made it able to receive input from a filename, and never chooses '2' anymore since competition has weeded that out as well. works with either all-0's as the starting input or no data in the file at all

edit2: forgot a min()

edit3: changed input to suit question's input needs

\$\endgroup\$
11
  • \$\begingroup\$ Causes a small problem with the scorer - I have to press enter to get the score for each round. Not much of a problem for my 10 round test runs, but could be a pain for the 100 round run. \$\endgroup\$
    – Gareth
    Feb 6, 2012 at 23:00
  • \$\begingroup\$ @Gareth, wrap it in a bash script. echo "$@" | python bidding.py should do the job. \$\endgroup\$ Feb 6, 2012 at 23:33
  • \$\begingroup\$ I've tried this as Peter suggested, but I'm getting an error TypeError: unsupported operand type(s) for +: 'int' and 'list' for line 23. I'm using Python 2.6.1, is that the problem? do I need a newer version? I get the same problem without using the bash script. \$\endgroup\$
    – Gareth
    Feb 7, 2012 at 20:30
  • \$\begingroup\$ @Gareth would it help if I made it so input is piped from sys.argv[1] with a filename? \$\endgroup\$
    – Blazer
    Feb 8, 2012 at 21:31
  • \$\begingroup\$ @Blazer I'm not sure that that's the problem. I'm calling the program from the command line myself using your example invocation and getting the error I gave above. Is there something in there that's incompatible with Python 2.6.1? \$\endgroup\$
    – Gareth
    Feb 8, 2012 at 21:40
3
\$\begingroup\$

Schwarzenbeck (Scala)

object Schwarzenbeck extends App {
  println ((args(0).split('\n')(0).split(' ').length+1)/4+1)
}

Schwarzenbeck isn't supposed to score the goals. He is the cleanup for Beckenbauer, which follows soon. :)

To use it, you need a compiler and compile it

scalac Schwarzenbeck.scala 

Then you can run it:

scala Schwarzenbeck 'your ar-
gu-
ment' 

Edit: Further adjustments.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Given that Schwarzenbeck was not supposed to score the goals, I'd say it utterly failed :-) \$\endgroup\$
    – celtschk
    Feb 21, 2012 at 8:05
  • \$\begingroup\$ Yes, I had a dilemma: I made a line of 3 players, and expected Müller to score the most points, but from a strategic position, Schwarzenbeck marked the ultimate defense line. The football metapher failed, since my defense line scored the goals. :) \$\endgroup\$ Feb 21, 2012 at 8:28
3
\$\begingroup\$

Strategist (Ruby )

Implements hundreds of simple strategies: for each round, picks the one which would have won the most previous rounds:

require 'Matrix'
def winner guesses
  g=guesses.sort
  while g[0]&&g[0]==g[1]
    g.shift while g[0]==g[1]
    g.shift
  end
  g[0]
end

def prob g
  prob=[0]*100;best=0;n=g.size*(g[0].size-1)
  g.each{|r|r[1..-1].each{|v|prob[v-1]+=1.0/n}};
  prob.map!{|v|v/n}
end    

def regression x, y, degree
  return y if x.size==1 
  x_data = x.map {|xi| (0..degree).map{|pow| (xi**pow.to_f) }}
  mx = Matrix[*x_data]
  my = Matrix.column_vector y
  begin
    r = ((mx.t * mx).inv * mx.t * my).transpose.to_a[0]
  rescue Exception => e
    r=[0]*degree;r[-1]=y[-1].to_f/(x[-1]**degree)
  end
  r
end

brains=((1..50).map{|w|[proc{|g|w},
    proc{|g|best=0;(p=prob g).each_with_index{|v,i|
      best=i if(v+i/100.0/w)<p[best]};best+1}]}+
  (1..7).map{|w|[proc{|g|p=1; if (g[1]) then h=g[1..-1];x=(1..h.size).to_a
      p=0;regression(x,h.map{|r|winner r},w).each_with_index{|v,i|
      p+=v*(g.size**i)};end;p.to_i},
    proc{|g|b=g[0].size/4;if g[1] then pred=[];h=g[1..-1]
      x=(1..h.size).to_a;h[0].size.times{|i|p=0
      regression(x,h.map{|r|r[i]},w).each_with_index{|v,i|p+=v*((x[-1]+1)**i)}
      pred<<[[p.to_i,1].max,100].min}
      (1..100).each{|i|if !pred.include?(i) then b=i;break;end};end;b}]}+
  (-1..1).map{|w|[proc{|g|r=g[0].size; if g.size>1 then
      f=g[1..-1].flatten;r=(f.inject{|s,v|s+v}/f.size.to_f+w).to_i;end;r},
    proc{|g|r=g[0].size/2; if g.size>1 then
      r=(g[1..-1].inject(0){|s,v|s+winner(v)}/(g.size.to_f-1)+w).to_i;end;r},
    proc{|g|(winner(g[-1])||9)+w}  ]}+
  [proc{|g|b=0;(p=prob g).each_with_index{|v,i|b=i if v<p[b]};b+1}]).flatten

games = ARGV[0].split("\n").map{|l|l.split.map{|v|v.to_i}}
winpct=[0]*brains.size
(games.size-1).times{|round|
  entries=games[round+1].dup
  brains.each_with_index{|b,i|
    entries[0]=pick=[b[games[0..round]],1].max
    winpct[i]+= 1.0/games.size if winner(entries)==pick 
  }
}
best=0;
winpct.each_index{|i|best = i if (winpct[i]>winpct[best])}
puts brains[best][games]

I'm not sure I've got the input format right - I'm not sure how to generate multi-line command line arguments for testing it on windows. (This method seems to work on IDEone.)

\$\endgroup\$
8
  • \$\begingroup\$ I can't test it right now, I'm at work and won't be home until after 9.30 (GMT). Does this SO question help with the multi-line arguments? \$\endgroup\$
    – Gareth
    Feb 20, 2012 at 17:16
  • \$\begingroup\$ Just tested this and it's giving me an error - strategist.rb:48:in 'each': No such file or directory - 42 2 6 10 8 6 5 7 6 1 5 8 3 6 3 4 26 2 10 1 26 8 42 5 3 7 (Errno::ENOENT). I'll stop considering new entries after 11PM, but I'll delay the scoring run slightly to give you time to look at the bug if you want. \$\endgroup\$
    – Gareth
    Feb 20, 2012 at 22:02
  • \$\begingroup\$ Okay, I think the problem was that you had ARGF instead of ARGV. After making that change the program guesses 1 every time. Any ideas what I can do to fix it? \$\endgroup\$
    – Gareth
    Feb 20, 2012 at 22:40
  • \$\begingroup\$ Can you add this line to the top and tell me what it prints when giving it the 2nd round input (2 lines of data): p ARGV.map{|l|l};exit (None of the SO answers to the question you reference or similar ones seem to give me the expected input) \$\endgroup\$
    – AShelly
    Feb 20, 2012 at 23:21
  • \$\begingroup\$ It prints out ["1 2\n3 4\n5 6\n1 2"] for the test input in the question. \$\endgroup\$
    – Gareth
    Feb 20, 2012 at 23:25
2
\$\begingroup\$

Perl

I figured that I might as well enter the inevitable. More serious entries coming soon. As a bonus, this entry will never lose in one-on-one competition.

print 1
\$\endgroup\$
4
  • \$\begingroup\$ not win every competition. in a one-on-one with another onesconfident, it will tie \$\endgroup\$
    – Blazer
    Feb 5, 2012 at 22:28
  • \$\begingroup\$ No! I can't believe I forgot about that case! I'll fix that. \$\endgroup\$
    – PhiNotPi
    Feb 5, 2012 at 22:34
  • \$\begingroup\$ One of my conclusions when I started designing my entry is that each bot should submit 1 at least 1/n of the time, to do their fair share in preventing onesconfident from walking away with it. \$\endgroup\$ Feb 6, 2012 at 8:43
  • \$\begingroup\$ @Peter: Don't worry, I took care of that. :) \$\endgroup\$ Feb 6, 2012 at 10:51
2
\$\begingroup\$

JavaScript (node.js)

Counts what was most popular last round and bids one less than that, wrapping to 20 and bidding 3 on the first round.

var lastRound = /[^\n]+$/.exec(process.argv[2]);
var numbers = {};
var re = /\d+/g;
var match;

while(match = re.exec(lastRound)) {
    numbers[match] = numbers[match] >>> 0 + 1;
}

var maxKey = -1;

for(var i in numbers) {
    if(maxKey === -1 || numbers[i] > numbers[maxKey]) {
        maxKey = i;
    }
}

if(maxKey == 0) {
    // First round. Bid 3.
    console.log(3);
} else if(maxKey == 1) {
    // Bid 20.
    console.log(20);
} else {
    // Bid one less.
    console.log(maxKey - 1);
}

How to invoke:

node script.js 'the argument'
\$\endgroup\$
7
  • \$\begingroup\$ Looking at the results of the most recent test run, this doesn't behave as documented. Any idea why not? \$\endgroup\$ Feb 7, 2012 at 22:32
  • 1
    \$\begingroup\$ @PeterTaylor I wonder if it's the first for loop? Should if(i in numbers) be if(matches[i] in numbers) do you think? \$\endgroup\$
    – Gareth
    Feb 7, 2012 at 22:50
  • \$\begingroup\$ @minitech After a little poking around at it, it looks like the regex is only matching the one number of the input - don't know enough about javascript or Nodejs to be able to say why though. Also, do you need to split the input on newlines to get the last round? \$\endgroup\$
    – Gareth
    Feb 7, 2012 at 23:38
  • \$\begingroup\$ @Gareth: Indeed it is. Updated, though if it performed better originally then I don't mind :) \$\endgroup\$
    – Ry-
    Feb 7, 2012 at 23:53
  • \$\begingroup\$ Unfortunately it's throwing an error for every round except the first now: node.js:201 throw e; // process.nextTick error, or 'error' event on first tick TypeError: Cannot read property 'length' of null at Object.<anonymous> (minitech1.js:6:23) \$\endgroup\$
    – Gareth
    Feb 8, 2012 at 19:40
2
\$\begingroup\$

Python (CopyCat)

Yet another, this time it copies the exact answer the last winner had, if there was one. It's dsigned to both try to win and block other bidders. bids 5 if first round, bids a random number from the previous round if there was somehow no winner

content = sys.argv[1].split('\n')
x = map(int, content[-1].split())
y = []
for each in x:
    if x.count(each) == 1:
        y.append(each)
print min(y) if sum(y) > 0 else random.choice(x) if sum(x) > 0 else 5
\$\endgroup\$
2
\$\begingroup\$

Python (Joe)

This is by no means designed to win, but I'm throwing it out there anyway to add some color to the crowd :) It bids the average of the last round (Average Joe). Invoked the same as my original answer (which I will now name because it seems like that's what all the cool kids are doing, and it helps to distinguish the two). if starting round, it bids 10.

content = sys.argv[1].split('\n')  
x = map(int, content[-1].split())
print sum(x)/len(x) if sum(x) != 0 else 10

edit: changed method of input to suit question's input method

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

Python (TotalBots)

I think this one will be my last, but we'll see. It takes advantange of knowing how many bots there are by simply outputting the number of competing bots, so if there are 17 bots (current number of bots, plus this one), it will output 17

content = sys.argv[1].split('\n')
print len(content[-1].split())
\$\endgroup\$
2
\$\begingroup\$

Perl (Health Inspector)

print ((((((2)**(2))*((2)**(2)))/((((2)**(2))*(2))*(2)))+((((2)**(2))*(2))/((2)+((2)*(((((2)**(2))+((2)*(2)))+(((2)*(2))/((2)**(2))))**(((2)/(2))/(2)))))))+((((2)-(2))/((((2)**(2))+(2))*((2)+(2))))*(rand(2))))

I bet you can guess what it does.

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

C++ (Educated Guess)

I already thought I would have missed the deadline, but thanks to the extension I can still add my entry. This program compiles with g++. The program tries to guess the statistics of the other entries, and to choose the smallest one not likely to be chosen by any other one.

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <deque>
#include <cstdlib>
#include <ctime>
#include <exception>
#include <stdexcept>

typedef std::vector<int> botvec;
typedef std::vector<botvec> scorevec;

// read all the scores from the given string
// note that this only does minimal error checking
// the result is a vector of vector, each entry of which
// represents one round. That is, the vectors in the vector
// correspond to the lines of the command line argument.
scorevec read_past_scores(char const* scoretext)
{
  scorevec past_scores;

  std::istringstream is(scoretext);
  std::string line;

  scorevec::size_type size = 0;

  while (std::getline(is, line))
  {
    past_scores.push_back(botvec());

    std::istringstream ils(line);
    int i;
    while (ils >> i)
      past_scores.back().push_back(i);
    if (size == 0)
      size = past_scores.back().size();
    else if (past_scores.back().size() != size)
      throw std::runtime_error("invalid score format");
  }
  return past_scores;
}

struct counts { int count[100]; };
struct prob { double p[100]; };

int generate_answer(scorevec& past_scores)
{
  int const number_of_players = past_scores.front().size();
  if (past_scores.front().front() == 0) // initial round
    past_scores.pop_back();

  // Pre-fill the counts to get reasonable probabilities also for
  // insufficient statistics (and the statistics *will* be
  // insufficient!). Bias in favour of small numbers.
  counts initial;
  for (int i = 0; i < 100; ++i)
    initial.count[i] =
      i < number_of_players? 100*(number_of_players-i) : 1;

  std::deque<counts> playercounts(number_of_players, initial);

  // add the actual guesses (with a high factor, to give them high
  // weight against the initial counts)
  for (int i = 0; i < past_scores.size(); ++i)
    for (int j = 0; j < number_of_players; ++j)
      playercounts[j].count[past_scores[i][j]-1]+=5000;

  // drop the own guesses
  playercounts.pop_front();

  // calculate the probabilities corresponding to the counts
  std::vector<prob> playerprobabilities(playercounts.size());
  for (int i = 0; i < playercounts.size(); ++i)
  {
    double sum = 0;
    for (int k = 0; k < 100; ++k)
      sum += playercounts[i].count[k];
    for (int k = 0; k < 100; ++k)
      playerprobabilities[i].p[k] = playercounts[i].count[k]/sum;
  }

  // for each selection, estimate the expected number of other players
  // who will bet on it. Return the first one with an expectation
  // below 1.5.
  for (int i = 0; i < 100; ++i)
  {
    double estimate = 0;
    for (int j = 0; j < number_of_players; ++j)
      estimate += playerprobabilities[j].p[i];
    if (estimate < 1.5)
      return i+1;
  }

  // in the unlikely case that such a choice doesn't exist (meaning
  // there are far more than 100 players), just return 100.
  return 100;
}

int main(int argc, char* argv[])
{
  if (argc < 2)
  {
    std::cerr << "Missing score argument!\n";
    return EXIT_FAILURE;
  }

  try
  {
    scorevec past_scores = read_past_scores(argv[1]);

    std::srand(std::time(0));

    std::cout << generate_answer(past_scores) << std::endl;

    return EXIT_SUCCESS;
  }
  catch(std::exception& e)
  {
    std::cerr << e.what() << "\n";
    return EXIT_FAILURE;
  }
  catch(...)
  {
    std::cerr << "Unknown error\n";
    return EXIT_FAILURE;
  }
}
\$\endgroup\$
2
\$\begingroup\$

Perl (Bob)

$_=<>;
INPUT:{

tr/ /,/;
@in = eval;
for(1..$#in){
 $bids[$rnum][$in[$_]]++
}
for(0..$#in){
 $tbids[$rnum][$in[$_]]++
}
$rnum++;
$_=<>;
if($_ ne"\n"){redo INPUT}
}

for(0..100){$pre[$_]=0}

blazer: {
for($r=1;$r<$rnum;$r++){
winner: for($pnt=1;$pnt<101;$pnt++){
        if($tbids[$r][$pnt] == 1){
            if($pnt > 2){
                $winnum[$pnt]++;
            $wins++;
            }
        last winner
        }
}
    }
    if($wins==0){
    $pre[3]++;last blazer
    }
}

CC1: for($pnt=1;$pnt<101;$pnt++){
    if($tbids[$rnum-1][$pnt] == 1){
        $pre[$pnt]++;last CC1
    }
}

CC2: for($pnt=1;$pnt<101;$pnt++){
    if($rnum-2<0){$pre[7]++;last CC2}
    if($tbids[$rnum-2][$pnt] == 1){
        $pre[$pnt]++;last CC2
    }
    if($pnt==100){
    $pre[7]++;last CC2
    }
}

one: {
$pre[1]+=2;
}

two: {
$pre[2]+=2;
}

five: {
$pre[5]+=2;
}

eight: {
$pre[8]+=2;
}

fortytwo: {
$pre[42]++;
}

mueller: {
    $a=($#in+2)/4;
    $pre[int$a]++;
}

schwarzenbeck: {
    $a=($#in+2)/4+1;
    $pre[int$a]++;
}

beckenbauer: {
    $a=($#in+2)/4+2;
    $pre[int$a]++;
}

totalbots: {
    $pre[$#in+1]++;
}

joe: {
$sum=0;
    for(1..100){
    $sum+=$_*$tbids[$rnum-1][$_];
}
    $average=$sum/($#in+1);
    if($average==0){$average=10};
    $pre[$average]++;
}

node: {
$max=0;$maxloc=0;
for(1..100){
    if($tbids[$rnum-1][$_]>$max){$max=$tbids[$rnum-1][$_];$maxloc=$_}
}
$maxloc--;
#if($maxloc==0){
$maxloc=20;
#}
if($rnum==1){$maxloc=3}
    $pre[$maxloc]++;
}
choice: for(1..100){
    if($pre[$_]==1){ 
$count++;
    if($count==3){print; last choice}
}
    if($_==100){print"98"}
}

See "Bob" for how to invoke.

\$\endgroup\$
2
  • \$\begingroup\$ That's a very recursive guide to invocation ;-) \$\endgroup\$
    – Gareth
    Feb 8, 2012 at 22:08
  • \$\begingroup\$ There's actually a chain of logic put into place: Alice describes how she takes input. Eve mentions that she takes input the same as Alice. Eve also mentions that she takes input the same as Bob. Thus, Bob takes the same input format as Alice, which is described. \$\endgroup\$
    – PhiNotPi
    Feb 8, 2012 at 22:33
2
\$\begingroup\$

Perl (Alice)

$_=<>;
INPUT:{

tr/ /,/;
@in = eval;
for(1..$#in){
 $bids[$rnum][$in[$_]]++
}
for(0..$#in){
 $tbids[$rnum][$in[$_]]++
}
$rnum++;
$_=<>;
if($_ ne"\n"){redo INPUT}
}

for(0..100){$pre[$_]=0}

blazer: {
for($r=1;$r<$rnum;$r++){
winner: for($pnt=1;$pnt<101;$pnt++){
        if($tbids[$r][$pnt] == 1){
            if($pnt > 2){
                $winnum[$pnt]++;
            $wins++;
            }
        last winner
        }
}
    }
    if($wins==0){
    $pre[3]++;last blazer
    }
}

CC1: for($pnt=1;$pnt<101;$pnt++){
    if($tbids[$rnum-1][$pnt] == 1){
        $pre[$pnt]++;last CC1
    }
}

CC2: for($pnt=1;$pnt<101;$pnt++){
    if($rnum-2<0){$pre[7]++;last CC2}
    if($tbids[$rnum-2][$pnt] == 1){
        $pre[$pnt]++;last CC2
    }
    if($pnt==100){
    $pre[7]++;last CC2
    }
}

one: {
$pre[1]+=2;
}

two: {
$pre[2]+=2;
}

five: {
$pre[5]+=2;
}

eight: {
$pre[8]+=2;
}

fortytwo: {
$pre[42]++;
}

mueller: {
    $a=($#in+2)/4;
    $pre[int$a]++;
}

schwarzenbeck: {
    $a=($#in+2)/4+1;
    $pre[int$a]++;
}

beckenbauer: {
    $a=($#in+2)/4+2;
    $pre[int$a]++;
}

totalbots: {
    $pre[$#in+1]++;
}

joe: {
$sum=0;
    for(1..100){
    $sum+=$_*$tbids[$rnum-1][$_];
}
    $average=$sum/($#in+1);
    if($average==0){$average=10};
    $pre[$average]++;
}

node: {
$max=0;$maxloc=0;
for(1..100){
    if($tbids[$rnum-1][$_]>$max){$max=$tbids[$rnum-1][$_];$maxloc=$_}
}
$maxloc--;
#if($maxloc==0){
$maxloc=20;
#}
if($rnum==1){$maxloc=3}
    $pre[$maxloc]++;
}
choice: for(1..100){
    if($pre[$_]==1){ 
$count++;
    if($count==2){print; last choice}
}
    if($_==100){print"99"}
}

Takes input similar to my other bots.

perl Alice.plx
1 4 3 12
3 2 4 11
[blank line]
\$\endgroup\$
2
\$\begingroup\$

Perl (Eve)

I completely redid this entry to help pave the way for my other bots.

$_=<>;
INPUT:{

tr/ /,/;
@in = eval;
for(1..$#in){
 $bids[$rnum][$in[$_]]++
}
for(0..$#in){
 $tbids[$rnum][$in[$_]]++
}
$rnum++;
$_=<>;
if($_ ne"\n"){redo INPUT}
}

for(0..100){$pre[$_]=0}

blazer: {
for($r=1;$r<$rnum;$r++){
winner: for($pnt=1;$pnt<101;$pnt++){
        if($tbids[$r][$pnt] == 1){
            if($pnt > 2){
                $winnum[$pnt]++;
            $wins++;
            }
        last winner
        }
}
    }
    if($wins==0){
    $pre[3]++;last blazer
    }
}

CC1: for($pnt=1;$pnt<101;$pnt++){
    if($tbids[$rnum-1][$pnt] == 1){
        $pre[$pnt]++;last CC1
    }
}

CC2: for($pnt=1;$pnt<101;$pnt++){
    if($rnum-2<0){$pre[7]++;last CC2}
    if($tbids[$rnum-2][$pnt] == 1){
        $pre[$pnt]++;last CC2
    }
    if($pnt==100){
    $pre[7]++;last CC2
    }
}

one: {
$pre[1]+=2;
}

two: {
$pre[2]+=2;
}

five: {
$pre[5]+=2;
}

eight: {
$pre[8]+=2;
}

fortytwo: {
$pre[42]++;
}

mueller: {
    $a=($#in+2)/4;
    $pre[int$a]++;
}

schwarzenbeck: {
    $a=($#in+2)/4+1;
    $pre[int$a]++;
}

beckenbauer: {
    $a=($#in+2)/4+2;
    $pre[int$a]++;
}

totalbots: {
    $pre[$#in+1]++;
}

joe: {
$sum=0;
    for(1..100){
    $sum+=$_*$tbids[$rnum-1][$_];
}
    $average=$sum/($#in+1);
    if($average==0){$average=10};
    $pre[$average]++;
}

node: {
$max=0;$maxloc=0;
for(1..100){
    if($tbids[$rnum-1][$_]>$max){$max=$tbids[$rnum-1][$_];$maxloc=$_}
}
$maxloc--;
#if($maxloc==0){
$maxloc=20;
#}
if($rnum==1){$maxloc=3}
    $pre[$maxloc]++;
}
choice: for(1..100){
    if($pre[$_]==1){ 
$count++;
    if($count==1){print; last choice}
}
    if($_==100){print"100"}
}

Takes one input format: the same as "Bob" and "Alice".

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

Brainfuck

To quote from the challenge:

"You can enter as many bots as you wish, so if anyone does enter a bot that only guesses 1, you can enter another that does the same to render it useless."

Well, since PhiNotPi did enter one, let me enter another. Just to be different, I'll do it in Brainfuck:

+++[->++++<]>[-<++++>]<+.

Of course, now that betting 1 is no longer a feasible strategy, the obvious thing to do now is to bet 2 instead...

Edit: Split answer into two per comments, rewrote both programs in more interesting languages.

\$\endgroup\$
12
  • \$\begingroup\$ Firstly, one entry per answer please. Secondly, I know that someone could post 100 answers each printing one of the digits from 1 to 100 in order to guarantee not losing - equally someone else could do exactly the same meaning that no-one will win. In a game of football (soccer) all 11 players could stand on the goal line to guarantee that the other team doesn't score. It never normally happens that way because it would be much of a game if they did would it? \$\endgroup\$
    – Gareth
    Feb 6, 2012 at 11:11
  • \$\begingroup\$ Thirdly, this objection should really have been raised in the sandbox - after all that is its purpose. \$\endgroup\$
    – Gareth
    Feb 6, 2012 at 11:11
  • \$\begingroup\$ @Gareth: OK, I've split the answer into two. As for the reasonability of the entries, you yourself suggested that, if anyone were to submit "onesconfident", someone else could do the same to counter it. At that point, of course, submitting "twosconfident" makes just as much sense as submitting "onesconfident" did in the first place, so... \$\endgroup\$ Feb 6, 2012 at 18:25
  • 1
    \$\begingroup\$ The neat thing about this is that now I cannot delete my onesconfident entry without allowing this entry to win. \$\endgroup\$
    – PhiNotPi
    Feb 6, 2012 at 21:29
  • 1
    \$\begingroup\$ @Peter: Why do you think so? Given that both mine and PhiNotPi's programs are in the race, there's no reason for anyone else to submit a program that ever bets 1 (if they want that program to win, that is). \$\endgroup\$ Feb 7, 2012 at 0:36
1
\$\begingroup\$

Mueller (Scala)

object Mueller extends App {
  println ((args(0).split('\n')(0).split(' ').length+1)/4)
}

If you know Schwarzenbeck and Beckenbauer, you surely expected Mueller. Here he is. He will benefit much from Beckenbauer and Schwarzenbeck and is supposed to win.

Details about running and compilation: See Schwarzenbeck

Closer to the goal, now.

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

Beckenbauer (Scala)

object Beckenbauer extends App {
  println ((args(0).split('\n')(0).split(' ').length+1)/4+2)
}

With the help of Schwarzenbeck, Beckenbauer is supposed to score some goals. Without Schwarzenbeck, he's nothing.

Details about running and compilation: See [Schwarzenbeck][1]

Edit: Playing deeper in the room now, too.

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

Batch Scripting

echo 5

My submission, gives 5 as its answer every time ;-)

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

Eight.bat

echo 8

Another simple answer, gives 8 every time.

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

FivesCancel (PHP)

Cancels mellamokb's "always 5" solution.

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

EightsCancel (PHP)

Cancels mellamokb's "always 8" solution. Sorry, mellamokb!

8
\$\endgroup\$
1
  • \$\begingroup\$ Here we go again, competition :P \$\endgroup\$
    – mellamokb
    Feb 17, 2012 at 13:59
1
\$\begingroup\$

Python 2.7 - Copycat2

Copies the second last round's winner. Oh no! otherwise outputs 7.

import sys
content = sys.argv[1].split('\n')
x = map(int, content[-2].split()) if len(content) > 1 else [7]
y = []
for each in x:
    if x.count(each) == 1:
        y.append(each)
print min(y) if sum(y) > 0 else random.choice(x) if sum(x) > 0 else 7
\$\endgroup\$
1
\$\begingroup\$

Shell script (Deep Thought)

OK, so that I get a slight second chance, here's another entry, this time a shell script (should work with any shell). This always gives the answer to the question of life, the universe and everything.

echo 42

Actually this algorithm is not entirely correct because I omitted the 7.5 million year delay. :-)

\$\endgroup\$
1
  • \$\begingroup\$ Too late for tonight's test run sorry, but I'll do another in the morning. \$\endgroup\$
    – Gareth
    Feb 19, 2012 at 22:08
1
\$\begingroup\$

dirichlet.c

#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>

main(int argc, char* argv[])
{
    int handle;
    char *str;
    int32_t bits, val, n = 0;

    if (argc) {
        for (str = argv[1]; *str; str++)
            if (*str == 32) n++;
            else if (*str == 10) break;
    }

    n /= 2;
    if (n > 99) n = 99;

    handle = open("/dev/urandom", O_RDONLY);
    do {
        read(handle, &bits, sizeof bits);
        bits &= 0x7fffffff;
        val = bits % n;
    } while (bits - val + (n-1) < 0);
    close(handle);

    printf("%d", 2 + val);
}

I think this goes through random bits too fast to use /dev/random, however much I'd prefer to. If anyone wants to test it on Windows you'll have to port it yourself, because I don't have access to a Windows box with a C compiler.

Rationale

I didn't want to explain the logic behind this before the tournament was over, but now that the winner has been announced, I think it's time.

By the pigeon-hole principle (aka Dirichlet's principle, hence the name of the bot), if there are N competing bots then there is a number w in [1..1+N/2] which either won or would have won if selected. I therefore conclude that the optimal strategy will not select numbers greater than 1+N/2. But if N is even, selecting 1+N/2 creates a smaller winning slot. Therefore the slots which are worth selecting are [1..(N+1)/2].

That leaves the question of how to select a slot. For small numbers of bots I verified that there's a Nash equilibrium when each bot selects uniformly among the candidates, and I strongly suspect that this will continue to hold true.

The minor deviation in this bot's strategy from the theoretical one is simply metagaming.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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