Skip to content

Instantly share code, notes, and snippets.

@okunishinishi
Last active March 4, 2019 10:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save okunishinishi/9bd81161665388ed2e62fb9914e902f6 to your computer and use it in GitHub Desktop.
Save okunishinishi/9bd81161665388ed2e62fb9914e902f6 to your computer and use it in GitHub Desktop.
婚活において積極的行動が必要な理由をGSアルゴリズムで検証してみる ref: https://qiita.com/okunishinishi@github/items/b26a1293dd510a302f37
const shuffle = require('shuffle-array')
function defineMembers (memberCount = 10) {
const men = shuffle(new Array(memberCount).fill(null).map((_, i) => ({
name: `man#${i}`,
rejectedBy: [], // 自分を拒否した異性の名前
likes: [], // 好みの異性
})))
const women = shuffle(new Array(memberCount).fill(null).map((_, i) => ({
name: `woman#${i}`,
proposedBy: [], // プロポーズしてきた異性の名前
keeps: null, // キープしている異性。最後まで残ったら結ばれる
likes: [], // 好みの異性
})))
for (const m of men) {
// 好みの順に異性を登録
m.likes = shuffle(women).map(({name}) => name)
}
for (const w of women) {
// 好みの順に異性を登録
w.likes = shuffle(men).map(({name}) => name)
}
return {men, women}
}
const memberCount = 10
const {men, women} = defineMembers(memberCount)
// 配列だけだと不便なのでnameをキーにした辞書を用意
const menByName = Object.assign({}, ...men.map((man) => ({
[man.name] : man
})))
const womenByName = Object.assign({}, ...women.map((woman) => ({
[woman.name] : woman
})))
// 複数回ラウンドを行う
const rounds = 4
for (let round = 0; round < rounds; round++) {
// Men側
for (const m of men) {
const isKept = women.some(({keeps}) => keeps === m.name)
if (!isKept) {
    // キープされていない孤独なmenはまだ自分をrejectしてない最良の相手を探す
const best = m.likes.find((name) => !m.rejectedBy.includes(name))
if (best) {
// 最良のWomanにプロポーズする
womenByName[best].proposedBy.push(m.name)
}
}
}
// Women側
for (const w of women) {
// プロポーズして来た相手を、暫定一位とその他に切り分ける
const [best, ...notGoodEnough] = w.proposedBy.sort((a, b) =>
w.likes.indexOf(a) - w.likes.indexOf(b)
)
w.keeps = best || null // 一番良いのをキープ
for (const n of notGoodEnough) {
menByName[n].rejectedBy.push(w.name) // それ以外は拒否
}
}
}
// ゲームが終わった時点でキープしている場合に成約とする
const couples = women
.map(({name, keeps}) => keeps ? [name, keeps] : null)
.filter(Boolean)
.map(([wName, mName]) => [
womenByName[wName],
menByName[mName]
])
const successCount = couples.length
const failureCount = memberCount - successCount
console.log(`${successCount} success, ${failureCount} failure`)
console.log(
couples.map(([w, m]) => [
// それぞれの名前と、何番目に好みの相手と結ばれたかを表示する
w.name, w.likes.indexOf(m.name), m.name, m.likes.indexOf(w.name)
])
)
10 success, 0 failure
[ [ 'woman#1', 1, 'man#3', 0 ],
[ 'woman#2', 0, 'man#1', 1 ],
[ 'woman#7', 0, 'man#7', 0 ],
[ 'woman#5', 0, 'man#0', 1 ],
[ 'woman#8', 7, 'man#6', 2 ],
[ 'woman#3', 2, 'man#8', 0 ],
[ 'woman#4', 1, 'man#4', 1 ],
[ 'woman#9', 1, 'man#2', 0 ],
[ 'woman#0', 4, 'man#5', 1 ],
[ 'woman#6', 9, 'man#9', 2 ] ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment