Skip to content

Instantly share code, notes, and snippets.

@hakatashi
Created September 30, 2018 09:03
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 hakatashi/b428d6e2db5d932a1a1f553933194fa9 to your computer and use it in GitHub Desktop.
Save hakatashi/b428d6e2db5d932a1a1f553933194fa9 to your computer and use it in GitHub Desktop.
const fs = require('fs');
const {promisify} = require('util');
const {get} = require('lodash');
(async () => {
const json = await promisify(fs.readFile)('dynamo-archive-sandbox-messages-201808280017.json');
const data = json.toString().split('\n').filter((line) => line.length).map((line) => JSON.parse(line));
data.sort((a, b) => a.ts.S.localeCompare(b.ts.S));
const battles = [];
let timestamp = new Date(0);
let theme = '';
let meanings = [];
let matches = null;
let url = '';
for (const message of data) {
const user = get(message, ['bot_id', 'S']);
const ts = get(message, ['ts', 'S']);
const text = get(message, ['text', 'S'], '');
const attachments = get(message, ['attachments', 'L'], []).map(({M}) => M);
if (text === 'たほいや') {
timestamp = new Date(parseFloat(ts) * 1000);
continue;
}
if (user !== 'B7PBPKTLP') {
continue;
}
if ((matches = text.match(/^\*(.+?)\* の正しい意味/m))) {
theme = matches[1];
if ((matches = text.match(/^<(http.+?)>$/m))) {
url = matches[1];
}
continue;
}
if (text.startsWith('今回の対戦結果')) {
meanings = attachments.map((attachment) => {
const title = get(attachment, ['title', 'S'], '').replace(/^\d+\. /, '');
const textContent = get(attachment, ['text', 'S'], '');
const info = {};
if ((matches = title.match(/^(.+?) by <@(.+?)>$/))) {
info.text = matches[1];
info.type = 'user';
info.user = matches[2];
} else if ((matches = title.match(/^(.+?) \((.+?)\)/))) {
info.text = matches[1];
info.type = 'dummy';
info.source = matches[2].includes(':') ? matches[2].split(':')[0].trim() : 'wikipedia';
info.title = matches[2].includes(':') ? matches[2].split(':')[1].trim() : matches[2].trim();
} else if ((matches = title.match(/^(.*?) :o:/))) {
info.text = matches[1];
info.type = 'correct';
} else {
console.log(title);
throw new Error();
}
if (textContent === '-') {
info.betters = [];
} else {
matches = textContent.match(/<@.+?> \(.+?枚\)/g) || [];
info.betters = matches.map((match) => {
const submatches = match.match(/^<@(.+?)> \((.+?)枚\)$/);
return {
user: submatches[1],
coins: parseInt(submatches[2]),
};
});
}
return info;
});
if (meanings.length !== 0) {
battles.push({timestamp, theme, meanings, url});
}
}
}
await promisify(fs.writeFile)('battles.json', JSON.stringify(battles));
console.log('done');
})();
const battles = require('./tahoiya-data.json');
const moment = require('moment');
for (const [i, {timestamp, theme, meanings, url}] of battles.entries()) {
const users = meanings.filter(({type}) => type === 'user').map(({user}) => user);
const urlTitle = decodeURI(url.match(/([^/]+)$/)[1]);
const urlSource = url.startsWith('https://ja.wikipedia.org') ? 'Wikipedia' : 'ウィクショナリー日本語版'
console.log(`
# 第${i + 1}回 「**${theme}**」
* **日時** ${moment(timestamp).utcOffset('+0900').format('YYYY-MM-DD HH:mm:ss')}
* **参加者** ${users.map((user) => `@${user}`).join(' ')} (${users.length}人)
${meanings.map((meaning, i) => `${i + 1}. ${meaning.text}`).join('\n')}
<details>
<summary>答え</summary>
${meanings.map((meaning, i) => {
let text = '';
if (meaning.type === 'user') {
text = `${i + 1}. ${meaning.text} (@${meaning.user})`;
} else if (meaning.type === 'dummy') {
text = `${i + 1}. ${meaning.text} (${meaning.source}: ${meaning.title})`;
} else if (meaning.type === 'correct') {
text = `${i + 1}. ⭕️**${meaning.text}**`;
}
return text;
}).join('\n')}
出典: [${urlTitle} - ${urlSource}](${url})
</details>
`.replace(/^\t+/gm, ''));
}
const battles = require('./battles.json');
const moment = require('moment');
const ratings = new Map();
let previousTimestamp = null;
for (const [i, {timestamp, meanings}] of battles.entries()) {
if (previousTimestamp === timestamp) {
continue;
}
const users = meanings.filter(({user}) => user).map(({user}) => user);
const newRatings = new Map(users.map((user) => [user, 0]));
const correctMeaningIndex = meanings.findIndex(({type}) => type === 'correct');
for (const user of users) {
const betMeaning = meanings.findIndex(({betters}) => betters.some((bet) => bet.user === user));
const bet = betMeaning !== -1 ? meanings[betMeaning].betters.find((bet) => bet.user === user) : [];
const betting = betMeaning !== -1 ? {meaning: betMeaning, coins: bet.coins} : {meaning: null, coins: 1};
if (betting.meaning === correctMeaningIndex) {
newRatings.set(user, newRatings.get(user) + betting.coins);
} else {
newRatings.set(user, newRatings.get(user) - betting.coins - 1);
if (betting.meaning !== null) {
const misdirectedUser = meanings[betting.meaning].user;
if (misdirectedUser) {
newRatings.set(misdirectedUser, newRatings.get(misdirectedUser) + betting.coins);
}
}
}
}
for (const [user, rating] of newRatings.entries()) {
if (!ratings.has(user)) {
ratings.set(user, []);
}
ratings.get(user).push({timestamp, rating});
}
previousTimestamp = timestamp;
}
const data = {};
for (const [user, rating] of ratings.entries()) {
data[user] = rating.slice(-5);
}
console.log(JSON.stringify(data));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment