text:
Traders to the Death
You are a foreign trader, hoping to make a profit.  There are 5 goods people wish to trade: Apricots, Boars, Canaries, Daffodils, and Earwigs.  Starting in the winter, you need to decide what to produce.  Then, in the fall, you travel and spend your days trading for a profit.
Gameplay
You start the game with 10 of each product in storage.  Each year, you will consume 2 of each product.
At the beginning of the game, you receive a list of 5 products, along with the amount you will be able to produce each year (ex:5-A,6-B,3-C,12-D,4-E).  You then will return a letter A through E deciding what to produce.
Then, in the fall time you will bring your products (including those in storage) to the market.  You have 50 turns to trade.
You must decide if you want to Purchase, Sell, or Leave the market.  The buyers will then be paired up randomly with the sellers.  If a group has extra, the random extras will miss out this turn.  If a trader is skipped, they will receive S, otherwise, T.  The seller must decide what he wants to sell, and amount (ex:3-A), and then what he would accept (ex:5-B,2-D,1-E) (The values are any of not all of).  The buyer will then be told what product the seller is selling, then the products the seller will take for it, and he can choose a product to trade for it (ex: D or X for nothing).
After all trades are over, or after you have left the market, you will consume 2 of each product, and the year starts over.  If you have less than 2 of any 1 product, you will die (and passed Q).
Your score will be the number of years you last, and after 50 games, your scores will be averaged for your total score.
Optional moves
At any time you can return G to query your goods
At any time you can return N to query the number of new products in your inventory (produced by any player in the past year, and new products will be traded before old products)
At any time you can return T for the current Turn phrase: Produce, Market, or Trading
During a trade, you can query I for an identifier unique to the player you are trading with.
During a trade, you can return M to query the number of people trading
How to code it:
You may use any standard language, and must include a command.txt which is the command to run your program.
The general flow of your program should be:
Get productivity
While alive:
    Output product you want to produce
    While in trading:
        Output whether you want to purchase or sell
        Get whether or not you were skipped.  If not skipped:
            If purchasing:
                print product you offer, and products you will accept
            Else:
                Get product offered, products being accepted, and choose the product you will give

I have a tester program here.  To use it, create a folder in the bots folder with your bot's name.  Add a command.txt, your program, and anything else your program needs.  I will be adding submissions as they come in.  If you don't want to install the languages required to run some or all of them, you just need to delete the command.txt in the bot's folder.
Inner Workings
There will be 5 bots for each program submitted.  The ID will be different for bots of the same type.
I will call the amount a person can produce a given product the productivity. Each product will be given a base productivity, where all of the base productivity will add up to 30.  One of the scores will be ensured to be at most 3, and all will be at least 2.
Then, each player's productivity will vary from the base productivity (One value will vary by +2, another +1, then +0, -1, and the remaining value will vary by -2).
The base productivity will change from game to game.
Scores:
seer:                10.128 years
level_headed_trader: 8.196 years
introvert:           6.856 years
random_ando:         5.408 years
hoarder_trader:      4.12 years
ratio_trader:        3.532 years
scared_trader:       3.056 years

So, if there are 10 user submitted programs a game will have 60 (10 submitted + 10 x 5 bots) players/traders? Also, I don't think you mentioned what the maximum number of years a game can last for. Only that there will be 50 games, and that trader/player's score for a game will be how long they lasted.

No.   My bots are no different than the rest.  If there are 10 user submitted, there will be (10 players + 4 my bots)*5 traders.  The game is set up so it is impossible for a game go on forever.  Eventually everybody will die.

Ah, thanks. It's a very interesting KOTH challenge. I'll certainly try and make a submission. Any programming language is permitted?

Yes, any programming language.

If you fail to consume from any one category, you die? Or from all categories? Eg. if I have no apricots but stuff in other categories, will I die?

Yes.  I will modify my post to make that clearer.

How long does Scoring.py normally run?

@EaterOfCode With just the bots, and with debug on, it takes about 5 seconds to run.

Im doing something really stupid probably but it just doesn't end, and I can't CTRL-C either

@EaterOfCode If you are running it on Windows and your program doesn't provide output/input properly, it will freeze, and you will have to kill it.

without my bot, it doesn't stop. I now use my bot to forcefully stop it

Let us continue this discussion in chat.

What does the T command return if you're dead? Q?

@ipi You won't get anything.  I don't prompt any dead controllers for input.

It's a pity nobody else made a submission. I was looking forward to this KOTH.

@AndoDaan I'm going to put a bounty on it after a week.  There will be submissions.

@AndoDaan Im busy with one :D

@EaterOfCode and Nathan, ah great. Of course I'll try and contribute a more cerebral bot than I did with Rando.

I'm not getting this to run on Windows with a fresh clone.

Hmm...it seems I can't run it from the console either on windows.  I'm using Pycharm on Windows, and it runs just fine there.  Let me see what I can figure out.

Hey, can you add some example IO?

I can't get the game to run on linux. Using only the bots that come with the controller. I just clone, compile and run. It sends the first message to each bot and then waits forever - no responses.

@ccarton That's odd.  I don't currently have access to a linux box, last time I used this code it worked.  Try removing RandomAndo and/or the Introvert, as they are non-python.

@BetaDecay That's tough due to the variety of optional moves.  The only outputs that will always happen is the beginning productivity, the final q, whether you were skipped, and if you are buying, the seller's offer and accepted products.  I hope the inputs are obvious.

Can a bot be stateful across multiple runs? For example, by writing a file to record info about competitors or certain statistical properties? I realize the resource distribution changes with each run, but there are other unknowns that could be estimated and exploited to build a better bot.

@COTO you program needs to die across multiple runs, but you are definitely are fine to store information in a file between runs.

Ha, Rando is smack dab in the middle. That's a win for a random bot.

Seer
This program predicts the future, and he chooses the trades which will increase his expected lifespan.
This isn't completely finished, because he only knows how to buy things but not sell things, so expect an update in the future.  Regardless, I believe that he will be competitive as-is.
$| = 1;
@names = ('A','B','C','D','E');
@counts = (12,12,12,12,12);
%names = ('A',0,'B',1,'C',2,'D',3,'E',4);

sub predict{
 local @a = @_;
 local $minval = 1000;
 local $minloc = 0;
 for(0..~~@a-1){
  if($a[$_]<$minval){
   $minloc = $_;
   $minval = $a[$_]
  }
  $a[$_]-=2;
 }
 if($minval <= 1){return (0,@a)}
 if($minval == 100){return (10000,@a)}
 $a[$minloc] += $productivity[$minloc];
 local @b = predict(@a);
 @b[0]++;
 return @b;
}

sub choice{
 local @a = @_;
 local $minloc = 0;
 local $minval = 1000;
 for(0..~~@a-1){
  if($a[$_]<$minval){
   $minloc = $_;
   $minval = $a[$_]
  }
 }
 return $minloc;
}

$productivity = <>;
@productivity = split(',',$productivity);

#@c = predict(@counts);
#print "@c\n";
$alive = 1;
while($alive){
 for(0..4){
  $counts[$_] -= 2;
 }
 $choice = choice(@counts);
 print "$names[$choice]\n";
 $counts[$choice] += $productivity[$choice];
 for(1..50){
  print "P\n";
  chomp($in = <>);
  if($in eq "T"){
   chomp($forsale = <>);
   ($quantity,$type) = split("-",$forsale);
   $type = $names{$type};
   #print "$quantity, $type\n";
   chomp($in = <>);
   @options = split(",",$in);
   @baseline = predict(@counts);
   $lifespan = shift @baseline;
   $basescore = $lifespan * 1000;
   @bestcounts = @counts;
   for(0..4){
    $basescore -= 10**(-1 * $baseline[$_]);
   }
   #print "Base: $basescore\n";
   @hypo = ();
   $bestscore = $basescore;
   $choice = "X";
   for(0..$#options){$curchoice = $_;
    ($cost,$ctype) = split("-",$options[$curchoice]);
    $ctype = $names{$ctype};
    @tempcounts = @counts;
    $tempcounts[$type] += $quantity;
    $tempcounts[$ctype] -= $cost;
    @curhypo = predict(@tempcounts);
    @hypo[$curchoice] = [@curhypo];
    #print "@curhypo\n";
    $lifespan = shift @curhypo;
    $score = $lifespan * 1000;
    for(0..4){
     $score -= 10**(-1 * $curhypo[$_]);
    }
    #print"$score\n";
    if($score > $bestscore){
     $bestscore = $score;
     $choice = $names[$ctype];
     @bestcounts = @tempcounts;
    }
   }
   print "$choice\n";
   @counts = @bestcounts;
  }
  #print"@counts\n";
  #@c = predict(@counts);
  #print "@c\n";
 }
}

I run this program like so:
perl seer.plx

I got your program to work, but I had to add $| = 1 at the beginning.  For your next revision, please do that.  Also, your bot didn't do so well.  To look at the results: http://pastebin.com/yaDprHPq

@NathanMerrill The very short lifespan is kinda bizarre.... I'll take a look at that now.

Level-headed Trader
This bot tries to make his quantities as equal as possible
command.txt
python leveller.py

leveller.py
import sys

def current_goods():
    print "G"
    return parse_goods(readline())

def parse_goods(good_string):
    return dict([(a, int(b))
                 for a, b in [product.split("-")
                              for product in good_string.split(",")]])

def get_minimum(goods):
    cur_min = 200
    min_good = "X"
    for good, amount in goods.items():
        if amount < cur_min:
            min_good = good
            cur_min = amount
    return min_good

def get_maximum(goods):
    cur_max = -1
    max_good = "X"
    for good, amount in goods.items():
        if amount > cur_max:
            max_good = good
            cur_max = amount
    return max_good

def add_goods(x, y):
    return {k: int(x.get(k, 0)) + int(y.get(k, 0)) for k in set(x) | set(y)}

def readline():
    line = sys.stdin.readline().strip()
    if line == 'Q' or not line:
        exit()
    return line

def output_goods(goods):
    print ",".join([good+"-"+str(amount) for good, amount in goods.items()])

def output_good(good, amount):
    print good+"-"+str(amount)

def current_turn_is(turn):
    print "T"
    return readline() == turn

turns = MARKET, PRODUCE, TRADING, SKIPPED = "M", "P", "T", "S"
market_options = PURCHASE, SELL = "P", "S"
items = APRICOTS, BOARS, CANARIES, DAFFODILS, EARWIGS, NOTHING = "A", "B", "C", "D", "E", "X"

productivity = parse_goods(readline())
while True:
    product_to_produce = get_minimum(current_goods())
    print product_to_produce
    while current_turn_is(MARKET):
        print SELL
        if readline() != SKIPPED:
            maximum = get_maximum(current_goods())
            goods = {"A": 1, "B": 1, "C": 1, "D": 1, "E": 1}
            del goods[maximum]
            output_good(maximum, 1)
            output_goods(goods)

Scared Trader
This trader avoids getting low numbers
command.txt
python scared.py

scared.py
import sys

def current_goods():
    print "G"
    return parse_goods(readline())

def parse_goods(good_string):
    return dict([(a, int(b))
                 for a, b in [product.split("-")
                              for product in good_string.split(",")]])

def get_minimum(goods):
    cur_min = 200
    min_good = "X"
    for good, amount in goods.items():
        if amount < cur_min:
            min_good = good
            cur_min = amount
    return min_good

def get_maximum(goods):
    cur_max = -1
    max_good = "X"
    for good, amount in goods.items():
        if amount > cur_max:
            max_good = good
            cur_max = amount
    return max_good

def add_goods(x, y):
    return {k: int(x.get(k, 0)) + int(y.get(k, 0)) for k in set(x) | set(y)}

def readline():
    line = sys.stdin.readline().strip()
    if line == 'Q' or not line:
        exit()
    return line

def output_goods(goods):
    print ",".join([good+"-"+str(amount) for good, amount in goods.items()])

def output_good(good, amount):
    print good+"-"+str(amount)

def current_turn_is(turn):
    print "T"
    return readline() == turn

turns = MARKET, PRODUCE, TRADING, SKIPPED = "M", "P", "T", "S"
market_options = PURCHASE, SELL = "P", "S"
items = APRICOTS, BOARS, CANARIES, DAFFODILS, EARWIGS, NOTHING = "A", "B", "C", "D", "E", "X"

productivity = parse_goods(readline())
while True:
    current = current_goods()
    min_product = get_minimum(current)
    min_amount = current[min_product]
    product_to_produce = min_product if min_amount < 4 else get_minimum(productivity)
    print product_to_produce
    while current_turn_is(MARKET):
        print SELL
        if readline() != SKIPPED:
            current = current_goods()
            maximum = get_maximum(current)
            minimum = get_minimum(current)
            to_offer = {maximum: max(productivity[maximum]/productivity[minimum], 1)}
            output_good(minimum, 1)
            output_goods(goods=to_offer)

Hoarder Trader
This trader tries to get as many products as possible.
command.txt
python hoarder.py

hoarder.py
import sys

def current_goods():
    print "G"
    return parse_goods(readline())

def parse_goods(good_string):
    try:
        return dict([(a, int(b))
                     for a, b in [product.split("-")
                                  for product in good_string.split(",")]])
    except:
        raise IOError(good_string)

def get_minimum(goods):
    cur_min = 200
    min_good = "X"
    for good, amount in goods.items():
        if amount < cur_min:
            min_good = good
            cur_min = amount
    return min_good

def get_maximum(goods):
    cur_max = -1
    max_good = "X"
    for good, amount in goods.items():
        if amount > cur_max:
            max_good = good
            cur_max = amount
    return max_good

def add_goods(x, y):
    return {k: int(x.get(k, 0)) + int(y.get(k, 0)) for k in set(x) | set(y)}

def readline():
    line = sys.stdin.readline().strip()
    if line == 'Q' or not line:
        exit()
    return line

def output_goods(goods):
    print ",".join([good+"-"+str(amount) for good, amount in goods.items()])

def output_good(good, amount):
    print good+"-"+str(amount)

def current_turn_is(turn):
    print "T"
    return readline() == turn

turns = MARKET, PRODUCE, TRADING, SKIPPED = "M", "P", "T","S"
market_options = PURCHASE, SELL = "P", "S"
items = APRICOTS, BOARS, CANARIES, DAFFODILS, EARWIGS, NOTHING = "A", "B", "C", "D", "E", "X"

productivity = parse_goods(readline())
while True:
    product_to_produce = get_minimum(add_goods(current_goods(), productivity))
    print product_to_produce
    while current_turn_is(MARKET):
        print PURCHASE
        if readline() != SKIPPED:
            offered_good = parse_goods(readline())
            accepted_goods = parse_goods(readline())
            minimum = get_minimum(accepted_goods)
            current = current_goods()
            if minimum not in current or current[minimum] < accepted_goods[minimum]:
                print NOTHING
            elif accepted_goods[minimum] < offered_good.values()[0]:
                print minimum
            elif accepted_goods[minimum] == offered_good.values()[0] \
                    and productivity[minimum] > productivity[offered_good.keys()[0]]:
                print minimum
            else:
                print NOTHING

Ratio Trader
This bot offers products matching the ratio of his productivity
command.txt
python ratio.py

ratio.py
import sys

def current_goods():
    print "G"
    return parse_goods(readline())

def parse_goods(good_string):
    return dict([(a, int(b))
                 for a, b in [product.split("-")
                              for product in good_string.split(",")]])

def get_minimum(goods):
    cur_min = 200
    min_good = "X"
    for good, amount in goods.items():
        if amount < cur_min:
            min_good = good
            cur_min = amount
    return min_good

def get_maximum(goods):
    cur_max = -1
    max_good = "X"
    for good, amount in goods.items():
        if amount > cur_max:
            max_good = good
            cur_max = amount
    return max_good

def add_goods(x, y):
    return {k: int(x.get(k, 0)) + int(y.get(k, 0)) for k in set(x) | set(y)}

def readline():
    line = sys.stdin.readline().strip()
    if line == 'Q' or not line:
        exit()
    return line

def output_goods(goods):
    print ",".join([good+"-"+str(amount) for good, amount in goods.items()])

def output_good(good, amount):
    print good+"-"+str(amount)

def current_turn_is(turn):
    print "T"
    return readline() == turn

turns = MARKET, PRODUCE, TRADING, SKIPPED = "M", "P", "T", "S"
market_options = PURCHASE, SELL = "P", "S"
items = APRICOTS, BOARS, CANARIES, DAFFODILS, EARWIGS, NOTHING = "A", "B", "C", "D", "E", "X"

productivity = parse_goods(readline())
while True:
    current = current_goods()
    min_product = get_minimum(current)
    min_amount = current[min_product]
    product_to_produce = min_product if min_amount < 4 else get_minimum(productivity)
    print product_to_produce
    while current_turn_is(MARKET):
        print SELL
        if readline() != SKIPPED:
            current = current_goods()
            maximum = get_maximum(current)
            minimum = get_minimum(current)
            to_offer = {maximum: max(productivity[maximum]/productivity[minimum], 1)}
            output_good(minimum, 1)
            output_goods(goods=to_offer)

Family Farmers - Java
The five family farmers do their best to cover all production options with whoever can make the most in any category working on that category. However, after the initial assignments the family members all strike out on their own; they don't collude after the initial assignments. I may get around to having them help each other while trading.
FamilyFarmers.java
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Scanner;

public class FamilyFarmers {
    final int MIN_PRODUCTION_CUTOFF = 4; // If my decision making has ended up
                                            // with a family member producing
                                            // less than this number, he will
                                            // just produce his most productive
                                            // item
    final int NUMBER_PRODUCTS = 5;
    final int MAX_TRADES = 50; // The number of trades per phase
    final byte EOF = 04;
    final byte NEW_LINE = 10;
    final int BILLBOARD_SIZE = 1000;

    boolean alive = true;

    int[] myInventory;

    int myNumber;
    // Primarily, the line this instance of the program will be printing on in
    // the billboard number 0 will be the "boss", and will do a bunch of the
    // calculations (To avoid them being done multiple times)
    MappedByteBuffer familyBillboard;
    String myProduct; // What product (single string character) we will be
                        // making
    Scanner stdin = new Scanner(System.in);

    /**
     * @param args
     *            A string in the form A-#,B-#,C-#,D-#,E-# representing the
     *            productivity of each good.
     * @throws IOException
     * @throws InterruptedException
     * @throws UnexpectedPhaseTokenException
     */
    public static void main(String[] args) throws IOException, InterruptedException {
        new FamilyFarmers();
    }

    public FamilyFarmers() throws IOException, InterruptedException {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                familyBillboard.clear();
                familyBillboard.put(new byte[familyBillboard.limit()]);
                Runtime.getRuntime().halt(0);
            }
        });
        initialSetup();
        mainLoop();
    }

    protected void mainLoop() throws InterruptedException {
        int tradeCounter = 0; // 50 trades per phase
        String currentStage;
        int toTrade = -1;
        int toGet = -1;
        boolean purchase = false;

        while (alive) {
            System.out.println("T");
            currentStage = stdin.nextLine();
            if (currentStage.equals("P")) { // Production period
                System.out.println(myProduct);
                /*
                System.out.println("G");
                String currentInv = stdin.nextLine();
                myInventory = parseProducts(currentInv);
                toTrade = getMostProduct();
                toGet = getLeastProduct();
                */
                tradeCounter = 0;

            } else if (currentStage.equals("M")) { // Market
                System.out.println("G");
                String currentInv = stdin.nextLine();
                myInventory = parseProducts(currentInv);
                tradeCounter++;
                purchase = (Math.random() >= 0.5);
                toTrade = getMostProduct();
                toGet = getLeastProduct();

                // If my goods are fairly even, it's time to head home!
                if (myInventory[toTrade] - myInventory[toGet] <= 2) {
                    System.out.println("L");
                    continue;
                }

                // If I don't have much to trade...
                if (toTrade <= 6) {
                    // But my goods levels are fairly even...
                    if (toGet >= 4) {
                        // I'll just leave the market
                        System.out.println("L");
                    }
                }

                if (purchase) {
                    System.out.println("P");
                } else {
                    System.out.println("S");
                }

            } else if (currentStage.equals("T")) {
                String toSend = "";
                if (purchase) { // Buying
                    boolean finished = false;
                    String offer = stdin.nextLine();
                    offer += "," + stdin.nextLine();
                    String[] offers = parseOffer(offer);
                    int quantityOffered = Integer.parseInt(offers[0].split("-")[0]);
                    int productOffered = offers[0].split("-")[1].charAt(0) - 65;

                    // This loop will probably never get off the first
                    // iteration...
                    // Go through the offers, blindly pick the first one that
                    // looks good.
                    for (int index = 1; index < offers.length && !finished; index++) {
                        int quantityDesired = Integer.parseInt(offers[index].split("-")[0]);
                        int productDesired = offers[index].split("-")[1].charAt(0) - 65;

                        // If the request would leave me with less than two, I'm
                        // not interested
                        if (quantityDesired - (myInventory[productDesired]) > 2) {
                            // Too rich for my blood!
                            continue;
                        }
                        if (productDesired == toGet) {
                            // I'm not interested in trading what I'm trying to
                            // get!
                        }
                        if (productOffered == toGet) {
                            // Since this is what I want to trade for, I'll be
                            // willing to consider different offers than
                            // otherwise

                            if (quantityDesired <= quantityOffered * 1.25
                                    && myInventory[productDesired] - quantityDesired > 4) {
                                System.out.println((char) (productDesired + 65));
                                finished = true;
                            }

                            // If I would otherwise die without the product,
                            // I'll accept a really bad trade
                            // (Remember that the incoming offers are already
                            // sorted least to highest)
                            if (myInventory[toGet] < 2 && tradeCounter > MAX_TRADES / 2) {
                                System.out.println((char) (productDesired + 65));
                                finished = true;
                            }
                        }

                        // If the product is what I'm trying to trade, and the
                        // offer isn't too bad
                        if (productDesired == toTrade && quantityOffered * 1.25 <= quantityDesired) {
                            System.out.println((char) (productDesired + 65));
                            finished = true;
                        }

                        // If I am offered either as much as or more of
                        // something, I'll do it.
                        if (quantityOffered >= quantityDesired) {
                            System.out.println((char) (productDesired + 65));
                            finished = true;
                        }
                    }

                    if (!finished) {
                        // If we get this far, nothing struck my fancy
                        System.out.println("X");
                    }

                } else { // Selling
                    int[] toBuy = getSameProducts(toGet);

                    // Make some self-beneficial offers in the first few rounds.
                    if (tradeCounter <= 5) {
                        toSend = "" + ("2-" + ((char) (toTrade + 65)));
                        for (int index = 0; index < toBuy.length; index++) {
                            toSend += (",3-" + ((char) (toBuy[index] + 65)));
                        }
                    } else {
                        // Basic offer. Just offer 1:1 for what I want.
                        toSend = "" + ("2-" + ((char) (toTrade + 65)));
                        for (int index = 0; index < toBuy.length; index++) {
                            toSend += (",2-" + ((char) (toBuy[index] + 65)));
                        }
                    }

                    // If trading has been going for awhile and I would die the
                    // next turn, I frantically offer everything I have for what
                    // I need to survive one more turn. This is probably a
                    // terrible strategy!
                    if (myInventory[toGet] < 2 && tradeCounter > MAX_TRADES / 2) {
                        toSend += ("4-" + ((char) (toTrade + 65))) + ",2-" + ((char) (toGet + 65));
                    }

                    if (toSend.length() < 6) {
                        // I couldn't find enough to sell...
                        System.out.println(toSend + "," + toSend);
                        // That's safe, right?
                        break;
                    }

                    // Put the products I would accept on a line after the
                    // product I want to sell
                    String[] splitSend = toSend.split(",");
                    toSend = splitSend[0] + "\n";
                    boolean first = true; // Don't prepend a comma on the first string

                    for (int index = 1; index < splitSend.length; index++) {
                        if (!first){
                            toSend += ",";
                        }
                        toSend += splitSend[index];
                        first = false;
                    }

                    System.out.println(toSend);

                }

            } else if (currentStage.equals("S")) { // I was skipped! Darn it!
            } else {
                // AAK! I received a token I don't know what to do with! I must
                // be dead...
                alive = false;
            }
        }
    }

    /**
     * Returns the offers, sorted from least product desired to most, with the
     * product being offered at the first index
     *
     * @param offer
     * @return String[] index 0 contains the product being offered, the
     *         following indicies are the desired products ordered from least to
     *         most
     */
    protected String[] parseOffer(String offer) {
        String[] splitOffers = offer.split(",");

        // Sort. Just using selection sort. The first index contains the string
        // with the product being asked for,
        // so should not be sorted.
        for (int index = 1; index < splitOffers.length; index++) {
            int indexOfMin = index;
            int minimum = Integer.parseInt(splitOffers[index].split("-")[0]);
            for (int jdex = index + 1; jdex < splitOffers.length; jdex++) {
                int thisValue = Integer.parseInt(splitOffers[jdex].split("-")[0]);
                if (thisValue < minimum) {
                    indexOfMin = jdex;
                    minimum = thisValue;
                }
            }
            String temp = splitOffers[index];
            splitOffers[index] = splitOffers[indexOfMin];
            splitOffers[indexOfMin] = temp;

        }

        return splitOffers;
    }

    /**
     * Returns an array of the indices of the product which I have the same
     * quantity of in myInventory
     *
     * @param startingIndex
     *            - The index of a value to match
     * @return
     */
    protected int[] getSameProducts(int startingIndex) {
        int[] toReturn = new int[0];

        for (int index = startingIndex + 1; index < myInventory.length; index++) {
            if (myInventory[index] == myInventory[startingIndex]) {
                int[] temp = new int[toReturn.length + 1];
                for (int jdex = 0; jdex < toReturn.length; jdex++) {
                    temp[jdex] = toReturn[jdex];
                }
                temp[temp.length - 1] = index;
                toReturn = temp;
            }
        }

        return toReturn;
    }

    /**
     * Returns the index of the product which I have the least of in myInventory
     * I can't help but feel that this lacks object-oriented design...
     *
     * @return
     */
    protected int getLeastProduct() {
        int toReturn = 0;

        for (int index = 1; index < myInventory.length; index++) {
            toReturn = myInventory[index] < myInventory[toReturn] ? index : toReturn;
        }

        return toReturn;
    }

    /**
     * Returns the index of the product which I have the most of in myInventory
     * I can't help but feel that this lacks object-oriented design...
     *
     * @return
     */
    protected int getMostProduct() {
        int toReturn = 0;

        for (int index = 1; index < myInventory.length; index++) {
            toReturn = myInventory[index] > myInventory[toReturn] ? index : toReturn;
        }

        return toReturn;
    }

    /**
     * Returns an int[] containing the productivity of each product in
     * alphabetical order
     *
     * @param products
     * @return
     */
    protected int[] parseProducts(String products) {
        int[] toReturn;
        // Split the string so that each line of the array has #-P
        String[] lineProductivities = products.split(",");

        // Split each string in the array so that it is just the number
        for (int index = 0; index < lineProductivities.length; index++) {
            lineProductivities[index] = lineProductivities[index].split("-")[0];
        }

        toReturn = new int[lineProductivities.length];

        for (int index = 0; index < lineProductivities.length; index++) {
            toReturn[index] = Integer.parseInt(lineProductivities[index]);
        }

        return toReturn;
    }

    /**
     * Append my productivity string to the family billboard. If the file was
     * empty when I got here (contained no newlines), I am the boss! The boss
     * gives orders.
     *
     * @throws IOException
     * @throws InterruptedException
     */
    protected void initialSetup() throws IOException, InterruptedException {
        String input;
        myNumber = 0;
        FileChannel familyBillboardFC;
        Path billboardPath = FileSystems.getDefault().getPath("family_billboard.txt");
        FileLock billboardLock;
        byte[] argsByteArray;

        byte currentByte = 0;

        input = stdin.nextLine();

        // Open the file and lock it
        familyBillboardFC = FileChannel.open(billboardPath, StandardOpenOption.WRITE, StandardOpenOption.READ);
        billboardLock = familyBillboardFC.lock();

        // Map the contents of the file to a space in memory
        familyBillboard = familyBillboardFC.map(FileChannel.MapMode.READ_WRITE, 0, BILLBOARD_SIZE);

        // Convert the incoming string into an array of bytes
        argsByteArray = input.getBytes();

        for (int index = 0; index < BILLBOARD_SIZE; index++) {
            currentByte = familyBillboard.get();
            if (currentByte == NEW_LINE) {
                myNumber++;
                familyBillboard.mark();
            }
        }

        if (myNumber == 0) {
            familyBillboard.position(0);
            familyBillboard.mark();
        }
        familyBillboard.reset();

        for (byte b : argsByteArray) {
            familyBillboard.put(b);
        }
        familyBillboard.put(NEW_LINE);
        familyBillboard.put(EOF);

        billboardLock.release();

        Thread.sleep(100); // Give other programs a chance to launch

        // Boss needs to wait for awhile to make sure the others have finished
        // writing...
        // I don't have any idea how to do this in an intelligent fashion. It is
        // *probably* safe to sleep for a few hundred milliseconds, but I'm not
        // certain. Instead, I'll try to take out a new lock. If I succeed
        // twice, the file must be finished!
        int counter = 0;
        while (myNumber == 0) {
            billboardLock = familyBillboardFC.tryLock();
            if (billboardLock != null) {
                billboardLock.release();
                counter++;
            } else {
                counter = 0;
                Thread.sleep(10);
            }
            if (counter >= 2) {
                giveOrders();
                break;
            }
        }

        byte foo = familyBillboard.get();
        // Until the boss has written out the instructions, sleep
        while (foo < 65) {
            Thread.sleep(10);
            familyBillboard.reset();
            foo = familyBillboard.get();
        }

        familyBillboard.reset();
        myProduct = String.valueOf((char) familyBillboard.get());
    } // initialSetup()

    /**
     * Run by the boss. Tries to sort the family so that every product is
     * covered and so that whoever can produce the most of a product is
     * producing it. Writes the character code representing the product to
     * produce to the first character of the relevant line in the family
     * billboard.
     */
    protected void giveOrders() {
        final int MAX_LINE_LENGTH = 24;
        int numberMembers = 0;
        byte currentByte = 0;
        Integer[][] productivities; // Table of member's productivities
        char[] selections; // Who will make what. selections[#] = the production
                            // letter for member #

        familyBillboard.position(0);

        // I have seen the rules to these games change. It's easy for me to
        // accommodate more (or less than) 5 instances now. It may not be easy
        // later
        while (currentByte != EOF) {
            currentByte = familyBillboard.get();
            if (currentByte == NEW_LINE) {
                numberMembers++;
            }
        }
        currentByte = 0;
        familyBillboard.reset();

        selections = new char[numberMembers];

        productivities = new Integer[numberMembers][NUMBER_PRODUCTS];

        for (int index = 0; index < numberMembers; index++) {
            byte[] currentLineBytes = new byte[MAX_LINE_LENGTH];
            String currentLine;

            // Read the next line
            for (int jdex = 0; jdex < currentLineBytes.length; jdex++) {
                currentByte = familyBillboard.get();
                if (currentByte == NEW_LINE) {
                    break;
                }
                currentLineBytes[jdex] = currentByte;
            }
            currentLine = new String(currentLineBytes);
            currentByte = 0;

            int[] lineProductivities = parseProducts(currentLine);

            // Need to iterate to get the int[] to Integer[]
            for (int jdex = 0; jdex < NUMBER_PRODUCTS; jdex++) {
                productivities[index][jdex] = lineProductivities[jdex];
            }

        }

        // If there are at least as many producers as products, select the most
        // productive for each producer. If there are overlaps, move the smaller
        // one to the second most productive and re-check for overlaps. If there
        // are overlaps and the productivity is tied, compare the second highest
        // and so on.
        // TODO What if members > 5?
        if (numberMembers <= NUMBER_PRODUCTS) {
            int[] overlapResult;
            for (int index = 0; index < selections.length; index++) {
                selections[index] = (char) (maxInArray(productivities[index]) + 65);
                // Can convert from a max value in productivities to a
                // human-readable character by adding 65, since 0 -> A, 1 -> B,
                // etc.
            }

            int counter = 0; // I imagine there is a possibility of this loop
                                // not terminating. I will use this counter to
                                // forcefully break it.

            // While there is an overlap
            while ((overlapResult = arrayHasOverlaps(selections)) != null && overlapResult[0] != -1) {
                byte productIndex = (byte) (selections[overlapResult[0]] - 65);
                // 0 through the number of production options, where A = 0, B =
                // 1, etc.
                if (productivities[overlapResult[0]][productIndex] > productivities[overlapResult[1]][productIndex]) {
                    int index = findNextHighestFromIndex(productivities[overlapResult[1]], productIndex);
                    selections[overlapResult[1]] = (char) (index + 65);
                }
                if (productivities[overlapResult[1]][productIndex] > productivities[overlapResult[0]][productIndex]) {
                    int index = findNextHighestFromIndex(productivities[overlapResult[0]], productIndex);
                    selections[overlapResult[0]] = (char) (index + 65);
                }
                // Things are beginning to get mega hairy
                if (productivities[overlapResult[0]][productIndex] == productivities[overlapResult[1]][productIndex]) {
                    int index0 = findNextHighestFromIndex(productivities[overlapResult[0]], productIndex);
                    int index1 = findNextHighestFromIndex(productivities[overlapResult[1]], productIndex);
                    if (productivities[overlapResult[0]][index0] > productivities[overlapResult[1]][index1]) {
                        selections[overlapResult[0]] = (char) (index0 + 65);
                    } else {
                        // I can't be bothered to go any further with this... If
                        // they're tied here, then to heck with it!
                        selections[overlapResult[1]] = (char) (index1 + 65);
                    }
                }

                counter++;
                if (counter > BILLBOARD_SIZE) {
                    break;
                }
            }
        }

        // Check for less than my minimum cutoff. If one is, set it to its max.
        for (int index = 0; index < selections.length; index++) {
            byte b = (byte) (selections[index] - 65);
            if (productivities[index][b] < MIN_PRODUCTION_CUTOFF) {
                selections[index] = (char) (maxInArray(productivities[index]) + 65);
            }
        }

        // Write the product to produce to the correct line
        familyBillboard.position(0);
        familyBillboard.put((byte) selections[0]);
        // If we find a newline, write the selected character to the next
        // spot. Otherwise, read the next character
        for (int index = 1; index < selections.length;) {
            byte thisByte = familyBillboard.get();
            if (thisByte == NEW_LINE) {
                familyBillboard.put((byte) selections[index]);
                index++;
            }
        }
    }

    /**
     * Look through the array. Find an element that is either later in the array
     * and <= the value at the incoming index and > the value at the toReturn
     * index, or earlier in the array and < the value at the current index and >
     * the value at toReturn. If we weren't able to set the new index (Maybe we
     * are already at the max value) return the index of the largest value
     *
     * @param array
     *            the array to search in
     * @param incomingIndex
     *            the index of the value to begin searching with
     * @return an index as described
     */
    protected int findNextHighestFromIndex(Integer[] array, int incomingIndex) {
        int toReturn = incomingIndex;
        int comparisonValue = -1; // The value at toReturn
        int index = (incomingIndex + 1) % array.length;

        for (int counter = 0; counter < array.length; counter++) {
            if (index > incomingIndex && array[index] == array[incomingIndex]) {
                // If we have found an equal value later in the array, return
                // immediately. In the unlikely event everything is equal,
                // don't just take the value at the bottom index!
                return index;
            }
            if (index > incomingIndex && array[index] < array[incomingIndex] && array[index] > comparisonValue) {
                toReturn = index;
                comparisonValue = array[toReturn];
            }
            if (index < incomingIndex && array[index] < array[incomingIndex] && array[index] > comparisonValue) {
                toReturn = index;
                comparisonValue = array[toReturn];
            }

            index++;
            index %= array.length; // How often do you get to use %= ?
        }

        if (comparisonValue == -1) {
            // In the unlikely event we weren't able to set comparisonValue
            // (maybe we are already at the minimum?)
            toReturn = maxInArray(array);
            // This will probably contribute to those endless loops I mentioned
            // above!
        }

        return toReturn;
    }

    /**
     * Checks the array for any two elements being the same. If two are, return
     * the indices. If not, return {-1, -1}
     *
     * @param selections
     *            The array to examine
     * @return Indices of the overlapping elements or {-1, -1}
     */
    protected int[] arrayHasOverlaps(char[] selections) {
        int[] toReturn = new int[] { -1, -1 };
        for (int index = 0; index < selections.length - 1; index++) {
            for (int jdex = index + 1; jdex < selections.length; jdex++) {
                if (selections[index] == selections[jdex]) {
                    toReturn[0] = index;
                    toReturn[1] = jdex;
                    return toReturn;
                }
            }
        }
        return toReturn;
    }

    /**
     * Returns the index of the max value of an array. In the case of a tie,
     * returns the earliest index.
     *
     * @param array
     *            the array to read
     * @return the index of the largest element in the array
     */
    protected <T extends Comparable<T>> byte maxInArray(T[] array) {
        byte currentMax = 0;
        for (byte index = 0; index < array.length; index++) {
            currentMax = array[index].compareTo(array[currentMax]) > 0 ? index : currentMax;
        }
        return currentMax;
    }
}

command.txt
cd bots/family_farmer && java FamilyFarmers

It can be compiled with
javac FamilyFarmer.java

There should also be another blank file, family_billboard.txt, in the bots/family_farmer folder.

If you got RandomAndo from github, it's current state works fine for me.

Also, it is definitely within the rules for your own bot to work with itself (across instances).  However, you won't always be matched up with them during trading

Hmm. I just checked out the latest and took my bot out. Random Ando is no longer spitting up errors, but I get absolutely no output from the program either way... With my bot in, it at least tells me that is is sending the original productivities to my bot!
I know Python 2.6.6 is a bit old. What version are you using?

2.7.6  I'm getting an error from your bot, you need to send what you want to produce first, and then (on the next line) what you would accept.

Ah. My misunderstanding. Happily, a one line hackey fix (line 199) :)

Ok.  There need to be some more fixes.  If there is anything in the family billboard file, it doesn't run.  Furthermore, I've noticed that the first item in the billboard starts with a letter, not a number.

Heh. That was silly of me. Assuming a clean exit every time, the program would empty its billboard file. Perhaps not a good assumption. I have added a shutdown hook so that it will empty the billboard as the JVM is going down -- The Boss changes the first number to a letter to let the other processes know what to produce. The line has already been ingested.

Ok.  There is still a problem with the code.  When you say you want to sell something, you need to provide two different lines of output:  The first describes 1 product that you want to sell, the second is a list of multiple products that you are willing to accept.  I'm still getting a list of products for the single item you are trying to sell.

Could you provide an example of the input/output you are using and seeing? I don't understand the problem.

With a single bot: http://pastebin.com/SM1MJKY6

Okay. My mistake again. I have now solidly verified that it prints the sell offer on its own line. I also moved some other lines around, so please re-download everything.

Another issue.  When you decide to purchase, you don't print the item you decide to purchase: http://pastebin.com/tUj0yqvH

Hmm. I thought I had already updated that. It works on my local file! It was related to the problem I was having with selling, because I wasn't looking for inputs on a separate line. I updated the submission to be exactly my local file.

This time, the bot doesn't respond.  (It prints a product twice, then doesn't print anything) http://pastebin.com/f8vEceG4

Introvert - Java
This bot is so introverted, it would rather die than talk to anyone in trading, so it immediately leaves market if it is there. However, it doesn't want to die so it tries to keep its supplies up as long as possible.
Introvert.java
import java.util.Scanner;

public class Introvert{

    static int[] current = {10,10,10,10,10};
    static int[] potentialProduction = new int[5];
    static boolean alive = true;

    public static void main(String[] args){
        Scanner s = new Scanner(System.in);
        String input = s.nextLine();
        String[] inputArray = input.split(",");
        for(int i = 0; i < 5; i++){
            potentialProduction[i] = Integer.parseInt(inputArray[i].replaceAll("\\D+",""));
        }

        while(alive){
            int pos = decideProduction();
            produce(pos);
            System.out.println("L");
            for(int i = 0; i < 5; i++){
                current[i] -= 2;
                if(current[i] < 0)
                    alive = false;
            }
        }
        s.nextLine(); //read final `q` message
    }

    public static int decideProduction(){
        int lowestPotential = 9999;
        int lowestPotentialPosition = 9999;
        for(int i = 0; i < 5; i++){
            if(current[i] == 2 || current[i] == 3){
                lowestPotentialPosition = i;
                break;
            }
            int potential = current[i] + potentialProduction[i];
            if(potential < lowestPotential){
                lowestPotential = potential;
                lowestPotentialPosition = i;
            }
        }
        switch(lowestPotentialPosition){
            case 0: System.out.println("A"); return 0;
            case 1: System.out.println("B"); return 1;
            case 2: System.out.println("C"); return 2;
            case 3: System.out.println("D"); return 3;
            case 4: System.out.println("E"); return 4;
            default: System.out.println("A"); return 0;
        }
    }

    public static void produce(int pos){
        current[pos] += potentialProduction[pos];
    }

}

command.txt
java Introvert

Compile with
javac Introvert.java

Note: I did this on my lunch break and my work computer doesn't have the jdk or python so I have not been able to test it at all. If it does not work let me know and I will try to fix it.

Introvert.java:47: error: missing return statement

@NathanMerrill added a default case to fix that, and made some other small changes to fix a bug I noticed.
Hopefully should work now, will install python to test it in a bit.

Introvert.java:18: cannot find symbol rounds ++;

Ok, I didn't see you using rounds anywhere, so I removed it...no working on another error..not sure if it is your fault or mine.

Ok.  Things are working now.  I removed all of your while(true) loops, and I have your program accepting input at the very end (to accept my q message).  Your modified code is on github (with the main project)

@NathanMerrill thanks for fixing it. And I apologize if not trading wasn't really in the spirit of the question.

Ah, no, its a valid bot.  It actually marks a good line (if you are above your bot, then you actually traded at an advantage)

Random Ando
Every KOTH should have a random bot. Coded, hopefully, so that it won't make invalid deals (like trying to sell more than what it has in stock).
--RandomAndo

math.randomseed(os.time()) math.random()math.random()math.random()

ITEMS = {"A", "B", "C","D", "E"}
MARKETOPTION = {"P", "S"}
MyGoods = {0,0,0,0,0}

local function readline() -- checks for the dying "Q" or just reads line
    local line = io.read("*l")
    if line == "Q" then
        os.exit()
    end

    return line
end

local function getCurrentTurn() -- asks for M,T,P
    print("T")
    return readline()
end

local function getRandom(array) -- returns for a random element in array
    local r=math.random(#array)
    return array[r]
end

local function getRandomMyItems() -- make a list of items I have and return a random one (no more than one of)
    local rgood=math.random(5)
    local amount=1
    while MyGoods[rgood] <= 0 do
        rgood=math.random(5)
    end
    return amount.."-"..ITEMS[rgood]
end

local function parseGoods(goodString) -- specialized to getMyGoods atm
    local goods={0,0,0,0,0}
    local c = 1
    example = "5-A,6-B,3-C,12-D,4-E"
    for good in goodString:gmatch("%d+%p[ABCDE]") do
        goods[c]=goods[c]+good:match("%d+")
        c=c+1
    end

    return goods
end

local function getMyGoods() -- asks for my goods
    print("G")
    local temp = parseGoods(readline())
    for i=1,5 do
        MyGoods[i]=temp[i]
    end
end

productivity = readline() -- doesn't matter

while true==true do

    print(getRandom(ITEMS)) -- produce random item

    while getCurrentTurn()=="M" do
        getMyGoods()

        local action=getRandom(MARKETOPTION) -- make a random market decision
        if action == "S" then -- offer to sell 1 of a random item I  have in stock, will take any 2 offered
            print("S")
            if readline()=="T" then
                print(getRandomMyItems())
                print("2-A,2-B,2-C,2-D,2-E")
            end
        elseif action == "P" then -- if I can do the deal, I will
            print("P")
            if readline()=="T" then
                local offered=readline()
                local accepted =readline()
                local taccepted={}
                for i in accepted:gmatch("%d+%p[ABCDE]") do
                    oitem =i:match("[ABCDE]")
                    oamount = i:match("%d+")
                    for k=1,5 do
                        if ITEMS[k]==oitem and MyGoods[k]>=tonumber(oamount) then
                            table.insert(taccepted, oitem)
                        end
                    end
                    if #taccepted>=1 then
                        print(getRandom(taccepted))
                    else
                        print("X")
                    end
                end
            end
        elseif action == "L" then
            print("L")
        end
    end
end

command.txt should be:
lua RandomAndo.lua

What's the command.txt supposed to look like?

@NathanMerrill yep, sorry, added to the bottom.

I'm running into problems running your bot from my controller: "The system cannot find the file specified".  However, while I'm trying to get that working, your program doesn't work--When I run it from the command line, I get: bad argument #1 to 'randomseed' (number expected, got no value) on line 3

@NathanMerrill Dumb mistake. Fixed.

Ok.  It looks like your code is now running, and I got it fixed on my end...but now I'm not getting any output from your program (maybe it's not getting my output, I'm not sure)  Anyways, I'll attempt to fix it tomorrow, I need to sleep.

@NathanMerrill Might just have been that I still had errors in the code. I made a couple more changes, so, hopefully, fingers crossed.

Ok, I got the piping working.  You have more bugs...all of your output should be in the form of A-1, while you have it as 1-A

Nevermind...my program doesn't match the spec.  I will update my program.

authors: มาลินี สูทอก


text:
Domino Circuits
Scoreboard
Here are the raw scores (i.e. domino counts) for VisualMelon's submission. I'll turn these into the normalised scores described below, when more answers come in. The existing solution can now solve all circuits in the benchmark:
 Author       Circuit:   1   2   3   4    5    6   7    8   9  10  11  12   13  14   15   16   17   18  19   20   21  22   23   24    25   26   27   28    29    30    31    32   33   34    35    36     37      38   39
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
VisualMelon             39  45  75  61  307  337  56  106  76  62  64  62  182  64  141  277  115  141  92  164  223  78  148  371  1482  232  107  782  4789  5035  1314  3213  200  172  1303  3732  97596  156889  857
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  I - invalid circuit
  B - circuit too big
  W - circuit computes wrong function
  T - exceeded time limit

The Challenge
It is possible to build simple logic gates from dominoes. Hence, by combining these or otherwise, arbitrary binary functions can be computed with dominoes.
But of course, everyone who has played with dominoes (except Robin Paul Weijers) has experienced the disappointment when running out of them. Hence, we want to use our dominoes as efficiently as possible, so we can do some really interesting computations with the material we have.
Note, that you cannot produce non-zero output from zero input per se, so we'll need to add a "power line", which falls along your setup, and which you can pull 1s from at any time.
Your task
Given a boolean function with M inputs and N outputs (f: {0,1}^M --> {0,1}^N for the mathematically inclined), produce a domino circuit with as few dominoes as possible which computes that function. You'll be using the symbols |, -, /, \ to represent dominoes in various orientations.
Input
You'll be given input via command-line arguments:
[command for your solver] M N f

where M and N are positive integers and f is the comma separated truth table in canonical order. That is, f will contain 2^M values of length N. E.g. if M = N = 2 and the first bit in the output was the AND function while the second bit was the OR function, f would read
00,01,01,11

Output
Write to STDOUT an ASCII grid representing the domino setup. Your setup has to fit in the following framework
/////.../////
 ????...????
I????...????O
I????...????O
.............
.............
I????...????O
I????...????O
I????...????O

The top row consists entirely of /, and the leftmost domino is guaranteed to be toppled over at the beginning - this is your power line.
The leftmost column consists of your inputs. Each I may either be a space or a |, such that there are exactly M |s.
The rightmost column consists of your outputs. Each O may either be a space or a |, such that there are exactly N |s.
Note that there is at least one blank before the first | in the input or output.
The . indicate that the grid can be arbitrarily large.
You can fill ? in any way you want.

Note that the bottom input is the fastest-varying while you go along the truth table, while the top input is the 0 for the first half of the outputs and 1 for the second half.
Rules
Dominoes propagate as specified in Golfing for Domino Day. In short, if we represent the falling directions as letters
Q W E
A   D
Z X C

then these are all unique combinations which can propagate (as well as their rotations and reflections):
D|   ->    DD          D\   ->    DE          D/   ->    DC

C|   ->    CD          C/   ->    CC

C    ->    C           C    ->    C           C    ->    C
 |          D           -          X           /          C

All of the above rules are applied simultaneously at each time step. If two of those rules are in conflict (i.e. a tile is pushed into two valid opposite directions at the same time), the affected tile will not fall, and will effectively be locked into position for the rest of the simulation.
Restrictions

M and N will never exceed 6.
Your solver must produce a circuit within N * 2M seconds.
Your solver must not use more than 1 GB of memory. This is a soft limit, as I will be monitoring this manually and kill your process if it significantly/continuously exceeds this limit.
No circuit is permitted to contain more than 8,000,000 cells or 1,000,000 dominoes.
Your submission must be deterministic. You are allowed to use pseudo-random number generators, but they must use a hardcoded seed (which you are free to optimise as much as you care to).

Scoring
For each circuit, let D be total number of dominoes in your circuit and B the lowest number of dominoes this circuit has been solved with (by you or any other participant). Then your score for this circuit is given by 10,000 * B / D rounded down. If you failed to solve the circuit, your score is 0. Your overall score will be the sum over a benchmark set of test cases. Circuits that have not yet been solved by anyone will not be included in the total score.
Each participant may add one test case to the benchmark (and all other submissions will be re-evaluated including that new test case).
The benchmark file can be found on GitHub.
Examples
Here are some non-optimally solved examples.
Constant 1
1 1
1,1

///////
   /
|   |||

Domino count: 12
OR gate
2 1
0,1,1,1

///////////

|||||/
      |||||
|||||\

Domino count: 28
AND gate
2 1
0,0,0,1

///////////////////

       \-/
       - -
|||||/|\ /|||/
      /      -
       -    \-
      \-   \ -
|||||\ /  \  /
        |\    |||||

Domino count: 62
Swap lanes
2 2
00,10,01,11

////////////

||||/  \||||
     /\
     \/
||||\  /||||

Domino count: 36
Additional Notes
The propagation rules are such, that diagonal lanes can cross using a diamond shape (see last example) even if one falls before the other (unlike with real dominoes).
As a starting point, you can use the (not minimised) logical gates in this gist and try combining as few of these as possible. For a simple (non-optimal) way to build arbitrary boolean functions from AND, OR and NOT gates, have a look at Conjunctive and Disjunctive Normal Forms.
There is a verifier this GitHub repository to test your code, which will also be used to score all submissions. This outputs the raw scores (domino counts) and saves them to a file to be processed by a separate scorer (also in that repository) to obtain the final scores.
General documentation can be found within the two Ruby files, but the controller.rb takes two command line switches before the benchmark file:

-v gives you some more output, including the actual circuits produced by your solver.
-c lets you select a subset of the benchmark you want to test. Provide the desired circuits as a comma-separated list of 1-based indices. You can also use Ruby ranges, so you could do something like -c 1..5,10,15..20.

Please include in your answer:

Your code
A command to (compile and) run  your code. I'll ask you where to obtain the necessary compilers/interpreters if I don't have them.
An additional truth table with a name, to be added as a test case to the benchmark. (This is optional, but strongly encouraged.)

I'll be testing all submissions on Windows 8.

All pushed at same time?

@l4m2 Yes, the inputs in the left-most column are toppled simultaneously.

C# - Massive, Slow, and inefficient solution
Confession: wrote this solution some time ago when the question was still in the sandbox, but it's not very good: you can do better!
Edit: replaced the boring solving with a less boring, more flexible, and generally better method
You run the program by compiling with csc dominoPrinter.cs and then passing arguments to the executable, for example (the 4-bit prime checker):
dominoPrinter.exe 4 1 0,0,1,1,0,1,0,1,0,0,0,1,0,1,1,1

Explanation:
The "Domino Printer" is a 3-stage program:
Stage 1: The "solver" generates an expression tree of "ifnot" and "or" binary operations with the given inputs, and a "1" from the powerline, there are 2ways this is done, depending on the number of inputs:

If there are fewer than 4 inputs the program brutes a solution of the fewest number of operations
If there are 4 or more inputs the program brutes each 8bit chunk of output and then combines the results to give the desired output. The bruted bits if flexible: the more bruted bits, the smaller the solution, but the longer the run-time.

The "solver" is what takes all the time (or at least it used to), and is also most of the code. I believe there is a well documented, fast, not so memory hungry, and probably optimal solution to this problem, but where would the fun be in looking it up?
The (bruted) expression tree for the 4-bit prime checker is
((2 or 1) ifnot (((0 ifnot 1) or ((1 ifnot 0) or (0 ifnot 2))) ifnot 3))

where the numbers are the indexes of the inputs.
Stage 2: The "organizer" takes the expression tree as input and assembles a "skeleton" layout, which precisely describes a domino layout made from some a set of 4x5 overlapping cells. Below is the skeleton for the bruted 4-bit prime checker (you'll need to change the bruteBase integer variable on line 473 to 4 (or larger) to get this result).
18 9
I ___ _ _______  O
 v _ X X ____  uu
I X X X u    UU/
 v X X v ___///
I X X \ u   //
 v X \ v __//
I_X \ \_u  /
   \ \ ___/
    \_U

This output is effectively made up to two parts, the "evaluator" on the right, which is created from the expression tree from stage 1, and the "switchboard" on the left, which swaps and splits the inputs so that they arrive in the right places for the "evaluator" to handle.
There is considerable scope for compacting the layout at this point, but the program currently does very little such work. The code for this stage is horrible, but pretty simple underneath (see the "orifnot" method). The output is passed to stage 3.
Stage 3: The "printer" takes the output from the "organizer" and prints the corresponding 4x5 overlapping "cells" along with the power line. Below is an animation of the bruted 4-bit prime checker checking whether 5 is prime.

Code the lack of indenting is to avoid going over the SE 30k character limit which it would otherwise:
using System;
using System.Collections.Generic;

namespace dominoPrinter
{
 class Program
 {
  static string bstring(bool[] barr)
  {
   string str = "";
   foreach (bool b in barr)
    str += b?1:0;
   return str;
  }

  public static void Main(string[] args)
  {

   int inputCount;
   val[] vals = resolveVals(args[0], args[1], args[2], out inputCount);

   System.IO.StringWriter sw = new System.IO.StringWriter();
   orifnot(inputCount, vals, sw);
   System.IO.StringReader sr = new System.IO.StringReader(sw.ToString());

   printDominoes(sr, Console.Out, args.Length > 3 && args[3] == "quite");
  }

  public abstract class val
  {
   public int size;
   public bool[] rs;
   public abstract string strness();
  }

  public class baseVal : val
  {
   public bool b;
   public int id;

   public baseVal(int idN)
   {
    id = idN;
    size = 1;
   }

   public override string strness()
   {
    return id.ToString();
   }
  }

  public abstract class biopVal : val
  {
   public val a, b;

   public biopVal(val aN, val bN)
   {
    a = aN;
    b = bN;
    size = a.size + b.size;
   }

   public bool buildCheckApply(nodev ntree)
   {
    nodev cur = ntree;
    rs = new bool[a.rs.Length];
    bool notOK = true;
    for (int i = 0; i < rs.Length; i++)
    {
     bool r = rs[i] = go(a.rs[i], b.rs[i]);
     if (notOK)
     {
      if (r)
      {
       if (cur.a == null)
        notOK = false;
       else
       {
        cur = cur.a;
        if (cur == nodev.full)
         return false;
       }
      }
      else
      {
       if (cur.b == null)
        notOK = false;
       else
       {
        cur = cur.b;
        if (cur == nodev.full)
         return false;
       }
      }
     }
    }

    ntree.apply(this, 0);
    return true;
   }

   public abstract bool go(bool a, bool b);
  }

  public class ifnotVal : biopVal
  {
   public override bool go(bool a, bool b)
   {
     return a ? false : b; // b IF NOT a, else FALSE
   }

   public ifnotVal(val aN, val bN) : base(aN, bN)
   {
   }

   public override string strness()
   {
    return "(" + b.strness() + " ifnot " + a.strness() + ")";
   }
  }

  public class orval : biopVal
  {
   public override bool go(bool a, bool b)
   {
    return a || b; // a OR b
   }

   public orval(val aN, val bN) : base(aN, bN)
   {
   }

   public override string strness()
   {
    return "(" + b.strness() + " or " + a.strness() + ")";
   }
  }

  static bool boolCompare(bool[] a, bool b)
  {
   for (int i = 0; i < a.Length; i++)
   {
    if (a[i] != b)
    {
     return false;
    }
   }
   return true;
  }

  static bool boolFlat(bool[] a)
  {
   bool p = a[0];
   for (int i = 1; i < a.Length; i++)
   {
    if (a[i] != p)
     return false;
   }
   return true;
  }

  static bool boolCompare(bool[] a, bool[] b)
  {
   if (a.Length != b.Length)
    return false; // let's do this proeprly
   for (int i = 0; i < a.Length; i++)
   {
    if (a[i] != b[i])
    {
     return false;
    }
   }
   return true;
  }

  // solver

  // these is something VERY WRONG with the naming in this code
  public class nodev
  {
   public static nodev full = new nodev();

   public nodev a, b;

   public nodev()
   {
    a = null;
    b = null;
   }

   public bool contains(bool[] rs)
   {
    nodev cur = this;
    if (cur == full)
     return true;

    for (int i = 0; i < rs.Length; i++)
    {
     if (rs[i])
     {
      if (cur.a == null)
       return false;
      cur = cur.a;
     }
     else
     {
      if (cur.b == null)
       return false;
      cur = cur.b;
     }

     if (cur == full)
      return true;
    }
    return true;
   }

   public bool contains(val v)
   {
    nodev cur = this;
    if (cur == full)
     return true;

    for (int i = 0; i < v.rs.Length; i++)
    {
     if (v.rs[i])
     {
      if (cur.a == null)
       return false;
      cur = cur.a;
     }
     else
     {
      if (cur.b == null)
       return false;
      cur = cur.b;
     }

     if (cur == full)
      return true;
    }
    return true;
   }

   // returns whether it's full or not
   public bool apply(val v, int idx)
   {
    if (v.rs[idx])
    {
     if (a == null)
     {
      if (idx == v.rs.Length - 1)
      { // end of the line, fellas
       a = full;
       if (b == full)
        return true;
       return false;
      }
      else
      {
       a = new nodev();
      }
     }
     if (a.apply(v, idx + 1))
      a = full;
     if (a == full && b == full)
      return true;
    }
    else
    {
     if (b == null)
     {
      if (idx == v.rs.Length - 1)
      { // end of the line, fellas
       b = full;
       if (a == full)
        return true;
       return false;
      }
      else
      {
       b = new nodev();
      }
     }
     if (b.apply(v, idx + 1))
      b = full;
     if (a == full && b == full)
      return true;
    }
    return false;
   }
  }

  public static void sortOutIVals(baseVal[] ivals, int rc)
  {
   for (int i = 0; i < ivals.Length; i++)
   {
    ivals[i].rs = new bool[rc];
    ivals[i].b = false;
   }

   int eri = 0;

   goto next;
  again:
   for (int i = ivals.Length - 1; i >= 0; i--)
   {
    if (ivals[i].b == false)
    {
     ivals[i].b = true;
     goto next;
    }
    ivals[i].b = false;
   }

   return;
  next:
   for (int i = ivals.Length - 1; i >= 0; i--)
   {
    ivals[i].rs[eri] = ivals[i].b;
   }

   eri++;
   goto again;
  }

  public static val[] resolve(int inputCount, int c, bool[][] erss, out baseVal[] inputs)
  {
   val[] res = new val[erss.Length];

   List<List<val>> bvals = new List<List<val>>();
   nodev ntree = new nodev();

   List<val> nvals = new List<val>();

   baseVal tval = new baseVal(-1);
   baseVal fval = new baseVal(-2);
   baseVal[] ivals = new baseVal[inputCount];
   inputs = new baseVal[inputCount + 2];

   for (int i = 0; i < inputCount; i++)
   {
    ivals[i] = new baseVal(i); // value will change anyway
    inputs[i] = ivals[i];
   }
   inputs[inputCount] = fval;
   inputs[inputCount + 1] = tval;

   sortOutIVals(ivals, c);

   for (int i = 0; i < inputCount; i++)
   {
    nvals.Add(ivals[i]);
   }

   tval.rs = new bool[c];
   fval.rs = new bool[c];
   for (int i = 0; i < c; i++)
   {
    tval.rs[i] = true;
    fval.rs[i] = false;
   }

   nvals.Add(tval);
   nvals.Add(fval); // ifnot and or do nothing with falses

   bvals.Add(new List<val>());

   foreach (val v in nvals)
   {
    ntree.apply(v, 0);
    if (!boolFlat(v.rs))
     bvals[0].Add(v); // I trust these are distinct..
   }

   Func<biopVal, bool> checkValb = (v) =>
   {
    if (!v.buildCheckApply(ntree))
    {
     return false;
    }
    bvals[v.size-1].Add(v);
    return true;
   };

   Action<biopVal, List<val>> checkVal = (v, li) =>
   {
    if (checkValb(v))
     li.Add(v);
   };

   int maxSize = 1;

  again:
   for (int i = 0; i < erss.Length; i++)
   {
    bool[] ers = erss[i];
    if (res[i] == null && ntree.contains(ers))
    {
     // there is a reason this is separate... I'm sure there is....
     foreach (val rv in nvals)
     {
      if (boolCompare(rv.rs, ers))
      {
       res[i] = rv;
       break;
      }
     }
    }
   }

   for (int i = 0; i < erss.Length; i++)
   {
    if (res[i] == null)
     goto notoveryet;
   }
   return res;

  notoveryet:

   maxSize++;
   bvals.Add(new List<val>()); // bvals[maxSize-1] always exists

   nvals.Clear();
   long cc = 0;

   List<val> sbvals = bvals[maxSize - 2];
   // NOTs have a habit of working out, get it checked first
   for (int i = sbvals.Count - 1; i >= 0; i--)
   { // also known as nvals, but let's ignore that
    val arv = sbvals[i];
    checkVal(new ifnotVal(arv, tval), nvals);
    cc += 1;
   }

   for (int s = 1; s < maxSize; s++)
   {
    List<val> abvals = bvals[s - 1];
    int t = maxSize - s;
    if (t < s)
     break;
    List<val> bbvals = bvals[t - 1];

    for (int i = abvals.Count - 1; i >= 0; i--)
    {
     val arv = abvals[i];

     int jt = t == s ? i : bbvals.Count - 1;
     for (int j = jt; j >= 0; j--)
     {
      val brv = bbvals[j];

      checkVal(new ifnotVal(brv, arv), nvals);
      checkVal(new ifnotVal(arv, brv), nvals);
      checkVal(new orval(brv, arv), nvals); // don't technically need ors, but they are good fun
      cc += 3;
     }
    }
   }

   int bc = 0;
   foreach (List<val> bv in bvals)
    bc += bv.Count;
   goto again;
  }

  public static val[] resolveVals(string mStr, string nStr, string erStr, out int inputCount)
  {
   int ic = int.Parse(mStr);
   int oc = int.Parse(nStr);
   inputCount = ic;
   int bruteBase = 3;
   if (inputCount <= bruteBase)
    return resolveVals(ic, oc, erStr);
   else
    return resolveValFours(bruteBase, ic, oc, erStr);
  }

  public static val joinVals(val low, val high, baseVal inp, baseVal tval, baseVal fval)
  {
   val lowCut = low == fval ? (val)fval : low == tval ? (val)new ifnotVal(inp, tval) : (val)new ifnotVal(inp, low);

   val highCut = high == fval ? (val)fval : high == tval ? (val)inp : (val)new ifnotVal(new ifnotVal(inp, tval), high);

   if (highCut == fval)
    return lowCut;
   if (lowCut == fval)
    return highCut;
   return new orval(highCut, lowCut);
  }

  public static val resolveValFour(int n, int m, int inputCount, bool[] ers)
  {
   // solves fours
   int fc = ers.Length / m;
   bool[][] fours = new bool[fc][];

   for (int i = 0; i < fc; i++)
   {
    fours[i] = new bool[m];
    for (int j = 0; j < m; j++)
    {
     fours[i][j] = ers[i*m+j];
    }
   }

   baseVal[] inputs;
   val[] fres = resolve(n, m, fours, out inputs);
   baseVal tval = inputs[inputs.Length - 1];
   baseVal fval = inputs[inputs.Length - 2];

   for (int i = 0; i < n; i++)
   {
    inputs[i].id += inputCount - n;
   }

   // assemble
   for (int i = 0, c = 1; c < fc; c *= 2, i++)
   {
    for (int j = 0; j + c < fc; j += c * 2)
    {
     fres[j] = joinVals(fres[j], fres[j+c], new baseVal((inputCount - n - 1) - i), tval, fval);
    }
   }

   return fres[0];
  }

  public static val[] resolveValFours(int n, int inputCount, int outputCount, string erStr)
  {
   int m = 1;
   for (int i = 0; i < n; i++)
    m *= 2;

   val[] res = new val[outputCount];

   string[] data = erStr.Split(',');
   for (int i = 0; i < outputCount; i++)
   {
    bool[] ers = new bool[data.Length];
    for (int j = 0; j < data.Length; j++)
     ers[j] = data[j][i] == '1';
    res[i] = resolveValFour(n, m, inputCount, ers);
   }

   return res;
  }

  public static val[] resolveVals(int inputCount, int outputCount, string erStr)
  {
   val[] res;

   string[] data = erStr.Split(',');
   bool[][] erss = new bool[outputCount][];
   for (int i = 0; i < outputCount; i++)
   {
    bool[] ers = new bool[data.Length];
    for (int j = 0; j < data.Length; j++)
     ers[j] = data[j][i] == '1';
    erss[i] = ers;
   }

   baseVal[] inputs; // no need
   res = resolve(inputCount, data.Length, erss, out inputs);

   return res;
  }

  // organiser
  public class vnode
  {
   private static vnode[] emptyVC = new vnode[0];
   public static vnode oneVN = new vnode('1');
   public static vnode noVN = new vnode(' ');
   public static vnode flatVN = new vnode('_');
   public static vnode moveUpVN = new vnode('/');
   public static vnode moveDownVN = new vnode('\\');
   public static vnode inputVN = new vnode('I');
   public static vnode outputVN = new vnode('O');
   public static vnode swapVN = new vnode('X');
   public static vnode splitDownVN = new vnode('v');

   public int size;
   public vnode[] children;
   public char c;
   public int id = -3;

   public vnode(char cN)
   {
    c = cN;
    children = emptyVC;
    size = 1;
   }

   public vnode(val v)
   {
    biopVal bv = v as biopVal;

    if (bv != null)
    {
     children = new vnode[2];
     children[0] = new vnode(bv.a);
     children[1] = new vnode(bv.b);
     size = children[0].size + children[1].size;

     if (bv is orval)
      c = 'U';
     if (bv is ifnotVal)
      c = 'u';
    }
    else
    {
     children = emptyVC;
     size = 1;
     c = 'I';
     id = ((baseVal)v).id;
    }
   }
  }

  public class nonArray<T>
  {
   public int w = 0, h = 0;
   Dictionary<int, Dictionary<int, T>> map;

   public nonArray()
   {
    map = new Dictionary<int, Dictionary<int, T>>();
   }

   public T this[int x, int y]
   {
    get
    {
     Dictionary<int, T> yd;
     if (map.TryGetValue(x, out yd))
     {
      T v;
      if (yd.TryGetValue(y, out v))
      {
       return v;
      }
     }
     return default(T);
    }
    set
    {
     if (x >= w)
      w = x + 1;
     if (y >= h)
      h = y + 1;
     Dictionary<int, T> yd;
     if (map.TryGetValue(x, out yd))
     {
      yd[y] = value;
     }
     else
     {
      map[x] = new Dictionary<int, T>();
      map[x][y] = value;
     }
    }
   }
  }

  public static int fillOutMap(nonArray<vnode> map, vnode rn, int y, int x)
  {
   if (rn.children.Length == 0)
   {
    map[y,x] = rn;
    return 1;
   }
   else
   {
    map[y+1,x] = rn;
    for (int i = 0; i < rn.children.Length; i++)
    {

     if (i == 0)
     {
      fillOutMap(map, rn.children[i], y, x + 1);
     }

     if (i == 1)
     {
      int ex = x + rn.children[0].size;
      for (int j = 1; j < ex - x; j++)
       map[y - j + 1,ex - j] = vnode.moveUpVN;
      fillOutMap(map, rn.children[i], y, ex);
     }

     y += rn.children[i].size;
    }
   }

   return rn.size;
  }

  public static void orifnot(int inputCount, val[] vals, System.IO.TextWriter writer)
  {
   // step one - build weird tree like thing of death
   nonArray<vnode> map = new nonArray<vnode>();

   int curY = 0;
   foreach (val v in vals)
   {
    vnode vnt = new vnode(v);
    map[curY, 0] = vnode.outputVN;
    curY += fillOutMap(map, vnt, curY, 1);
   }

   // step two - build the thing to get the values to where they need to be
   // find Is
   List<int> tis = new List<int>();
   for (int y = 0; y < map.w; y++)
   {
    for (int x = map.h - 1; x >= 0; x--)
    {
     vnode vn = map[y,x];
     if (vn != null && vn.c == 'I')
     {
      tis.Add(vn.id);
      if (vn.id > -2)
      {
       for (;x < map.h; x++)
       {
        map[y,x] = vnode.flatVN;
       }
      }
      goto next;
     }
    }
    tis.Add(-2);
   next:
    continue;
   }

   // I do not like this piece of code, it can be replaced further down for the better if you get round to thinking about it
   // add unused Is
   for (int z = 0; z < inputCount; z++)
   {
    if (!tis.Contains(z))
    {
     int midx = tis.IndexOf(-2);
     if (midx != -1)
     {
      tis[midx] = z;
      map[midx,map.h-1] = vnode.noVN;
     }
     else
     {
      tis.Add(z);
      map[map.w,map.h-1] = vnode.noVN;
     }
    }
   }

   int curX = map.h;

  MORE:
   for (int y = 0; y < map.w; y++)
   {
    if (y == map.w - 1)
    {
     if (tis[y] == -2)
      map[y,curX] = vnode.noVN;
     else
      map[y,curX] = vnode.flatVN;
    }
    else
    {
     int prev = tis[y];
     int cur = tis[y + 1];

     if (cur != -2 && (prev == -2 || cur < prev))
     { // swap 'em
      map[y,curX] = vnode.noVN;
      if (prev == -2)
       map[y+1,curX] = vnode.moveDownVN;
      else
       map[y+1,curX] = vnode.swapVN;
      int temp = tis[y];
      tis[y] = tis[y + 1];
      tis[y + 1] = temp;
      y++; // skip
     }
     else
     {
      if (/*thatThingThat'sAThing*/ prev == cur && cur != -2)
      {
       map[y,curX] = vnode.noVN;
       map[y+1,curX] = vnode.splitDownVN;
       int temp = tis[y];
       tis[y+1] = -2;
       y++; // skip
      }
      else
      {
       if (prev == -2)
        map[y,curX] = vnode.noVN;
       else
        map[y,curX] = vnode.flatVN;
      }
     }
    }
   }

   // check if sorted
   for (int y = 0; y < map.w - 1; y++)
   {
    int prev = tis[y];
    int cur = tis[y + 1];

    if (cur != -2 && (prev == -2 || cur < prev))
     goto NOTSORTED;
   }

   goto WHATNOW;

  NOTSORTED:
   curX++;
   goto MORE;

  WHATNOW:

   tis.Add(-2); // this is to avoid boud checking y+2
   // so... it's sorted now, so add the splits
  morePlease:
   curX++;
   for (int y = 0; y < map.w; y++)
   {
    if (y == map.w - 1)
    {
     if (tis[y] == -2)
      map[y,curX] = vnode.noVN;
     else
      map[y,curX] = vnode.flatVN;
    }
    else
    {
     int prev = tis[y];
     int cur = tis[y + 1];
     int next = tis[y + 2];

     if (cur != -2 && prev == cur && cur != next)
     { // split
      map[y,curX] = vnode.noVN;
      map[y+1,curX] = vnode.splitDownVN;
      tis[y + 1] = -2;
      y++; // skip
     }
     else
     {
      if (prev == -2)
       map[y,curX] = vnode.noVN;
      else
       map[y,curX] = vnode.flatVN;
     }
    }
   }

   // check if collapsed
   for (int y = 0; y < map.w - 1; y++)
   {
    int prev = tis[y];
    int cur = tis[y + 1];

    if (cur != -2 && prev == cur)
     goto morePlease;
   }

   // ok... now we put in the Is and 1
   curX++;
   map[0, curX] = vnode.oneVN;
   int eyeCount = 0;
   int ly = 0;
   for (int y = 0; y < map.w; y++)
   {
    if (tis[y] > -1)
    {
     map[y, curX] = vnode.inputVN;
     eyeCount++;
     ly = y;
    }
   }

   // step three - clean up if we can
   // push back _  esq things to  _
   //           _/               /
   // this /shouldn't/ be necessary if I compact the vals properlu
   for (int y = 0; y < map.w - 1; y++)
   {
    for (int x = 1; x < map.h; x++)
    {
     if (map[y, x] != null && map[y+1, x] != null && map[y+1, x-1] != null)
     {
      char uc = map[y+1, x-1].c;
      if (map[y, x].c == '_' && map[y+1, x].c == '_'
          && (uc == 'U' || uc == 'u'))
      {
       map[y, x] = vnode.noVN;
       map[y, x-1] = vnode.flatVN;
       map[y+1, x] = map[y+1, x-1];
       map[y+1, x-1] = vnode.noVN;
      }
     }
    }
   }

   // step four - write out map
   writer.WriteLine(map.h + " " + map.w);

   for (int y = 0; y < map.w; y++)
   {
    for (int x = map.h - 1; x >= 0; x--)
    {
     vnode vn = map[y,x];
     if (vn != null)
      writer.Write(vn.c);
     else
      writer.Write(' ');
    }
    writer.WriteLine();
   }
  }

  // printer
  static string up1 = @"      /     /     /     /";
  static string input = @"                    |||||";
  static string output = @"                    |    ";
  static string flat = @"            |/  \  /|\   ";
  static string splitDown = @"|//   / /\  |\/    /     ";
  static string splitUp = @"         \  |/\ \ \/|\\  ";
  static string moveDown = @"|//     /     /    /     ";
  static string moveUp = @"         \    \   \ |\\  ";
  static string swap = @"|/  |  /\   /\   \/ |\  |";
  static string orDown = @"|/    /     |/  \  /|\   ";
  static string orUp = @"|/    /  \  |\  \   |\   ";
  static string ifnotDown = @"|/     /     -   \/ |\  |";
  static string ifnotUp = @"|/  |  /\    -   \  |\   ";

  public static void printDominoes(System.IO.TextReader reader, System.IO.TextWriter writer, bool moreverbosemaybe)
  {
   string line;
   string[] data;

   line = reader.ReadLine();
   data = line.Split(' ');
   int w = int.Parse(data[0]);
   int h = int.Parse(data[1]);

   int ox = 0;
   int oy = 0;
   int cx = 5;
   int cy = 5;

   char[,] T = new char[ox + w * cx, oy + h * (cy - 1) + 1];

   Action<int, int, string> setBlock = (int x, int y, string str) =>
   {
    for (int i = 0; i < cx; i++)
    {
     for (int j = 0; j < cy; j++)
     {
      char c = str[i + j * cx];
      if (c != ' ')
       T[ox + x * cx + i, oy + y * (cy - 1) + j] = c;
     }
    }
   };

   // read and write
   for (int j = 0; j < h; j++)
   {
    line = reader.ReadLine();
    for (int i = 0; i < w; i++)
    {
     if (line[i] != ' ')
     {
      switch (line[i])
      {
       case '1':
        setBlock(i, j, up1);
        break;
       case '_':
        setBlock(i, j, flat);
        break;
       case '^':
        setBlock(i, j, splitUp);
        break;
       case 'v':
        setBlock(i, j, splitDown);
        break;
       case '/':
        setBlock(i, j, moveUp);
        break;
       case '\\':
        setBlock(i, j, moveDown);
        break;
       case 'X':
        setBlock(i, j, swap);
        break;
       case 'U':
        setBlock(i, j, orUp);
        break;
       case 'D':
        setBlock(i, j, orDown);
        break;
       case 'u':
        setBlock(i, j, ifnotUp);
        break;
       case 'd':
        setBlock(i, j, ifnotDown);
        break;
       case 'I':
        setBlock(i, j, input);
        break;
       case 'O':
        setBlock(i, j, output);
        break;
      }
     }
    }
   }

   // end
   for (int i = 0; i < T.GetLength(0); i++)
   {
    T[i, 0] = '/';
   }

   // writeout
   w = T.GetLength(0) - cx + 1;
   h = T.GetLength(1);
   if (moreverbosemaybe)
    writer.Write(w + " " + h + " ");
   for (int j = 0; j < T.GetLength(1); j++)
   {
    for (int i = 0; i < T.GetLength(0) - cx + 1; i++)
    {
     char c = T[i, j];
     writer.Write(c == 0 ? ' ' : c);
    }
    if (!moreverbosemaybe)
     writer.WriteLine();
   }
  }
 }
}

An additional test case:
4 1 0,0,0,1,0,0,1,1,0,0,0,1,1,1,1,1

This checks whether two adjacent (non-wrapping) bits are both 1s (e.g. true for 0110, but false for 0101 and 1001)

This is beautiful. Now we need a meta domino solver which takes the truth table in I and whose outputs specify a new domino layout

I'm confused as to how that truth table represents a four bit prime checker. Does it not say that 14 and 15 are prime?

@quintopia having looked again... you do appear to be right,and IT IS my fault, the one Martin uses is correct, but I am NOT rebuilding that primechecker now!

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes