| }, | }, | ||||
| "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" |