var sprintf = require('sprintf-js').sprintf; var _ = require('underscore'); var config = require('../config'); var chalk = require('../chalk'); var log = require('../log'); var core = require('../core'); var session = require('../session'); var h = require('../helper'); var cmd = { command: 'stat', desc: 'Show statistics', aliases: ['stats', 'progress', 'report'], builder: function(yargs) { return yargs .option('g', { alias: 'graph', type: 'boolean', default: false, describe: 'Show graphic statistics' }) .option('l', { alias: 'lock', type: 'boolean', default: true, describe: 'Include locked questions' }) .option('t', { alias: 'tag', type: 'string', default: 'all', describe: 'Show statistics for given tag', choices: ['all'].concat(config.sys.categories) }) .example(chalk.yellow('leetcode stat'), 'Show progress status') .example(chalk.yellow('leetcode stat --no-lock'), 'Show progress status without locked questions') .example(chalk.yellow('leetcode stat -t algorithms'), 'Show progress status of algorithms questions') .example(chalk.yellow('leetcode stat -g'), 'Show detailed status in graph'); } }; function bar(c, n) { return _.range(n) .map(function(i) { return c; }) .join(''); } function printLine(key, done, all) { var n = 30; var percent = (all > 0) ? done / all : 0; var x = Math.ceil(n * percent); log.printf(' %s\t%3d/%-3d (%.2f%%) %s%s', h.prettyLevel(key), done, all, 100 * percent, chalk.green(bar('█', x)), chalk.red(bar('░', n - x))); } function showProgress(problems) { var stats = { easy: {all: 0, ac: 0}, medium: {all: 0, ac: 0}, hard: {all: 0, ac: 0} }; problems.forEach(function(problem) { var level = problem.level.toLowerCase(); var state = problem.state.toLowerCase(); if (!(level in stats)) return; ++stats[level].all; if (!(state in stats[level])) return; ++stats[level][state]; }); printLine('Easy', stats.easy.ac, stats.easy.all); printLine('Medium', stats.medium.ac, stats.medium.all); printLine('Hard', stats.hard.ac, stats.hard.all); } function showGraph(problems) { var icons = { ac: chalk.green(h.isWindows() ? 'O ' : '▣ '), notac: chalk.red(h.isWindows() ? 'X ' : '▤ '), none: chalk.gray(h.isWindows() ? 'o ' : '⬚ '), empty: ' ' }; // row header is 4 bytes // each question takes 2 bytes // each group has 10 questions, which takes (2*10=20) + 3 paddings var groups = Math.floor((h.width - 4) / (3 + 2 * 10)); if (groups < 1) groups = 1; if (groups > 5) groups = 5; var header = _.range(groups) .map(function(x) { return sprintf('%5d%18d', x * 10 + 1, x * 10 + 10); }) .join(''); log.info(' ' + header); var graph = []; _.each(problems, function(problem) { graph[problem.id] = icons[problem.state] || icons.none; }); var line = [sprintf(' %03d', 0)]; for (var i = 1, n = graph.length; i <= n; ++i) { // padding before group if (i % 10 === 1) line.push(' '); line.push(graph[i] || icons.empty); // time to start new row if (i % (10 * groups) === 0 || i === n) { log.info(line.join('')); line = [sprintf(' %03d', i)]; } } log.info(); log.printf('%7s%s%3s%s%3s%s', ' ', icons.ac + chalk.green(' Accepted'), ' ', icons.notac + chalk.red(' Not Accepted'), ' ', icons.none + ' Remaining'); log.info(); } cmd.handler = function(argv) { session.argv = argv; core.getProblems(function(e, problems) { if (e) return log.fail(e); if (argv.tag !== 'all') { problems = _.filter(problems, function(x) { return x.category === argv.tag; }); } if (!argv.lock) { problems = _.filter(problems, function(x) { return !x.locked; }); } if (argv.graph) return showGraph(problems); showProgress(problems); }); }; module.exports = cmd;