Фондовая биржа KoTH

23

Фондовый рынок все о скорости знаний. В отличие от предыдущих испытаний, текущая цена акций не случайна: она определяется теми, кто играет в игру. Если вы можете определить недооцененную акцию раньше, чем кто-либо другой, то вы написали себе программу для зарабатывания денег.

Цена относится к тому, за сколько люди торгуют акцией, а стоимость - к сумме, которую акция стоит в конце игры.

Каждый игрок начинает с 1000 каждой акции и 0 относительной чистой стоимостью. Каждая акция имеет секретное значение, и ваш счет в конце игры равен(stockValue for each ownedStock) + netWorth . Ваш собственный капитал может быть отрицательным. В игре с N игроками есть N акций.

шаги:

Игра состоит из следующих шагов:

  1. Вам дана секретная стоимость одной акции.
  2. Вы делаете предложение продать акции X of Y за $ Z
  3. Все игроки получают предложения, и каждый может выбрать один из них, чтобы принять
  4. Все игроки проинформированы о принятых предложениях
  5. Вернитесь к шагу 2

Каждый из шагов подробно описан ниже:

  1. void secretValue(int stockType, int value):

    • Значение, которое вы изучаете, не раскрывается ни одному другому игроку.
    • Значение между 0и1000
    • Низкие значения чаще встречаются, чем высокие (квадратное равномерное распределение)
  2. Offer makeOffer(List<Stock> currentStock)

    • Вы можете вернуться, nullчтобы не делать никаких предложений.
  3. Offer acceptOffer(List<Offer> offers)

    • Вы можете вернуться, nullчтобы принять ни один из них
    • Если нет доступных предложений, это не будет называться
    • Если вы согласитесь, ваш собственный капитал уменьшится на $ Z (может стать отрицательным) и вы получите X из Y акций. Противоположное происходит с продавцом.
    • Если вы примете предложение, обмен произойдет немедленно, и предложение будет удалено, поэтому дополнительные игроки не смогут его принять.
  4. void acceptedOffers(List<Offer> offers)

    • Включает также ваши принятые предложения

Статические переменные или запись в файлы не допускаются. (Нет постоянных данных от игры к игре) Допускаются несерьезные соперники.

Интерфейсы:

public final class Stock {
    public Stock(int stockType, int amount);
    public int getType();
    public int getAmount();
    public Stock minus(Stock other);
    public Stock plus(Stock other);
    public Stock minus(int amount);
    public Stock plus(int amount);
    public Stock setAmount(int amount);
}
public class Offer {
    public Offer(Stock offer, int payment);
    public Stock getOffer();
    public int getPayment();
}

Материалы не на Java:

  • Все вызовы состоят из двух строк: Первая строка функция вызывается: SecretValue, MakeOffer, AcceptOffer, AcceptedOffers, SetRandom, и вторая строка , содержащая фактические данные.
  • Запасы отформатированы с :разделителем: stockType:stockAmount.
  • Предложения форматируются с @разделителем:offer@price
  • Списки отформатированы с ;разделителем
  • SecretValueотформатирован с :разделителем:stockType:value
  • RandomSeedиспользуется, чтобы сделать ваше представление детерминированным. Если ваше представление использует случайность, пожалуйста, используйте целочисленное значение, переданное в качестве начального числа!
  • Все вызовы функций требуют ответа. Если ответом является nullили void, вернуть пустую строку.
  • Пожалуйста, включите, command.txtкоторый дает аргументы командной строки для запуска вашего представления

счет

Игры, состоящие из 1000 ходов, будут запускаться несколько раз. Игроки будут забиты в соответствии с системой ELO , и в паре с игроками с аналогичным уровнем квалификации. Игрок с наибольшим итоговым результатом ELO побеждает! (Я модифицировал систему так, чтобы в каждой игре очки ELO обновлялись для каждого игрока в паре)

Контроллер включает в себя Autodownloader, поэтому , пожалуйста , начните представление с заголовком: Name, Language. Если ваша заявка не на Java, каждый блок кода должен начинаться с имени файла. (исключая командный файл, который должен быть первым блоком в вашем посте)

Бег

Есть 2 способа запустить этот проект:

  1. Скачайте исходный код, скомпилируйте и запустите. Вы можете найти источник на Github . Бегgit clone --recursive https://github.com/nathanmerrill/StockExchange.git

  2. Загрузите исполняемый файл JAR. Материалы должны быть размещены в вашем текущем рабочем каталоге в /submissionsпапке. Вы можете скачать только JAR , только материалы или оба

Перейдите runк запуску проекта (опция по умолчанию) или перейдите downloadк загрузке всех представленных материалов, которые пока не отвечают этому вопросу.

Табло

1.  1308.1220497323848  Cheater
2.  1242.0333695640356  InsideTrader
3.  1158.3662658295411  UncleScrooge
4.  1113.8344000358493  BlackMarket
5.  1051.8370015258993  DartMonkey
6.  983.0545446731494   WarGamer
7.  939.457423938002    Spammer
8.  901.4372529538886   DumbBot
9.  859.0519326039137   ShutUpAndTakeMyMoney
10. 852.9448222849587   VincentKasuga
11. 718.2112067329083   Profiteer
Натан Меррилл
источник
фондовые свойства не являются публичными, проинструктируйте использовать методы получения
noɥʇʎԀʎzɐɹƆ
@AgentCrazyPython лучше?
Натан Меррилл
соотносятся ли текущие цены с предыдущими?
noɥʇʎԀʎzɐɹƆ
1
Чат был бы признателен.
TheNumberOne

Ответы:

13

Читер, Ява

Пытается ничего не продавать за деньги.

import java.util.List;
import java.util.Random;
import com.ppcg.stockexchange.*;

public class Cheater extends Player {
    private Random random = new Random();

    public Offer acceptOffer(List<Offer> offers) {
        return null;
    }

    public Offer makeOffer(List<Stock> currentStock){
        Stock stock = randomStock();
        int price = random.nextInt(100) + 1;
        return new Offer(stock.setAmount(0), price);
    }
}
CommonGuy
источник
5
И так случается великая депрессия! Я мог видеть, как это сломало много ботов, которые покупают дешево ...
Сократик Феникс
Congrats! Я исправил критическую ошибку, и теперь этот бот первый!
Натан Меррилл
Ничего себе, другие боты недостаточно хороши, чтобы этот тупой бот мог выиграть
justhalf
8

WarGamer, Java

После поверхностного изучения правил я решил, что основной выигрышный ход - не играть. Любой, кто предлагает продать акции, наверняка знает цену и получит прибыль от продажи. Его можно переключать, чтобы он делал «шутливые» предложения продать акцию за доллары Integer.MAX_VALUE в надежде заткнуться и забрать мои деньги.

import java.util.List;
import com.ppcg.stockexchange.*;
import com.ppcg.kothcomm.game.AbstractPlayer;
import com.ppcg.kothcomm.utils.Tools;

import java.util.List;

public class WarGamer extends Player {
static final boolean FRAUD = false;
    /**
     * @param offers All available offers
     * @return An offer you want to accept, or null if you want to accept neither.
     */
    public Offer acceptOffer(List<Offer> offers){
        return null;
    }

    public Offer makeOffer(List<Stock> currentStock){
    if(FRAUD)
    return new Offer(new Stock(0,1),Integer.MAX_VALUE);
        //defraud shut up and take my money            
    return null;
    }
}
Рохан Джунджхунвала
источник
1
Это, вероятно, сработало бы хорошо, за исключением того, что я ожидаю, что будут записи, которые будут немного выше. Там обычно есть.
Geobits
Это не компилируется.
Rainbolt
@Rainbolt имеет свои зависимости. Вы должны убедиться, что присутствуют.
Рохан Джунджхунвала
@Rainbolt, какую ошибку компилятора вы получаете
Rohan Jhunjhunwala
1
Я не уверен, что та часть, где вы обманываете другого бота-шутки, находится в правильном духе ...
Maltysen
5

ShutUpAndTakeMyMoney, Java

import java.util.List;
import com.ppcg.stockexchange.*;

public class ShutUpAndTakeMyMoney extends Player {
    public ShutUpAndTakeMyMoney() {}

    public Offer acceptOffer(List<Offer> offers) {
        try {
            return offers.get(0);
        } catch (Exception ex) {
            return null;
        }
    }
    public Offer makeOffer(List<Stock> stock) {
        return null;
    }
}

Он принимает любое предложение.

TuxCrafting
источник
На самом деле спасибо за ваш бот
Рохан Jhunjhunwala
6
+1 для того, чтобы сделать меня богатым
Рохан Джунджхунвала
1
Мне кажется , что это на самом деле не совместимо с требованием, чтобы каждый ответ должен « быть серьезным претендентом на выигрышных критериев , используемых ».
Питер Тейлор
2
@PeterTaylor Это серьезно, это 5-е место в таблице лидеров
TuxCrafting
Возможно, это самоубийственный вход , так как разумно ожидать, что другие боты будут продавать акции больше, чем они стоят, что приведет к тому, что вы купите акции намного дороже, чем их фактическая цена.
Mego
4

DumbBot, Java

Используйте этот бот при создании своего. Предлагает свои секретные акции по сниженной цене.

import java.util.List;
import com.ppcg.stockexchange.*;
public class DumbBot extends Player {
    public Offer acceptOffer(List<Offer> offers) {
        return null;
    }
    public Offer makeOffer(List<Stock> currentStock){
        return new Offer(currentStock.get(secretStockType).setAmount(1), Math.max(1, secretStockValue - 5));
    }
    public void secretValue(int stockType, int value) {
        super.secretValue(stockType, value);
    }
    public void acceptedOffers(List<Offer> acceptedOffers) {
    }
}
Натан Меррилл
источник
1
Похоже, я хочу, чтобы он распоряжался моими деньгами
Рохан Джунджхунвала
пожалуйста, сделайте это сообщество вики
noɥʇʎԀʎzɐɹƆ
@AgentCrazyPython почему?
Натан Меррилл
@NathanMerrill, репутант, получает прибыль от этого фиктивного бота
noɥʇʎԀʎzɐɹƆ
@AgentCrazyPython Я действительно не хочу, чтобы люди редактировали это ... Меня не волнует мнение, так что не стесняйтесь не повышать (или понижать)
Натан Меррилл
3

python_starter, Python 3

Используйте это как отправную точку для любых программ на Python (или других языках)

Принимает случайное предложение.

Командный файл:

python3 starter.py

Программа:

starter.py
import random
from functools import total_ordering


LIST_DELIMITER = ';'
STOCK_DELIMITER = ':'
OFFER_DELIMITER = '@'


@total_ordering
class Stock:
    @staticmethod
    def parse(string: str):
        return Stock(*map(int, string.split(STOCK_DELIMITER)))

    def __init__(self, stock_type: int, amount: int):
        self.type = stock_type
        self.amount = max(amount, 0)

    def __str__(self):
        return str(self.type)+STOCK_DELIMITER+str(self.amount)

    def __eq__(self, other):
        return self.amount == other.type

    def __lt__(self, other):
        return self.amount < other.amount

    def update(self, amount) -> 'Stock':
        return Stock(self.type, amount)

    def __mul__(self, other: int) -> 'Stock':
        return self.update(self.amount*other)

    def __floordiv__(self, other: int) -> 'Stock':
        return self.update(self.amount//other)

    def __add__(self, other: int) -> 'Stock':
        return self.update(self.amount+other)

    def __sub__(self, other: int) -> 'Stock':
        return self.update(self.amount-other)


class Offer:
    @staticmethod
    def parse(string: str) -> 'Offer':
        try:
            offer, payment = string.split(OFFER_DELIMITER)
        except ValueError:
            raise Exception("Cannot unpack "+string)
        return Offer(Stock.parse(offer), int(payment.strip()))

    def __init__(self, offer: Stock, payment: int):
        self.offer = offer
        self.payment = payment

    def __str__(self):
        return str(self.offer)+OFFER_DELIMITER+str(self.payment)


def read_stock_value(value: str):
    global hidden_price, hidden_stock
    stock, price = value.split(STOCK_DELIMITER)
    hidden_price = float(price)
    hidden_stock = int(stock)


def process_input():
    handlers = {
        "SecretValue": read_stock_value,
        "RandomSeed": read_seed,
        "MakeOffer": make_offer,
        "AcceptOffer": accept_offer,
        "AcceptedOffers": accepted_offers,
    }
    method = input().strip()
    data = input().strip()
    output = handlers[method](data)
    if output is not None:
        print(str(output))
    else:
        print()


def read_seed(seed: str):
    random.seed(int(seed))


def start():
    while True:
        process_input()


hidden_stock = None
hidden_price = None


def make_offer(current_stock: str):
    current_stock = map(Stock.parse, current_stock.split(LIST_DELIMITER))
    pass


def accept_offer(available_offers: str):
    available_offers = list(map(Offer.parse, available_offers.split(LIST_DELIMITER)))
    return random.sample(available_offers, 1)[0]


def accepted_offers(offers: str):
    offers = map(Offer.parse, offers.split(LIST_DELIMITER))
    pass


if __name__ == "__main__":
    start()
Натан Меррилл
источник
1
это слишком сложно.
noɥʇʎԀʎzɐɹƆ
2
В основном это вспомогательные вещи. Если вы пишете это на python, вам просто нужно реализовать три нижние функции.
Натан Меррилл
Что это делает?
noɥʇʎԀʎzɐɹƆ
Бот принимает случайный запас. Вспомогательный материал выполняет синтаксический анализ / кодирование, а также предоставляет классы для предложений / акций.
Натан Меррилл
... и это выигрывает: /
noɥʇʎԀʎzɐɹƆ
3

Винсент Касуга, Ява

Не уверен, что моя Java действительна. Пожалуйста ознакомтесь.

Как это работает

- если вы владеете всеми акциями, вы можете установить цену акции. Вы единственный продавец. 1. Купите все акции. 2. Установите цену всех акций, чтобы быть супер высокой на последнем тике. 3. ПРИБЫЛЬ! - Обычно это невозможно, потому что ...

  • Цена обычно взлетает до бесконечности ... но есть предел!
  • ... (больше причин прийти)

Как это работает, v2

  • Цена искусственно установлена ​​на максимуме каким-то анархистским государством
  • Это плохо экономически
  • Бот не предсказывает - он использует врожденный недостаток в структуре рынка!

Сделать

  • Уголок рынка несколько раз! Muahaha!

Вопросы-Ответы

В: Кто такой Винсент Касуга?

A: Он купил весь лук и фьючерс на лук в Соединенных Штатах. (поместите их все в секретный склад) Держите индустрию в выкупе - дайте мне X миллионов, или я установлю цену до небес, и вы все обанкротитесь.

Но он не остановился на этом.

Затем он тайно замкнул луковый ETF (держу пари, что он упадет). Он продал все луковицы за один раз, физически доставив их на бирже тысячами грузовиков. Луковая сумка стоит дешевле, чем лук. Он снова заработал миллионы. Одним словом, река Гудзон переполнена луком.

Он настоящий человек.

Код

import com.ppcg.stockexchange.Offer;
import com.ppcg.stockexchange.Player;
import com.ppcg.stockexchange.Stock;

import java.util.List;

public class VincentKasuga extends Player {
    private int knownStock;
    private int knownPrice;
    private int corneredStockType = -1;
    private int corneredLikelehood = 0;
    private boolean marketCornered;
    private int ticks;

    public Offer acceptOffer(List<Offer> offers) {
        if (!marketCornered) {
            Offer maxOffer = null;
            int maxAmount = 0;
            if (corneredStockType == -1) {
                for (Offer offer: offers) {
                    if (offer.getOffer().getAmount() > maxAmount) {
                        maxAmount = offer.getOffer().getAmount();
                        maxOffer = offer;
                    }
                }
            } else {
                for (Offer offer: offers) {
                    if (offer.getOffer().getAmount() > maxAmount && offer.getOffer().getType() == corneredStockType) {
                        maxAmount = offer.getOffer().getAmount();
                        maxOffer = offer;
                    }
                }
            }


            if (maxOffer == null) {
                // may have cornered the market
                corneredLikelehood++;
                if (corneredLikelehood == 5) {
                    // probably cornered the market
                    marketCornered = true;
                }
            }
            return maxOffer;
        } else {
            // who needs offers when the market is cornered!?
            return null;
        }
    }

    public Offer makeOffer(List<Stock> currentStock) {
        ticks++;
        if (ticks >= 999) {
            // SELL SELL SELL!
            return new Offer(new Stock(corneredStockType, 1000), 1000);
        } else {
            return null;
        }
    }

    public void secretValue(int stockType, int value) {
        knownStock = stockType;
        knownPrice = value;
        if (stockType == corneredStockType) {
            if (knownPrice == 1000) {
                corneredLikelehood += 3;
            } else if (knownPrice < 900){
                // didn't corner the market.
                corneredLikelehood = 0;
            }
        }
    }
}

"Я загнал в угол Золотой Рынок, мистер Бонд!"

noɥʇʎԀʎzɐɹƆ
источник
Я включил автозагрузчик для ботов. Пожалуйста, поместите ваш код в блок кода. Если это не подходит, это нормально.
Натан Меррилл
@ NatanMerrill я понимаю. А компилируется ли?
noɥʇʎԀʎzɐɹƆ
@NathanMerrill сделано. Probs не компилируется. интересная стратегия, а? И урок экономики!
noɥʇʎԀʎzɐɹƆ
for (offer: offers)->for (Offer offer: offers)
Натан Меррилл
corneredStockType == nullтакже не действует. intне может быть null.
MegaTom
2

Спамер, Java

import java.util.List;
import java.util.ArrayList;
import com.ppcg.stockexchange.*;

public class Spammer extends Player {
    private boolean panic = false;

    public Offer acceptOffer(List<Offer> offers) {
        for (Offer offer : offers) {
            if (this.panic || offer.getPayment() < 20)
                return offer;
        }
        return null;
    }
    public Offer makeOffer(List<Stock> currentStock) {
        if (currentStock.size() > 1) { // Don't sell all the stock
            this.panic = false;
            return new Offer(currentStock.get(secretStockType).setAmount(1), 1);
        }
        this.panic = true; // BUY
        return null;
    }
}

Спам на рынке с действительно дешевыми акциями, и покупайте акции только тогда, когда цена меньше 20. Когда количество акций упадет до 1, он попытается купить что угодно.

TuxCrafting
источник
хорошо работает в Великой депрессии
noɥʇʎԀʎzɐɹƆ
... как это победа !?
noɥʇʎԀʎzɐɹƆ
2

DartMonkey, Java

(не конкурирует: он не победит, и у меня уже есть другой ответ)

Обезьяна-дротик любит бросать вещи ... а рядом с ним большая куча острых палочек. Он видит какую-то бумагу на стене. Бам! Бам! Бам! В мгновение ока Дарт Обезьяна бросила 80 дротиков! Половина дротиков красного цвета, а другая половина синего цвета, и на них случайные числа! Обезьяна Дартс видит компьютер ... Обезьяна Дартс набирает цифры. Дартс обезьяна любит цифры. Обезьяна Дартс зарабатывает деньги на своих дротиках ...


На самом деле, DartMonkey инициализирует целочисленный массив, длина которого в два раза превышает количество акций. Он хранит одно число для количества акций, которые он хочет купить / продать, и одно число для цены акции. Затем он чередует продажу акций из массива и принимает предложения в соответствии с массивом. Если у него нет акций из массива, он ничего не будет предлагать, а если у него нет предложений, выданных ему из массива, он ничего не примет.


Этот ответ был вдохновлен @TheNumberOne, который упомянул обезьян дартс в чате

import com.ppcg.stockexchange.Offer;
import com.ppcg.stockexchange.Player;
import com.ppcg.stockexchange.Stock;

import java.util.List;
import java.util.Random;

public class DartMonkey extends Player {
    private int basePrice = 100;
    private int numStocks;
    private int[] dartBoard;
    private boolean first = true;

    @Override
    public Offer acceptOffer(List<Offer> offers) {
        for(Offer offer : offers) {
            Stock stock = offer.getOffer();
            int type = stock.getType();
            int amount = stock.getAmount();
            int price = offer.getPayment();
            if(this.dartBoard[type] < 0 && amount <= -this.dartBoard[type] && price <= this.dartBoard[type + this.numStocks]) {
                this.dartBoard[type] = 0;
                return offer;
            }
        }
        return null;
    }

    @Override
    public Offer makeOffer(List<Stock> stocks) {
        if(this.first) {
            this.first = false;
            this.numStocks = stocks.size();
            this.dartBoard = new int[this.numStocks * 2];
            Random random = this.getRandom();
            for (int i = 0; i < 20; i++) {
                int index = random.nextInt(this.dartBoard.length / 2);
                this.dartBoard[index] = random.nextInt(1001);
                this.dartBoard[this.numStocks + index] = random.nextInt(1001);
            }

            for (int i = 0; i < 20; i++) {
                int index = random.nextInt(this.dartBoard.length / 2);
                this.dartBoard[index] = -random.nextInt(1001);
                this.dartBoard[this.numStocks + index] = random.nextInt(1001);                
            }
        }

        for (Stock stock : stocks) {
            int type = stock.getType();
            if(this.dartBoard[type] > 0) {
                Offer offer = new Offer(stock.setAmount(this.dartBoard[type]), this.basePrice + this.dartBoard[type + this.numStocks]);
                this.dartBoard[type] = 0;
                this.dartBoard[type + this.numStocks] = 0;
                return offer;
            }
        }

        return null;
    }

}
Сократовский феникс
источник
Я вижу, вы случайно пошли по Уолл-стрит?
Рохан Джунджхунвала
Это, возможно, суицидальная запись , которая не допускается.
Mego
1
@ Мего, я не понимаю, как ... Самоубийственная запись будет продавать акции за 0 долларов, эта запись определяет, что она покупает и продает случайным образом. Что определенно не противоречит правилам ...
Сократов Феникс
2

InsideTrader, Java

InsideTrader просто огляделся и увидел, что все пытаются быть креативными. Но он сделал что-то творческое: делай то, что ожидается.

Этот бот покупает, когда он «стоит», потому что он «позаимствовал» некоторые «внутренние документы», чтобы «направлять» «инвестиционные решения».

To-Do и как это работает в коде. ;)

Код"

import java.util.List;

import com.ppcg.stockexchange.*;

public class InsideTrader extends Player {
    public String coverStory = "I can tell the good companies from the bad ones.";
    private String theTruth = "I'm cheating. (but so is everyone else)";
    private String ambitions = "Learn to \"follow the market\"";  // don't steal this idea
    private int secretStock = -1;
    private int secretStockValue = -1;

    private int appraiseOffer(Offer offer) {
        /* get how much the offer is worth, 0 if it's not the secret stock */
        if (offer.getOffer().getType() != secretStock ||offer.getOffer().getAmount() == 0) {
            return 0;
        }
        return (offer.getPayment()/offer.getOffer().getAmount())  // price per stock...
                - secretStockValue  // minus value of stock.
                ;
    }
    public Offer acceptOffer(List<Offer> offers) {
        Offer bestOffer = null;
        int bestOfferValue = -1;
        for (Offer offer :
                offers) {
            int value = appraiseOffer(offer);
            if (value > bestOfferValue && value > 0) {
                bestOfferValue = value;
                bestOffer = offer;
            }
        }
        return bestOffer;
    }

    public Offer makeOffer(List<Stock> currentStock) {
        return new Offer(new Stock(0,1), Integer.MAX_VALUE);
    }

    public void secretValue(int stockType, int value) {
        secretStock = stockType;
        secretStockValue = value;
    }

    public void acceptedOffers(List<Offer> acceptedOffers) {

    }
}
noɥʇʎԀʎzɐɹƆ
источник
Вы не можете иметь эти дополнительные классы в начале файла ... это синтаксически неверно ... они могут быть добавлены до конца без публичного, я думаю
Socratic Phoenix
Error on line 50: modifier private not allowed here Error on line 54: modifier private not allowed here, Я бы просто удалил классы и продлил ихPlayer
Натан Меррилл
Просто обратите внимание, некоторые новые боты предлагают акции на сумму ноль, поэтому ваш бот выбрасывает ArithimeticException (/ на ноль) от возврата appraiseOffer ... может быть, добавить чек или что-то еще?
Сократов Феникс
@SocraticPhoenix Спасибо, исправлю.
no16z at
Поздравляю, этот бот на втором месте!
Натан Меррилл
2

WallStreet, Котлин

Начнем с того, что продаем высоко и покупаем низко и постепенно смещаемся к тому, что, по его мнению, цена на самом деле. Кроме того, вы можете использовать это как шаблон для создания своего собственного в kotlin.

Примечание: здесь есть ошибка, которую я не могу точно воспроизвести. Если моя программа дает сбой или возникли проблемы, пожалуйста, напишите мне в чате и вставьте ссылку на содержимоеsubmissions/other/WallStreet/log.txt

kotlinc WallStreet.kt
kotlin WallStreetKt
WallStreet.kt
import java.io.FileOutputStream
import java.io.PrintStream
import java.util.*

val LOGGER = PrintStream(FileOutputStream("log.txt", true))
const val DEBUG = false

const val LOG_GAME_HEADER = """
###############
#STARTING GAME#
###############"""

data class Stock(val type : Int, val amount : Int) {

    operator fun minus(amount : Int) = copy(amount = this.amount - amount)
    operator fun plus(amount: Int) = copy(amount = this.amount + amount)
    fun setAmount(amount: Int) = copy(amount = amount)

    operator fun minus(other : Stock) : Stock {
        assert(type == other.type)
        return copy(amount = this.amount - other.amount)
    }

    operator fun plus(other : Stock) : Stock {
        assert(type == other.type)
        return copy(amount = this.amount + other.amount)
    }

    override fun toString() = "$type:$amount"
}

data class Offer(val offer: Stock, val payment: Int) {
    override fun toString() = "$offer@$payment"
}

fun parseStock(repr : String) : Stock {
    val data = repr.split(":").map { it.toInt() }
    return Stock(data[0], data[1])
}

fun parseOffer(repr: String) : Offer {
    val data = repr.split("@")
    return Offer(parseStock(data[0]), data[1].toInt())
}

fun parseOffers(repr: String) = if (repr == "") emptyList<Offer>() else repr.split(";").map { parseOffer(it) }


interface Player {
    fun secretValue(stockType: Int, value: Int)
    fun makeOffer(currentStock: List<Stock>) : Offer?
    fun acceptOffer(offers: List<Offer>) : Offer?
    fun acceptedOffers(offers: List<Offer>)

    var random : Random
}

fun main(args : Array<String>) {

    try {

        if (DEBUG) {
            LOGGER.println(LOG_GAME_HEADER)
        }
        //Change bot name here
        val player = WallStreet()

        while (true) {
            val function = readLine()
            function ?: return
            val line = readLine()!!
            if (DEBUG) {
                LOGGER.println("\nInput:")
                LOGGER.println(function)
                LOGGER.println(line)
            }
            var result : Any
            try {
                result = when (function) {
                    "SecretValue" -> {
                        val data = line.split(":").map { it.toInt() }
                        player.secretValue(data[0], data[1])
                    }
                    "MakeOffer" -> player.makeOffer(line.split(";").map { parseStock(it) }) ?: ""
                    "AcceptOffer" -> player.acceptOffer(parseOffers(line)) ?: ""
                    "AcceptedOffers" -> player.acceptedOffers(parseOffers(line))
                    "RandomSeed" -> player.random = Random(line.toLong())
                    else -> return        //Exit program
                }
                if (function == "AcceptOffer" && result.toString() !in line) {
                    throw Exception("Offer not among available offers!!!!\nResult: $result\nParsed Available Offers: ${parseOffers(line)}")
                }
            } catch (e : Exception) {
                LOGGER.println("Turn #${player.turn}")
                LOGGER.println("\nInput:")
                LOGGER.println(function)
                LOGGER.println(line)
                throw e
            }

            if (result == Unit) {
                result = ""
            }
            if (DEBUG) {
                LOGGER.println("Output:")
                LOGGER.println(result)
            }

            println(if (result == Unit) "" else result)
        }
    } catch (e : Exception) {
        e.printStackTrace(LOGGER)
        throw e
    } finally {
        LOGGER.close()
    }
}


// ###################################################
// #          Put program logic below here.          #
// ###################################################


const val DEFAULT_STOCK_VALUE = 333
const val MAX_TURNS = 1000
const val MAX_STOCK_VALUE = 1000

class WallStreet : Player {

    var secretStockType = 0
    var secretStockValue = 0
    override var random = Random()


    var turn = 0
    val stockPriceStatistics = mutableMapOf<Int, DoubleSummaryStatistics>()

    override fun secretValue(stockType: Int, value: Int) {
        secretStockType = stockType
        secretStockValue = value
    }

    override fun makeOffer(currentStock: List<Stock>): Offer {
        val stock = currentStock[random.nextInt(currentStock.size)]
        val type = stock.type
        val amount = random.nextInt(stock.amount)
        val price = getSellPrice(type) * amount
        return Offer(Stock(type, amount), Math.ceil(price).toInt())
    }

    override fun acceptOffer(offers: List<Offer>): Offer? {
        var bestOffer : Offer? = null
        var mostProfit = 0.0
        for (offer in offers) {
            val offerProfit = profitOfOffer(offer)
            if (offerProfit > mostProfit) {
                bestOffer = offer
                mostProfit = offerProfit
            }
        }
        if (bestOffer != null && bestOffer !in offers) {
            throw IllegalStateException("Tried to accept non-existent offer.\nOffer:  $bestOffer\nAvailable Offers: ${offers.joinToString(";")}")
        }
        return bestOffer
    }

    override fun acceptedOffers(offers: List<Offer>) {
        turn++
        for ((stock, payment) in offers) {
            val stats = stockPriceStatistics.getOrPut(stock.type) { DoubleSummaryStatistics() }
            for (i in 1..stock.amount) {
                stats.accept(payment.toDouble() / stock.amount)
            }
        }
    }

    private fun getSellPrice(type: Int): Double {
        var price = getPrice(type)
        if (price < 1000) {
            price += (1000 - price) * (MAX_TURNS - turn) / MAX_TURNS
        }
        return if (type == secretStockType) Math.max(secretStockValue.toDouble(), price) else price
    }

    private fun getPrice(type: Int): Double {
        return stockPriceStatistics[type]?.average ?: DEFAULT_STOCK_VALUE.toDouble()
    }

    private fun profitOfOffer(offer: Offer): Double {
        return getBuyPrice(offer.offer.type) * offer.offer.amount - offer.payment
    }

    private fun getBuyPrice(type: Int): Double {
        var price = getPrice(type)
        price = price * turn / MAX_TURNS
        return if (type == secretStockType) Math.min(secretStockValue.toDouble(), price) else Math.min(price, MAX_STOCK_VALUE.toDouble())
    }

}
Номер один
источник
command.txtне нужно имя файла. Хороший пост!
Натан Меррилл
Я думал, что интерполяция строк была сделана с помощью $ {}, а не только $?
Сократов Феникс
@SocraticPhoenix $работает только с именем переменной. ${}выполняет произвольный код. В принципе, это работает в любом случае, и я предпочитаю без скобок.
TheNumberOne
К вашему сведению: в качестве временного решения пользователям окон, которые хотят запустить этот файл, нужно изменить command.txt: kotlinc-> kotlinc.batи kotlin->kotlin.bat
Натан Меррилл
После того, как я исправил свой контроллер, этот бот начал возвращать кучу плохих данных, поэтому я удалил их из соревнования. Я могу помочь вам в чате, если хотите :)
Натан Меррилл
1

UncleScrooge, Java

import java.util.List;
import com.ppcg.stockexchange.*;

public class UncleScrooge extends Player {
    public Offer acceptOffer(List<Offer> offers) {
        Offer offer;
        try {
            offer = offers.get(0);
        } catch (Exception ex) {
            return null;
        }
        if (offer.getPayment() < 100)
            return offer;
        else
            return null;
    }
    public Offer makeOffer(List<Stock> currentStock){
        if (this.getRandom().nextDouble() < 0.6)
            return new Offer(currentStock.get(secretStockType).setAmount(1), Integer.MAX_VALUE);
        else
            return null;
    }
    public void secretValue(int stockType, int value) {
        super.secretValue(stockType, value);
    }
    public void acceptedOffers(List<Offer> acceptedOffers) { }
}

Продавайте акции по действительно высокой цене, и покупайте, только если цена меньше 100.

TuxCrafting
источник
1

Профитер, Java

Профессионал в этом за деньги, и он всегда считает монеты. Он консервативно оценивает, сколько у него денег. Затем он купит секретную акцию, если она меньше стоимости, или купит дешевую акцию. Он также помнит, сколько ему заплатили за все, и всегда делает предложения выше цены акций. Кроме того, он сделает более высокие предложения, если у него будет меньше денег.

Примечание: я думаю, что я сделал это правильно, но если бы @NathanMerrill не возражал против просмотра моего кода на предмет ошибок, это было бы здорово

import com.ppcg.stockexchange.Offer;
import com.ppcg.stockexchange.Player;
import com.ppcg.stockexchange.Stock;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class Profiteer extends Player {
    private List<StockInfo> onMarket;
    private List<StockInfo> stocks;
    private int money;
    private boolean first = true;

    @Override
    public Offer acceptOffer(List<Offer> offers) {
        Offer finalOffer;

        Optional<Offer> offer = offers.stream().filter(o -> o.getOffer().getType() == this.secretStockType && o.getPayment() < this.secretStockValue * o.getOffer().getAmount()).sorted((a, b) -> Integer.compare((this.secretStockValue * a.getOffer().getAmount()) - b.getPayment(), (this.secretStockValue * b.getOffer().getAmount()) - b.getPayment())).findFirst();
        if (offer.isPresent()) {
            finalOffer = offer.get();
        } else {
            finalOffer = offers.stream().sorted((a, b) -> Integer.compare(a.getPayment(), b.getPayment())).findFirst().orElse(null);
        }

        if (finalOffer == null || this.money <= finalOffer.getPayment()) {
            return null;
        } else {
            this.stocks.add(new StockInfo(finalOffer.getOffer(), finalOffer.getPayment()));
            this.refreshMoney();
            return finalOffer;
        }
    }

    @Override
    public Offer makeOffer(List<Stock> stocks) {
        if (this.first) {
            this.init(stocks);
        } else {
            this.refreshMarketList(stocks);
        }

        Optional<StockInfo> least = this.stocks.stream().sorted((a, b) -> Integer.compare(a.getBoughtPrice(), b.getBoughtPrice())).findFirst();
        Optional<StockInfo> secret = this.stocks.stream().filter(stockInfo -> stockInfo.getStock().getType() == this.secretStockType).sorted((a, b) -> Integer.compare(a.getBoughtPrice(), b.getBoughtPrice())).findFirst();

        StockInfo finalOffer;
        int price;
        if (secret.isPresent()) {
            finalOffer = secret.get();
        } else if (least.isPresent()) {
            finalOffer = least.get();
        } else {
            return null;
        }

        this.onMarket.add(finalOffer);
        this.stocks.remove(finalOffer);
        price = this.calculatePrice(finalOffer.boughtPrice);
        return new Offer(new Stock(finalOffer.getStock().getType(), finalOffer.getStock().getAmount()), price);
    }

    private int calculatePrice(int boughtPrice) {
        return (int) (boughtPrice + ((boughtPrice / (double) this.money) * this.money)) + 1;
    }

    private void refreshMarketList(List<Stock> stocks) {
        this.stocks.addAll(this.onMarket.stream().filter(stockInfo -> stocks.contains(stockInfo.getStock())).collect(Collectors.toList()));
        this.onMarket.clear();
    }

    private void refreshMoney() {
        this.money = this.stocks.stream().mapToInt(info -> this.secretStockType == info.getStock().getType() ? this.secretStockValue : 5).reduce((a, b) -> a + b).orElseGet(() -> 0) - this.stocks.stream().mapToInt(StockInfo::getBoughtPrice).reduce((a, b) -> a + b).orElseGet(() -> 0);
    }

    private void init(List<Stock> stocks) {
        this.stocks = stocks.stream().map(stock -> new StockInfo(stock, 0)).collect(Collectors.toList());
        this.onMarket = new ArrayList<>();
        this.money = 0;
        this.first = false;
        this.refreshMoney();
    }

    private static class StockInfo {
        private Stock stock;
        private int boughtPrice;

        public StockInfo(Stock stock, int boughtPrice) {
            this.stock = stock;
            this.boughtPrice = boughtPrice;
        }

        public Stock getStock() {
            return this.stock;
        }

        public int getBoughtPrice() {
            return this.boughtPrice;
        }

    }

}
Сократовский феникс
источник
вы можете
влезть
@AgentCrazyPython Я знаю, но спекулянт не хочет рисковать
Сократик Феникс
не могу отменить голосование
noɥʇʎԀʎzɐɹƆ
@AgentCrazyPython Мех, все в порядке, игра веселая, и вот что важно
Сократик Феникс
1

MaxBot, Java

Этот бот пытается извлечь максимальную прибыль из каждой транзакции. При продаже ставит цену неизвестной акции в 300 долларов, при покупке 250 долларов.

import java.util.List;
import com.ppcg.stockexchange.*;
public class MaxBot extends Player {
    int toSell;
    int sellPrice;

    public void secretValue(int stockType, int value) {
        super.secretValue(stockType, value);
        toSell = stockType;
        sellPrice = (value + 1000)/2;
    }
    public Offer acceptOffer(List<Offer> offers) {
        Offer max = null;
        int maxDif = 0;
        for(Offer o: offers){
            int price = secretStockType == o.getOffer().getType()? secretStockValue: 250;
            int val = price * o.getOffer().getAmount();
            int dif = val - o.getPayment();
            if(maxDif < dif){
                max = o;
                maxDif = dif;
            }
        }
        return max;
    }
    public Offer makeOffer(List<Stock> currentStock){
        if(toSell == -1){
            return null;
        }
        int sum = 0;
        for (Stock s: currentStock){
            if(s.getType() == toSell){
                sum += s.getAmount;
            }
        }
        int n = sum - sum/2;
        return new Offer(new Stock(toSell, n), n * sellPrice);
    }
    public void acceptedOffers(List<Offer> acceptedOffers) {
        int highStock = -1;
        int highPrice = 0;
        int markup = 0;
        for(Offer o: offers){
            int trueVal = secretStockType == o.getOffer().getType()? secretStockValue: 250;
            int marketVal = o.getPayment()/o.getOffer().getAmount();
            if(marketVal - trueVal > markup){
                highStock = o.getOffer().getType();
                highPrice = marketVal;
                markup = marketVal - trueVal;
            }
        }
        toSell = highStock;
    }
}
MegaTom
источник
1

BlackMarket, Java

Не много, чтобы сказать об этом, учитывая, что эти транзакции будут ... вне графика, вы могли бы сказать.

import java.util.List;
import com.ppcg.stockexchange.*;

public class BlackMarket extends Player {
    private boolean approvedBySEC = false;
    private int ammoLeft = 30;
    public String taxView = "We want higher tax rates";
    public String excuse = "I never saw that in my life";

    public void secretValue(int drugType, int warrantForMyArrest) {
        super.secretValue(drugType, warrantForMyArrest);
        if (warrantForMyArrest != 0 || drugType == 420) {
            ammoLeft += 10;
        }
    }

