}, | }, | ||||
"dependencies": { | "dependencies": { | ||||
"core-js": "^3.6.5", | "core-js": "^3.6.5", | ||||
"vue": "^3.0.0" | |||||
"vue": "^3.0.0", | |||||
"vue-underscore": "^0.1.4" | |||||
}, | }, | ||||
"devDependencies": { | "devDependencies": { | ||||
"@vue/cli-plugin-babel": "~4.5.0", | "@vue/cli-plugin-babel": "~4.5.0", | ||||
"babel-eslint": "^10.1.0", | "babel-eslint": "^10.1.0", | ||||
"eslint": "^6.7.2", | "eslint": "^6.7.2", | ||||
"eslint-plugin-vue": "^7.0.0-0", | "eslint-plugin-vue": "^7.0.0-0", | ||||
"sass-loader": "10.1.1", | |||||
"node-sass": "^5.0.0" | |||||
"node-sass": "^5.0.0", | |||||
"sass-loader": "10.1.1" | |||||
}, | }, | ||||
"eslintConfig": { | "eslintConfig": { | ||||
"root": true, | "root": true, |
</button> | </button> | ||||
</div> | </div> | ||||
<Intro v-show="activeTab === 'Intro'" class="tabs__body" /> | |||||
<Intro v-if="activeTab === 'Intro'" class="tabs__body" /> | |||||
<Pots | <Pots | ||||
v-show="activeTab === 'Pots'" | |||||
v-if="activeTab === 'Pots'" | |||||
class="tabs__body" | class="tabs__body" | ||||
:pots="pots" | :pots="pots" | ||||
@removePot="removePot" | @removePot="removePot" | ||||
@addPot="addPot" | @addPot="addPot" | ||||
/> | /> | ||||
<Jams | <Jams | ||||
v-show="activeTab === 'Jams'" | |||||
v-if="activeTab === 'Jams'" | |||||
class="tabs__body" | class="tabs__body" | ||||
:jams="jams" | :jams="jams" | ||||
@removeJam="removeJam" | @removeJam="removeJam" | ||||
@addJam="addJam" | @addJam="addJam" | ||||
/> | /> | ||||
<Result v-show="activeTab === 'Result'" class="tabs__body" /> | |||||
<Result | |||||
v-if="activeTab === 'Result'" | |||||
class="tabs__body" | |||||
:propPots="pots" | |||||
:propJams="jams" | |||||
/> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<style lang="scss" scoped> | <style lang="scss" scoped> | ||||
#app { | #app { | ||||
margin-top: 60px; | |||||
margin: 1rem; | |||||
} | } | ||||
.tabs { | .tabs { | ||||
max-width: 1440px; | max-width: 1440px; | ||||
margin: 1rem; | |||||
margin: 60px auto; | |||||
min-height: 75vh; | min-height: 75vh; | ||||
display: flex; | display: flex; | ||||
flex-direction: column; | flex-direction: column; |
<template> | <template> | ||||
<div> | |||||
Result | |||||
<div v-if="isProcessing" class="progress"> | |||||
<progress>Разливаем...</progress> | |||||
</div> | |||||
<div v-else> | |||||
<h2 v-if="result.state == 'error'" class="error"> | |||||
{{ result.message }} | |||||
</h2> | |||||
<div v-for="jam in jams" :key="jam.id"> | |||||
<h3> | |||||
Варенье: {{ jam.id }}, всего сварено: {{ jam.vol }} мл, | |||||
<span v-if="jam.restVol > 0" class="error" | |||||
>осталось не розлито: {{ jam.restVol }} мл</span | |||||
> | |||||
<span v-else>розлито полностью</span> | |||||
</h3> | |||||
<ul> | |||||
<li v-for="pot in jam.pots" :key="pot.id"> | |||||
<span | |||||
>Банка <b>{{ pot.id }}</b> ({{ pot.vol }} мл)</span | |||||
> | |||||
— | |||||
<span> залито {{ pot.jamVol }} мл</span> | |||||
— | |||||
<span v-if="pot.isFull"> полная</span> | |||||
<b v-else class="error"> | |||||
недолив {{ pot.vol - pot.jamVol }} мл</b | |||||
> | |||||
</li> | |||||
</ul> | |||||
</div> | |||||
<div v-if="emptyPots.length > 0"> | |||||
<hr> | |||||
<h4>Остались пустые банки:</h4> | |||||
<ul> | |||||
<li v-for="pot in emptyPots" :key="pot.id"> | |||||
<b>{{ pot.id }}</b> ({{ pot.vol }} мл) | |||||
</li> | |||||
</ul> | |||||
</div> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script> | <script> | ||||
import { _ } from "vue-underscore"; | |||||
export default { | export default { | ||||
setup () { | |||||
props: ["propPots", "propJams"], | |||||
data() { | |||||
return { | |||||
isProcessing: false, | |||||
pots: [], | |||||
jams: [], | |||||
result: { state: "initial" }, | |||||
}; | |||||
}, | |||||
mounted: function () { | |||||
this.isProcessing = true; | |||||
this.pots = _.map(this.propPots, _.clone); | |||||
this.jams = _.map(this.propJams, _.clone); | |||||
this.result = fillPots(this.pots, this.jams); | |||||
// console.log("result", this.result); | |||||
// console.log("jams", this.jams); | |||||
this.isProcessing = false; | |||||
}, | |||||
computed: { | |||||
emptyPots: function () { | |||||
return this.pots.filter((p) => p.jamVol === 0); | |||||
}, | |||||
}, | |||||
}; | |||||
function fillPots(pots, jams) { | |||||
prepare(pots, jams); | |||||
// Сперва попытаемся разлить варенья по банкам, заполняя их по максимуму | |||||
// Приоритет отдаем самым большим банкам, чтобы не лазать в погреб лишний раз | |||||
let isDone = false; | |||||
let isFoundSolution; | |||||
do { | |||||
isFoundSolution = false; | |||||
for (const jam of jams) { | |||||
for (const pot of pots) { | |||||
if (!pot.isFilled && pot.vol <= jam.restVol) { | |||||
pot.jamId = jam.id; | |||||
pot.jamVol = Math.min(pot.vol, jam.restVol); | |||||
pot.isFilled = true; | |||||
pot.isFull = true; | |||||
jam.restVol -= pot.vol; | |||||
jam.pots.push(pot); | |||||
isFoundSolution = true; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
} while (!isDone && isFoundSolution); | |||||
// А теперь разливаем остатки по самым маленьким из оставшихся банок | |||||
isDone = true; | |||||
for (const jam of jams) { | |||||
if (jam.restVol > 0) { | |||||
for (let i = pots.length - 1; i > 0; i--) { | |||||
if (!pots[i].isFilled && pots[i].vol >= jam.restVol) { | |||||
pots[i].jamId = jam.id; | |||||
pots[i].jamVol = jam.restVol; | |||||
pots[i].isFilled = true; | |||||
pots[i].isFull = pots[i].vol === jam.restVol; | |||||
jam.restVol = 0; | |||||
jam.pots.push(pots[i]); | |||||
break; | |||||
} | |||||
} | |||||
if (jam.restVol !== 0) { | |||||
isDone = false; | |||||
} | |||||
} | |||||
} | |||||
if (!isDone) { | |||||
return { | |||||
state: "error", | |||||
message: "Не удалось разлить варенья", | |||||
}; | |||||
} | |||||
return { state: "success" }; | |||||
function prepare(pots, jams) { | |||||
pots.sort(sortByVolDesc); | |||||
jams.sort(sortByVolDesc); | |||||
for (const pot of pots) { | |||||
pot.isFilled = false; | |||||
pot.isFull = false; | |||||
pot.jamId = null; | |||||
pot.jamVol = 0; | |||||
} | |||||
return {} | |||||
for (const jam of jams) { | |||||
jam.restVol = jam.vol; | |||||
jam.pots = []; | |||||
} | |||||
function sortByVolDesc(a, b) { | |||||
if (a.vol > b.vol) { | |||||
return -1; | |||||
} else if (a.vol < b.vol) { | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} | |||||
} | } | ||||
} | } | ||||
</script> | </script> | ||||
<style lang="scss" scoped> | <style lang="scss" scoped> | ||||
.progress { | |||||
height: 100%; | |||||
display: flex; | |||||
align-items: center; | |||||
progress { | |||||
width: 100%; | |||||
} | |||||
} | |||||
.error { | |||||
color: orangered; | |||||
} | |||||
</style> | </style> |
module.exports = { | |||||
publicPath: './' | |||||
}; |
commander "~2.19.0" | commander "~2.19.0" | ||||
source-map "~0.6.1" | source-map "~0.6.1" | ||||
underscore@^1.8.3: | |||||
version "1.12.0" | |||||
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.0.tgz#4814940551fc80587cef7840d1ebb0f16453be97" | |||||
integrity sha512-21rQzss/XPMjolTiIezSu3JAjgagXKROtNrYFEOWK109qY1Uv2tVjPTZ1ci2HgvQDA16gHYSthQIJfB+XId/rQ== | |||||
unicode-canonical-property-names-ecmascript@^1.0.4: | unicode-canonical-property-names-ecmascript@^1.0.4: | ||||
version "1.0.4" | version "1.0.4" | ||||
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" | resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" | ||||
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825" | resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825" | ||||
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw== | integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw== | ||||
vue-underscore@^0.1.4: | |||||
version "0.1.4" | |||||
resolved "https://registry.yarnpkg.com/vue-underscore/-/vue-underscore-0.1.4.tgz#c3dcee26a6e0279df29448a6041a7e64c20981aa" | |||||
integrity sha1-w9zuJqbgJ53ylEimBBp+ZMIJgao= | |||||
dependencies: | |||||
underscore "^1.8.3" | |||||
vue@^3.0.0: | vue@^3.0.0: | ||||
version "3.0.6" | version "3.0.6" | ||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.0.6.tgz#2c16ed4bb66f16d6c6f6eaa3b7d5835a76598049" | resolved "https://registry.yarnpkg.com/vue/-/vue-3.0.6.tgz#2c16ed4bb66f16d6c6f6eaa3b7d5835a76598049" |