Skip to content

Instantly share code, notes, and snippets.

@zackexplosion
Created August 1, 2020 19:02
Show Gist options
  • Save zackexplosion/e13c3fdae7057667139b9e3774897d3f to your computer and use it in GitHub Desktop.
Save zackexplosion/e13c3fdae7057667139b9e3774897d3f to your computer and use it in GitHub Desktop.
抽獎機率設定
<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>
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");
<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>
.testprogress {
margin-top: 1em;
text-align: center;
}
pre {
margin-top: 1em;
text-align: left;
}
<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