    public Offer acceptOffer(List<Offer> offers) {
        for (Offer offer : offers) {
            if (this.approvedBySEC || offer.getPayment() < 9)
                return offer;
        }
        return null;
    }


    public Offer makeOffer(List<Stock> currentStock) {
        return new Offer(new Stock(0,1),420);
    }
}
Timtech
источник
return null is outside ... пожалуйста, сделайте отступ тоже правильно.
no16z at
1
@AgentCrazyPython Спасибо! Мы получим «вернуть ноль», как только стемнеет. Остерегайтесь автомобилей, следующих за вами на следующий месяц.
Timtech
1
Почему отрицательный голос? Мы заняли четвертое место в последнем соревновании. Хотя мы не совсем уверены, как ...
Timtech
0

NotQuiteABanksBestFriend, Python 3

Command.txt:

python3 NotQuiteABanksBestFriend.py
NotQuiteABanksBestFriend.py
import random
from functools import total_ordering
from io import StringIO

log = StringIO()
log.write("\n\n~~~NEW GAME~~~\n\n")

LIST_DELIMITER = ';'
STOCK_DELIMITER = ':'
OFFER_DELIMITER = '@'

JAVA_MAX_INT = 2147483647

@total_ordering
class Stock:
    @staticmethod
    def parse(string: str):
        return Stock(*map(int, string.split(STOCK_DELIMITER)))

    def __init__(self, stock_type: int, amount: int):
        self.type = stock_type
        self.amount = max(amount, 0)

    def __str__(self):
        return "T%sx%s"%(self.type, self.amount)

    def __repr__(self):
        return str(self.type)+STOCK_DELIMITER+str(int(self.amount))

    def __bool__(self):
        return bool(self.amount)

    def __eq__(self, other):
        return self.amount == other.amount

    def __lt__(self, other):
        return self.amount < other.amount

    def update(self, amount) -> 'Stock':
        return Stock(self.type, amount)

    def __mul__(self, other: int) -> 'Stock':
        return self.update(self.amount*other)

    def __floordiv__(self, other: int) -> 'Stock':
        return self.update(self.amount//other)

    def __add__(self, other: int) -> 'Stock':
        return self.update(self.amount+other)

    def __sub__(self, other: int) -> 'Stock':
        return self.update(self.amount-other)


class Offer:
    @staticmethod
    def parse(string: str) -> 'Offer':
        try:
            stock, price = string.split(OFFER_DELIMITER)
        except ValueError:
            raise Exception("Cannot unpack "+string)
        return Offer(Stock.parse(stock), int(price.strip()))

    def __init__(self, stock: Stock, price: int):
        self.stock = stock
        self.price = price
        try:
            self.price_per_unit = self.price/self.stock.amount
        except ZeroDivisionError:
            self.price_per_unit = float('inf')

    def __str__(self):
        return "%s$%s"%(self.stock, self.price)

    def __repr__(self):
        return repr(self.stock)+OFFER_DELIMITER+str(int(self.price))


def read_stock_value(value: str):
    global hidden_price, hidden_stock
    stock, price = value.split(STOCK_DELIMITER)
    hidden_price = float(price)
    hidden_stock = int(stock)
    log.write("Hidden StockID: %s\nHidden Price: %s\n"%(hidden_stock, hidden_price))

def process_input():
    handlers = {
        "SecretValue": read_stock_value,
        "RandomSeed": read_seed,
        "MakeOffer": make_offer,
        "AcceptOffer": accept_offer,
        "AcceptedOffers": accepted_offers,
    }
    method = input().strip()
    data = input().strip()
    output = handlers[method](data)
    if output is not None:
        print(repr(output))
    else:
        print()

def read_seed(seed: str):
    random.seed(int(seed))

def start():
    while True:
        process_input()

hidden_stock = None
hidden_price = None

def filter_offers(offer):
    if offer.stock.amount == 0:
        return False
    if offer.price_per_unit > 1000:
        return False
    return True

def certain_profit(offer):
    stock = offer.stock
    if stock.type == hidden_stock and offer.price_per_unit < hidden_price:
        log.write("Offer, %s is certainly profitable.\n"%offer)
        return True
    return False

def make_offer(current_stock: str):
    current_stock = list(map(Stock.parse, current_stock.split(LIST_DELIMITER)))
    own_stock = [stock for stock in current_stock if stock.type == hidden_stock]
    if own_stock and own_stock[0]:
        own_stock = own_stock[0]
        amount_sold = min(random.randrange(1,50), own_stock.amount)
        price = hidden_price+random.randrange(10,50)
        return Offer(Stock(hidden_stock, amount_sold), price*amount_sold)
    sell_stock = random.choice(current_stock)
    amount_sold = min(random.randrange(1,50), sell_stock.amount)
    price = random.randrange(1000, JAVA_MAX_INT//(amount_sold or 1))
    return Offer(Stock(sell_stock.type, amount_sold), price*(amount_sold or 1))

def accept_offer(available_offers: str):
    available_offers = list(map(Offer.parse, available_offers.split(LIST_DELIMITER)))
    filtered_offers = list(filter(filter_offers, available_offers))
    profitable = list(filter(certain_profit, filtered_offers))
    rtn_list = filtered_offers
    if profitable:
        log.write("Profitable: %s\n"%profitable)
        rtn_list = profitable
    if not rtn_list:
        return None
    accepted_offer = min(rtn_list, key=lambda offer: offer.price_per_unit)
    log.write("Bidded for %s\n"%accepted_offer)
    return accepted_offer

def accepted_offers(offers: str):
    pass


if __name__ == "__main__":
    try:
        start()
    finally:
        log.close()

Всегда старается продать скрытые акции больше, чем стоит.

синий
источник