-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
118 lines (101 loc) · 3.2 KB
/
index.js
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/* eslint-disable no-unused-vars */
const fs = require('fs');
const solver = require('./node_modules/javascript-lp-solver');
const CSVToJSON = require('./resources/csvToJson');
const { getDeckSizeConstraints, getCardFormatConstraints } = require('./constraints');
const { getInts, getOptimize, getVariables } = require('./entries');
const { downloadMtgJsonZip, unzipJson, getMtgJsonVersion } = require('./resources/resources');
const deckSize = 100;
const landCount = 40;
const maxCardCount = 1;
/**
* Create the variables as entries (list of tuples)
* [
* [name, {data}],
* [name, {data}],
* ]
*/
const getVariablesEntries = (jsonData) => jsonData.reduce((memo, curr) => {
const { 'Card Name': name, ...data } = curr;
if (name) {
memo.push([name, data]);
}
return memo;
}, []);
const tacticConstraints = [
['Ramp', { min: 10 }],
['Board Wipe', { min: 10 }],
// ['Discard synergy', { min: 10 }],
// ['Zombie Synergy', { min: 10 }],
// ['instants Synergy', { min: 5 }],
// ['Return things to hand', { min: 15 }],
];
const deckSizeContraints = getDeckSizeConstraints(deckSize, landCount);
// Read in the sample data (card list with tactics)
const data = fs.readFileSync('sample_data.csv')
.toString().trim();
const jsonData = CSVToJSON(data);
const variablesEntries = getVariablesEntries(jsonData);
const cardFormatConstraints = getCardFormatConstraints(variablesEntries, maxCardCount);
// Make contraints from the all our entries,
const constraints = Object.fromEntries([
...cardFormatConstraints,
...tacticConstraints,
deckSizeContraints,
]);
const ints = getInts(variablesEntries);
const optimize = getOptimize(variablesEntries);
/**
* Create the variables object, from entries.
*
* Each Card also gets a category for it's name (so we can enforce card number lmitis),
* As well as this, we give each card a 'cards' category (so we can enforce deck size)
* [
* [cardName, {
* cat1: score1,
* cat2: score2,
* ...
* cardName: 1,
* cards: 1
* }]
* ]
*/
const variables = getVariables(variablesEntries);
// Combine all the objects, into our model
const model = {
optimize,
constraints,
variables,
ints,
options: {
// these options allow the procees to finish
tolerance: 0.1,
timeout: 100000,
},
};
// Let the library solve the model
const results = solver.Solve(model);
// Vertices are the solutions to individual constraints
// Any card with a score of 0 is not included
// in the proposed deck
const filteredVerts = results.vertices.map((vertex) => Object.fromEntries(
Object.entries(vertex)
.filter(([dim, score]) => Boolean(score)),
));
// console.log(filteredVerts);
// Midpoint is the arithmetic mean of all individual solutions
// console.log(results.midpoint);
// Ranges show minium and maximum values
// across all of th vertices
// good as a diagnostic for which solutions
// don't include tactics, which can be fed back in
// to the tacticConstraints
// console.log(Object.fromEntries(
// Object.entries(results.ranges)
// .filter(([name, score]) => score.min >= 0)
// )
// )
getMtgJsonVersion().then(
(version) => console.info(version),
(...args) => console.error(...args));
// downloadMtgJsonZip().then(() => unzipJson());