Created
August 1, 2020 19:02
-
-
Save zackexplosion/e13c3fdae7057667139b9e3774897d3f to your computer and use it in GitHub Desktop.
抽獎機率設定
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div id="app"> | |
<!-- top buttons --> | |
<template> | |
<el-button @click="addItem">新增物品</el-button> | |
<el-button @click="showTestDialog">測試</el-button> | |
<el-button type="primary" @click="showGetItemMessage">開獎</el-button> | |
</template> | |
<!-- the main ui --> | |
<template> | |
<h1>機率設定</h1> | |
<!-- <el-input-number v-model="chanceInputStep"> </el-input-number> --> | |
<el-table :data="tableData" style="width: 100%"> | |
</el-table-column> | |
<el-table-column label="物品名稱" width="180"> | |
<template slot-scope="scope"> | |
<el-input v-model="scope.row.name" /> | |
</template> | |
</el-table-column> | |
<el-table-column label="機率"> | |
<template slot-scope="scope"> | |
<span style="margin-left: 10px">{{ (scope.row.p * 100).toFixed(0) }}%</span> | |
<el-input-number style="margin-left:8px" v-model="scope.row.p" controls-position="right" :step="0.01" @change="(newValue) => {countTotalChance(newValue, scope.$index)}"> | |
</el-input-number> | |
</template> | |
</el-table-column> | |
</el-table> | |
<pre>{{tableData}}</pre> | |
</template> | |
<!-- the test dialog --> | |
<el-dialog title="測試抽獎機率" :visible.sync="testDialogVisible" width="80%" center> | |
<div style="text-align:center;"> | |
<span>要測試幾次呢?</span> | |
<el-input-number v-model="testTimes" controls-position="right"> | |
</el-input-number> | |
<div class="testprogress"> | |
<el-progress type="circle" :percentage="testPercentage" :status="testPercentage >= 100 ? 'success' : ''"></el-progress> | |
</div> | |
<pre v-if="runnningTest">{{ testMessage }}</pre> | |
<div v-if="testResult.length > 0 && runnningTest === false"> | |
<h2>測試結果</h2> | |
<el-table :data="testResult" style="width: 100%"> | |
<el-table-column prop="name" label="物品名稱"> | |
</el-table-column> | |
<el-table-column prop="count" label="出現次數"> | |
</el-table-column> | |
<el-table-column prop="chance" label="出現機率"> | |
</el-table-column> | |
<el-table-column prop="chanceBySetting" label="設定的機率"> | |
</el-table-column> | |
</el-table> | |
</div> | |
</div> | |
<span slot="footer" class="dialog-footer"> | |
<el-button @click="testDialogVisible = false">取消</el-button> | |
<el-button type="primary" @click="startTest">開始</el-button> | |
</span> | |
</el-dialog> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Main = { | |
data() { | |
return { | |
// p means Probability, init data | |
tableData: [ | |
{ | |
name: "喔喔,請下次再來", | |
p: 0.5 | |
}, | |
{ | |
name: "A", | |
p: 0.3 | |
}, | |
{ | |
name: "SSS", | |
p: 0.2 | |
} | |
], | |
testTimes: 10000, | |
testMessage: "waiting for test...", | |
runnningTest: true, | |
runnningTestDone: false, | |
testResult: [], | |
testDialogVisible: false, | |
chanceInputStep: 0.1, | |
testPercentage: 0 | |
}; | |
}, | |
methods: { | |
showTestDialog() { | |
// just reset data | |
this.testMessage = "waiting for test..."; | |
this.runnningTest = true; | |
this.testResult = []; | |
this.testDialogVisible = true; | |
this.testPercentage = 0; | |
}, | |
startTest() { | |
// setup variables | |
this.runnningTest = true; | |
this.testResult = []; | |
this.testPercentage = 0; | |
var chance = {}; | |
this.tableData.forEach((i) => { | |
chance[i.name] = 0; | |
}); | |
var i = 0; | |
// run in next tick (after vue view updated) | |
this.$nextTick(() => { | |
var interval = setInterval(() => { | |
if (i === this.testTimes) { | |
clearInterval(interval); | |
this.runnningTest = false; | |
// create test result | |
Object.keys(chance).forEach((_, index) => { | |
this.testResult.push({ | |
name: _, | |
count: chance[_], | |
chance: Math.round((chance[_] / this.testTimes) * 100) + "%", | |
chanceBySetting: this.tableData[index].p * 100 + "%" | |
}); | |
}); | |
} else { | |
// get the item, render testMessage update chance coutner | |
const item = this.getItemByChange(); | |
chance[item.name]++; | |
// this.testMessage = JSON.stringify(item, null, 4); | |
this.testMessage = item; | |
i++; | |
} | |
// update the progress bar | |
this.testPercentage = parseInt((i / this.testTimes) * 100); | |
}, 1); | |
}); | |
}, | |
// add new item to the list | |
addItem() { | |
this.tableData.push({ | |
name: "new Item", | |
p: 0 | |
}); | |
}, | |
// put the item on the number line and check if on the range | |
getItemByChange() { | |
const r = Math.random(); | |
let count = 0; | |
let item; | |
// 從第一個開始排,看哪個會到隨機數字,有到他的範圍抽出來內的話,就抽出來 | |
for (let i = 0; i < this.tableData.length; i++) { | |
let _ = this.tableData[i]; | |
// console.log("count", r, count, count + _.p); | |
// 假設 r 是 0.7, 第一圈判斷開始 | |
// 0.7 >= 0 && 0.7 <= 0 + 0.5 | |
// return false 下一圈 | |
// 0.7 >= 0.5 && 0.7 <= 0.8(count = count + _.p) 上一圈判斷失敗加的 | |
// return true 找到了! | |
if (r >= count && r <= count + _.p) { | |
// yes, it's in range! | |
item = _; | |
break; | |
} else { | |
// not in range, going to next loop | |
count = count + _.p; | |
} | |
} | |
return item; | |
}, | |
showGetItemMessage() { | |
const item = this.getItemByChange(); | |
this.$confirm( | |
`您抽到的是 『${item.name}』, 他有 ${(item.p * 100).toFixed( | |
2 | |
)}%的機率被抽中`, | |
"開獎囉!", | |
{ | |
confirmButtonText: "再抽一次", | |
cancelButtonText: "取消" | |
// type: "warning" | |
} | |
).then(() => { | |
this.showGetItemMessage(); | |
}); | |
}, | |
getNextAvaiableItemIndex(currentIndex) { | |
let index = currentIndex - 1; | |
if (index < 0) index = this.tableData.length - 1; | |
if (this.tableData[index].p <= 0) { | |
index--; | |
} | |
return index; | |
}, | |
// when the value changed, we must make sure the sum of items chance is "1" | |
countTotalChance(value, index) { | |
var total = 0; | |
this.tableData.forEach((_) => { | |
total += _.p; | |
}); | |
var number_to_plus = (number_to_plus = 1 - total); | |
number_to_plus = parseFloat(number_to_plus.toFixed(4)); | |
let next_index = this.getNextAvaiableItemIndex(index); | |
this.tableData[next_index].p = Number( | |
(this.tableData[next_index].p + number_to_plus).toFixed(4) | |
); | |
} | |
} | |
}; | |
var Ctor = Vue.extend(Main); | |
new Ctor().$mount("#app"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.13.2/index.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.testprogress { | |
margin-top: 1em; | |
text-align: center; | |
} | |
pre { | |
margin-top: 1em; | |
text-align: left; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment