/*************************************************************************** Aldo -------------------- begin : Sun May 6 2001 copyright : Giuseppe "denever" Martino email : denever@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301 USA * * * ***************************************************************************/ #include "resources.hh" #include "blocks.hh" #include "koch.hh" #include #include #include #include #include // width of screen in characters #define TERMINAL_WIDTH 80 // markers for the correspondence between keyed symbol and copied symbol #define CORRECT_MARKER '.' #define INCORRECT_MARKER '!' #define MISSED_MARKER '@' using namespace std; typedef map::const_iterator c_map; typedef list< string >::const_iterator c_lststr; typedef string::const_iterator c_str; /* * Returns a string truncated or padded to a given length. The padding is to * the right and the padding character is 'MISSED_MARKER'. */ string padding(unsigned int len, const string& b) { int s = len - b.size(); if(s > 0) return b + string(s,MISSED_MARKER); if(s < 0) return string(b, 0, len); return b; } /* * This function computes the width in characters for representing an integer * in base 10. It is useful in determining the maximum with needed for * displaying a loop counter, such that vertical alignment can be achieved. */ size_t width_base_10(const size_t n) { size_t n_width = 0; for (size_t n_max = n; n_max > 0; n_max /= 10) { ++n_width; } return n_width; } /* * This function displays the copy success rate. */ void display_overall_rate(const unsigned int percentage) { cout<& lks, const list& lcs) { map keyed_all; map keyed_bad; map keyed_missed; map copied_all; map copied_good; map copied_bad; // compute results // iterate over the lists of strings c_lststr lks_it; c_lststr lcs_it; for(lks_it = lks.begin(), lcs_it = lcs.begin(); lks_it != lks.end() && lcs_it != lcs.end(); ++lks_it, ++lcs_it ) { // ensure that the copied string is as long as the keyed string, // padding it with 'MISSED_MARKER' if necessary string copied = padding((*lks_it).size(), *lcs_it); // iterate over the characters in each group c_str kit; c_str cit; for(kit = (*lks_it).begin(), cit = copied.begin(); kit != (*lks_it).end(); ++kit, ++cit ) { char kc = *kit; // keyed symbol char cc = *cit; // copied sybmol keyed_all[kc]++; // mark keyed symbol copied_all[cc]++; // mark copied symbol if(kc == cc) { // keyed symbol was copied correctly copied_good[cc]++; } else if(cc != MISSED_MARKER) { // keyed symbol was copied incorrectly keyed_bad[kc]++; copied_bad[cc]++; } else { // keyed symbol was missed keyed_missed[kc]++; } } } // display results cout< get_marked_strings(const list& lks, const list& lcs) { list< string > lms; //list of marked strings c_lststr lks_it = lks.begin(); c_lststr lcs_it = lcs.begin(); while(lks_it != lks.end()) if(lcs_it != lcs.end()) { lms.push_back(mark_mistakes(*lks_it, *lcs_it)); ++lks_it; ++lcs_it; } else { lms.push_back( string((*lks_it).size(), INCORRECT_MARKER) ); ++lks_it; } return lms; } /* * This function displays the keyed sign groups and the copied sign groups * alongside each other, accompanied by markers which indicate the positions * of the copying mistakes. */ void display_comparison(const list& lks, const list& lcs) { // display evaluation header cout< lms = get_marked_strings(lks, lcs); // temporary variables for preparing output lines ostringstream mistaken_row_formatter; string mistaken_row; string keyed_row; string copied_row; // how many characters are needed for representing the highest index size_t n_width = width_base_10(lks.size()); // indentation string for keyed and copied strings string indent = string(n_width, ' '); // format the evaluation strings // (loop with iterators over the lists of strings) unsigned int n; c_lststr lms_it = lms.begin(); c_lststr lks_it = lks.begin(); c_lststr lcs_it = lcs.begin(); for( n = 1 ; lms_it != lms.end() && lks_it != lks.end() && lcs_it != lcs.end() ; ++n, ++lms_it, ++lks_it, ++lcs_it ) { mistaken_row_formatter << " "; mistaken_row_formatter.width(n_width); mistaken_row_formatter << n << ":" << *lms_it; keyed_row += indent + "k:" + *lks_it; copied_row += indent + "c:" + padding((*lks_it).size(), *lcs_it); } mistaken_row = mistaken_row_formatter.str(); // display evaluation cells, breaking the lines at or before TERMINAL_WIDTH // (TERMINAL_WIDTH / cell_width) feedback cells fit on a row // cell_width is the sum of: // 1 character blank to separate the cells // n_width characters for the counter // 1 character blank between the counter and the sign group // size() characters for the sign group unsigned int cell_width = 2 + n_width + lks.front().size(); // how many characters to use in a screen row, // such that lines break at cell border unsigned int used_width = (TERMINAL_WIDTH / cell_width) * cell_width; // loop over the screen rows for(size_t pos = 0; pos < mistaken_row.size(); pos += used_width) { // display output lines cout << mistaken_row.substr(pos, used_width) << endl; // e.g. 12:!.!.@@! cout << keyed_row.substr(pos, used_width) << endl; // eishtmo cout << copied_row.substr(pos, used_width) << endl; // aibh@@d cout << endl; } } /* * This function lets the user input the copied sign groups */ list get_copied_strings(unsigned int num_groups) { list lcs; cout << endl << chkmsg_1 << endl; cout << chkmsg_2 << endl; // how many characters are needed for representing the highest index int i_width = width_base_10(num_groups); for(unsigned int i=0; i& lks, const list& lcs) { double wrong_letters = 0.0; double total = 0.0; c_lststr lks_it = lks.begin(); c_lststr lcs_it = lcs.begin(); while(lks_it != lks.end()) { total += (*lks_it).size(); if(lcs_it != lcs.end()) { wrong_letters += count_wrong_letters(*lks_it, *lcs_it); ++lks_it; ++lcs_it; } else { wrong_letters += (*lks_it).size(); ++lks_it; } } double wrong_tax = wrong_letters/total; return int(100 - 100 * wrong_tax); } /* * This function lets the user input the copied sign groups and displays * information about how well an exercise was completed. * Its goal is to help the user discover the areas where improvement is possible. */ unsigned int check(const libexercises::Blocks& current_exercise) { list lks = current_exercise.tokenize(); // list of keyed strings list lcs = get_copied_strings(lks.size()); // list of copied strings cout << endl << fbkmsg_title << endl; // introduce the feedback information unsigned int overall_rate = get_overall_rate(lks, lcs); // overall success rate display_overall_rate(overall_rate); // display overall success rate display_symbol_rate(lks, lcs); // display success rate per keyed symbol display_comparison(lks, lcs); // display comparison between keyed and copied sign groups cout< lks = current_exercise.tokenize(); // list of keyed strings list lcs = get_copied_strings(lks.size()); // list of copied strings cout << endl << fbkmsg_title << endl; // introduce the feedback information unsigned int overall_rate = get_overall_rate(lks, lcs); // overall success rate display_overall_rate(overall_rate); // display overall success rate display_symbol_rate(lks, lcs); // display success rate per keyed symbol display_comparison(lks, lcs); // display comparison between keyed and copied sign groups cout<