Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PIXEL selling and buyEnergy #706

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/brain_main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const {checkPlayers} = require('./diplomacy');
const {handleQuests} = require('./quests');
const {prepareMemory} = require('./brain_memory');
const {handlePixel} = require('./brain_pixel');

global.cpuUsed = 0;

Expand Down Expand Up @@ -86,6 +87,9 @@ module.exports.execute = function() {
try {
prepareMemory();
brain.buyPower();
if (config.pixel.enabled && Game.cpu.generatePixel) {
handlePixel();
}
brain.handleNextroomer();
brain.handleSquadManager();
brain.handleIncomingTransactions();
Expand All @@ -104,7 +108,7 @@ module.exports.execute = function() {
});

if (global.config.tickSummary.gcl) {
console.log(`${Game.time} GCL ${Game.gcl.level}: ${global.utils.leftPadRound(Game.gcl.progress/Game.gcl.progressTotal*100, 3, 5)} % ${Math.round(Game.gcl.progress)}/${Math.round(Game.gcl.progressTotal)}`);
console.log(`${Game.time} GCL ${Game.gcl.level}: ${global.utils.leftPadRound(Game.gcl.progress / Game.gcl.progressTotal * 100, 3, 5)} % ${Math.round(Game.gcl.progress)}/${Math.round(Game.gcl.progressTotal)}`);
}
if (global.config.tickSummary.bucket) {
console.log(`${Game.time} Bucket: ${Game.cpu.bucket}`);
Expand Down
40 changes: 40 additions & 0 deletions src/brain_pixel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use strict';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the brain prefix anymore. I would just call it pixel.js


const {debugLog} = require('./logging');
const pixelLog = (message) => {
debugLog('pixel', message);
};

module.exports.handlePixel = function() {
if (typeof PIXEL !== 'undefined') {
// generate PIXEL
if (Game.cpu.bucket >= PIXEL_CPU_COST + config.pixel.minBucketAfter) {
global.load = Math.round(Game.cpu.getUsed());
Game.cpu.generatePixel();
const pixel = Game.resources[PIXEL] || '';
const deltaPixel = Game.time - (global.data.pixel || 0);
pixelLog(`PIXEL generated!\tCurrent ${pixel + 1}\t delta: ${deltaPixel} \t load: ${global.load}`);
global.data.pixel = Game.time;
}

// sell PIXEL, make money to buy energy
if (config.pixel.sell && Game.resources[PIXEL] > config.pixel.minPixelAmount) {
const buyOrder = _.sortBy(Game.market.getAllOrders({type: 'buy', resourceType: PIXEL}), (o) => -o.price)[0];
if (buyOrder) {
const history = Game.market.getHistory(PIXEL);
const lastDay = history[history.length - 1];
if (lastDay) {
const minPriceToSell = (lastDay.avgPrice - (config.pixel.allowedSalesHistoryDeviation * lastDay.stddevPrice)).toPrecision(3);
if (buyOrder.price >= minPriceToSell) {
pixelLog(`PIXEL pices: ${buyOrder.price}\tamount: ${buyOrder.amount}\tlastDay.avgPrice: ${lastDay.avgPrice}\tlastDay.stddevPrice: ${lastDay.stddevPrice}\tminPrice: ${minPriceToSell}`);
const amount = Math.min(buyOrder.amount, Game.resources[PIXEL] - config.pixel.minPixelAmount);
Game.market.deal(buyOrder.id, amount);
pixelLog(`PIXEL sold!\t${buyOrder.price} @ ${amount}`);
}
}
} else {
pixelLog(`PIXEL has no bestOrder ${buyOrder}`);
}
}
}
};
13 changes: 10 additions & 3 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ global.config = {

pixel: {
enabled: false,
sell: true,
allowedSalesHistoryDeviation: 0.05,
minPixelAmount: 500,
minBucketAfter: 2500,
},

Expand Down Expand Up @@ -289,11 +292,15 @@ global.config = {
maxBuyPrice: 0.5,
// buyByOwnOrders: true,
buyOrderPriceMultiplicand: 0.5,

// buy energy, let make use of our credits
buyEnergy: {
enabled: true,
allowedSalesHistoryDeviation: 0.05,
},
// buy power if we have more credits than config.market.minCredits
buyPower: false,
// 300M credits
minCredits: 300000000,
// 300K credits
minCredits: 300000,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have as minCredits the price of an access key, which is currently around 500M.
So we shouldn't reduce this, if you prefer you can change it in your local config.

What do you think?

// disable to use power only in gathered room
sendPowerOwnRoom: true,
// equalizes the energy between your rooms via terminal
Expand Down
8 changes: 1 addition & 7 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,7 @@ module.exports.loop = function() {
execute();
}
}
if (global.config.pixel.enabled) {
if (typeof PIXEL !== 'undefined') {
if (Game.cpu.bucket >= PIXEL_CPU_COST + global.config.pixel.minBucketAfter) {
Game.cpu.generatePixel();
}
}
}

brain.stats.updateCpuStats();

if (config.resourceStats) {
Expand Down
64 changes: 62 additions & 2 deletions src/prototype_room_market.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Room.prototype.sellByOwnOrders = function(resource, sellAmount) {

Room.prototype.sellByOthersOrders = function(sellAmount, resource, force) {
const sortByEnergyCostAndPrice = (order) => Game.market.calcTransactionCost(sellAmount, this.name, order.roomName) +
-order.price * sellAmount / config.market.energyCreditEquivalent;
-order.price * sellAmount / config.market.energyCreditEquivalent;
if (Memory.orders[ORDER_BUY][resource]) {
const orders = _.sortBy(Memory.orders[ORDER_BUY][resource].orders, sortByEnergyCostAndPrice);
for (const order of orders) {
Expand Down Expand Up @@ -194,7 +194,7 @@ Room.prototype.sendEnergyToMyRooms = function() {
const myRoom = _.shuffle(Memory.needEnergyRooms)[0];
const room = Game.rooms[myRoom];
if (!room) {
Memory.needEnergyRooms.splice( Memory.needEnergyRooms.indexOf(myRoom), 1 );
Memory.needEnergyRooms.splice(Memory.needEnergyRooms.indexOf(myRoom), 1);
return;
}
const amount = this.sendEnergyAmountToMyRoom();
Expand All @@ -213,13 +213,73 @@ Room.prototype.sendEnergyToMyRooms = function() {
return false;
};

/**
* make use of the credits we earn from selling PIXEL
*
* @return {ERR_NOT_FOUND|boolean}
*/
Room.prototype.buyEnergy = function() {
if (!this.isRoomReadyForMineralHandling()) {
this.debugLog('market', 'not ReadyForMineralHandling');
return false;
}
if (!config.market.buyEnergy || Game.market.credits < config.market.minCredits || (this.terminal.cooldown > 0)) {
this.debugLog('market', 'config cooldown or no credits');
return false;
}
// todo maybe use this.getEnergy()
const energyInRoom = (this.terminal.store.getUsedCapacity(RESOURCE_ENERGY) + this.storage.store.getUsedCapacity(RESOURCE_ENERGY));
if (energyInRoom > (config.terminal.maxEnergyAmount + config.terminal.minEnergyAmount)) {
this.debugLog('market', 'room has energy');
return false;
}
const returnCode = this.getEnergyLogic();
if (returnCode === ERR_NOT_FOUND) {
// no orders found, next time check for low price
this.data.allowedSalesHistoryDeviation = ((this.data.allowedSalesHistoryDeviation || 0) + config.market.buyEnergy.allowedSalesHistoryDeviation);
this.debugLog('market', this.data.allowedSalesHistoryDeviation);
}
};

Room.prototype.getEnergyLogic = function() {
try {
this.data.allowedSalesHistoryDeviation = this.data.allowedSalesHistoryDeviation || config.market.buyEnergy.allowedSalesHistoryDeviation;
const filterOrders = {type: ORDER_SELL, resourceType: RESOURCE_ENERGY};
const sellOrder = _.sortBy(Game.market.getAllOrders(filterOrders), (o) => o.price)[0];
if (sellOrder) {
const history = Game.market.getHistory(RESOURCE_ENERGY);
const lastDay = history[history.length - 1];
if (lastDay) {
const maxPrice = parseFloat('' + (lastDay.avgPrice + (this.data.allowedSalesHistoryDeviation * lastDay.stddevPrice))).toPrecision(4);
this.debugLog('market', `maxPrice ${maxPrice}\t${lastDay.avgPrice} + (${this.data.allowedSalesHistoryDeviation} * ${lastDay.stddevPrice})`);
if (sellOrder.price <= maxPrice) {
const amount = Math.min(config.terminal.minEnergyAmount, sellOrder.amount, this.terminal.store.getFreeCapacity());
const returnCode = Game.market.deal(sellOrder.id, amount, this.name);
this.debugLog('market', 'market.deal:', sellOrder.id, amount, this.name);
if (returnCode === OK) {
return true;
} else if (![ERR_TIRED, ERR_NOT_ENOUGH_RESOURCES].indexOf(returnCode)) {
this.debugLog('market', `market.deal: ${returnCode}`);
return false;
}
}
}
}
} catch (e) {
this.debugLog('market', e.message);
}
return ERR_NOT_FOUND;
};

Room.prototype.handleMarket = function() {
if (!this.terminal || this.terminal.cooldown) {
return false;
}
this.sellOwnMineral();
this.buyLowResources();
this.buyLowCostResources();
this.buyEnergy();

if (config.market.sendPowerOwnRoom) {
this.sendPowerOwnRooms();
}
Expand Down
64 changes: 39 additions & 25 deletions src/quests.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


const {debugLog} = require('./logging');

/**
Expand Down Expand Up @@ -68,7 +66,7 @@ function getQuest(transaction, data) {
/**
* haveActiveQuest
*
* @return {bool}
* @return {boolean}
*/
function haveActiveQuest() {
if (!global.data.activeQuest) {
Expand All @@ -93,7 +91,7 @@ module.exports.haveActiveQuest = haveActiveQuest;
* getQuestFromTransactionDescription
*
* @param {object} description
* @return {bool}
* @return {boolean}
*/
function getQuestFromTransactionDescription(description) {
let data;
Expand All @@ -107,7 +105,6 @@ function getQuestFromTransactionDescription(description) {
debugLog('quests', 'Quest transaction: No type');
return false;
}
console.log(JSON.stringify(data));
for (const key of ['type', 'action', 'id']) {
if (!data[key]) {
debugLog('quests', `Incoming transaction no Quest: No ${key}`);
Expand All @@ -129,17 +126,22 @@ function getQuestFromTransactionDescription(description) {
* checkQuestForAcceptance
*
* @param {object} transaction
* @return {bool}
* @return {boolean}
*/
function checkQuestForAcceptance(transaction) {
Memory.quests = Memory.quests || {};
transaction.description = transaction.description || JSON.stringify({
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this change.
This sets the description of the transaction to some 'random' value.

type: 'quest',
action: 'apply',
id: _.first(Memory.quests),
});
const data = getQuestFromTransactionDescription(transaction.description);
if (!data) {
return false;
}
if (Memory.quests[data.id]) {
console.log(`Quest already ongoing ${JSON.stringify(data)}`);
return;
return false;
}
const quest = getQuest(transaction, data);
console.log(`Found quest acceptance on transaction ${JSON.stringify(quest)}`);
Expand All @@ -158,6 +160,7 @@ function checkQuestForAcceptance(transaction) {
const terminalResponse = room.terminal.send(RESOURCE_ENERGY, 100, transaction.from, JSON.stringify(response));
console.log(`terminalResponse ${JSON.stringify(terminalResponse)}`);
// TODO find reserver in room and remove quest hint
return true;
}

module.exports.checkQuestForAcceptance = checkQuestForAcceptance;
Expand All @@ -166,35 +169,46 @@ module.exports.checkQuestForAcceptance = checkQuestForAcceptance;
* checkAppliedQuestForAcceptance
*
* @param {object} transaction
* @return {bool}
* @return {boolean}
*/
function checkAppliedQuestForAcceptance(transaction) {
let response;
try {
const response = JSON.parse(transaction.description);
if (!response.type) {
debugLog('quests', `No type: ${JSON.stringify(response)}`);
}
if (response.type !== 'quest') {
debugLog('quests', `Wrong type: ${JSON.stringify(response)}`);
try {
response = JSON.parse(transaction.description);
} catch (e) {
debugLog('quests', e.toString(), JSON.stringify(transaction));
return false;
}
if (response.action) {
debugLog('quests', `Action exist type: ${JSON.stringify(response)}`);
return false;
if (response) {
if (!response.type) {
debugLog('quests', `No type: ${JSON.stringify(response)}`);
return false;
}
if (response.type !== 'quest') {
debugLog('quests', `Wrong type: ${JSON.stringify(response)}`);
return false;
}
if (response.action) {
debugLog('quests', `Action exist type: ${JSON.stringify(response)}`);
return false;
}
debugLog('quests', `Quest accept transaction: ${JSON.stringify(response)}`);
if (!haveActiveQuest()) {
debugLog('quests', 'No active quest');
return false;
}
global.data.activeQuest.state = 'active';
global.data.activeQuest.accept = response;
debugLog('quests', `activeQuest: ${JSON.stringify(global.data.activeQuest)}`);
return true;
}
debugLog('quests', `Quest accept transaction: ${JSON.stringify(response)}`);
if (!haveActiveQuest()) {
debugLog('quests', 'No active quest');
return false;
}
global.data.activeQuest.state = 'active';
global.data.activeQuest.accept = response;
debugLog('quests', `activeQuest: ${JSON.stringify(global.data.activeQuest)}`);
} catch (e) {
console.log('checkAppliedQuestForAcceptance');
console.log(e);
console.log(e.stack);
return false;
}
}

module.exports.checkAppliedQuestForAcceptance = checkAppliedQuestForAcceptance;