You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
3.1 KiB
JavaScript
136 lines
3.1 KiB
JavaScript
const Bucket = require('./bucket');
|
|
const { fill, empty, pour } = require('./action');
|
|
|
|
class Buckets {
|
|
constructor(buckets = []) {
|
|
this.buckets = buckets;
|
|
}
|
|
|
|
hasTarget(target) {
|
|
return !!this.buckets.find(bucket => bucket.volume === target)
|
|
}
|
|
|
|
performAction(action) {
|
|
if (action.isEmpty()) {
|
|
this.buckets[action.target].empty()
|
|
}
|
|
if (action.isFill()) {
|
|
this.buckets[action.target].fill()
|
|
}
|
|
if (action.isPour()) {
|
|
this.buckets[action.src].pour(this.buckets[action.target])
|
|
}
|
|
}
|
|
|
|
possibleActions() {
|
|
const ret = []
|
|
this.buckets.forEach((bucket, index) => {
|
|
if (!bucket.isFull()) {
|
|
ret.push(fill(index));
|
|
}
|
|
if (!bucket.isEmpty()) {
|
|
ret.push(empty(index));
|
|
this.buckets.forEach((dest, j) => {
|
|
if (index === j) {
|
|
return
|
|
}
|
|
if (!dest.isFull()) {
|
|
ret.push(pour(index, j));
|
|
}
|
|
})
|
|
}
|
|
})
|
|
return ret
|
|
}
|
|
|
|
string() {
|
|
return this.buckets.map(bucket => bucket.string()).join(', ')
|
|
}
|
|
|
|
findTarget(target) {
|
|
const results = {
|
|
mapping: { [this.string()]: [[]] },
|
|
matching: new Set(),
|
|
}
|
|
this._findTarget(target, results, [], 0)
|
|
|
|
let best = null
|
|
|
|
results.matching.forEach(matchingKey => {
|
|
const result = results.mapping[matchingKey]
|
|
if (best === null) {
|
|
best = result;
|
|
return
|
|
}
|
|
if (best[0].length == result[0].length) {
|
|
best.push(result);
|
|
}
|
|
if (best[0].length > result[0].length) {
|
|
best = result;
|
|
}
|
|
})
|
|
|
|
return best || []
|
|
}
|
|
|
|
_findTarget(target, state, actions = [], depth = 0) {
|
|
if (this.hasTarget(target)) {
|
|
return
|
|
}
|
|
const possibleActions = this.possibleActions();
|
|
const results = possibleActions.map(action => {
|
|
const copy = fromJSON(this);
|
|
copy.performAction(action);
|
|
return copy;
|
|
});
|
|
|
|
const numberOfKeys = Object.keys(state.mapping).length
|
|
|
|
results.forEach(((result, i) => {
|
|
const key = result.string();
|
|
const existingActions = state.mapping[key];
|
|
const action = possibleActions[i];
|
|
|
|
if (result.hasTarget(target)) {
|
|
debugger
|
|
state.matching.add(result.string());
|
|
}
|
|
|
|
if (!existingActions) {
|
|
state.mapping[key] = [[...actions, action]]
|
|
return
|
|
}
|
|
|
|
if (existingActions[0].length == actions.length + 1) {
|
|
state.mapping[key].push([...actions, possibleActions[i]])
|
|
return
|
|
}
|
|
|
|
if (existingActions[0].length > actions.length + 1) {
|
|
state.mapping[key] = [[...actions, action]]
|
|
}
|
|
}));
|
|
|
|
if (Object.keys(state.mapping).length === numberOfKeys) {
|
|
return
|
|
}
|
|
|
|
results.forEach(((result, i) => {
|
|
const action = possibleActions[i];
|
|
result._findTarget(target, state, [...actions, action], depth + 1)
|
|
}))
|
|
}
|
|
}
|
|
|
|
function fromJSON(json) {
|
|
const jsonStr = JSON.stringify(json)
|
|
const newJSON = JSON.parse(jsonStr)
|
|
const buckets = newJSON.buckets.map(val => new Bucket(val));
|
|
return new Buckets(buckets)
|
|
}
|
|
|
|
module.exports = {
|
|
fromJSON,
|
|
Buckets,
|
|
}
|