Logo Search packages:      
Sourcecode: aldo version File versions  Download package

check.cc

/***************************************************************************
                                 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 <iostream>
#include <string>
#include <sstream>
#include <list>
#include <map>

// width of screen in characters
#define TERMINAL_WIDTH 80

// use less than max width of unsigned int for displaying counter
#define COUNTER_WIDTH 2

// character for marking mistakes
#define MISTAKE_MARKER '!'

using namespace std;

typedef map<char, unsigned int>::const_iterator c_map;
typedef list< string >::const_iterator c_lststr;
typedef string::const_iterator c_str;

/*
 * This function displays the copy success rate.
 */
void display_overall_rate(const unsigned int percentage)
{
    cout<<endl<<ovrmsg_title<<": ";
    cout.width(3);
    cout<<percentage<<'%'<<endl;
}

/*
 * This function displays the copy success rate per keyed symbol.
 */
void display_symbol_rate(const list<string>& lks, const list<string>& lcs)
{
    map<char, unsigned int> total;
    map<char, unsigned int> correct;

    c_lststr lks_it = lks.begin();
    c_lststr lcs_it = lcs.begin();

    while(lks_it != lks.end() && lcs_it != lcs.end())
    {
          c_str kit = (*lks_it).begin();
          c_str cit = (*lcs_it).begin();

          while(kit != (*lks_it).end())
            if(cit != (*lcs_it).end())
            {
                total[*kit]++;

                if(*kit == *cit)
                  correct[*kit]++;

                ++kit;
                ++cit;
            }
            else
            {
                total[*kit]++;
                correct[*kit] = 0;
                ++kit;
            }

          ++lks_it;
          ++lcs_it;
    }
    
    cout<<endl<<smbmsg_title<<':'<<endl; // display feedback category "title"
    cout<<smbmsg_percentage<<"%-'"<<smbmsg_symbol<<"'-("
      <<smbmsg_copiedok<<'/'<<smbmsg_keyed<<')'<<endl;    // display legend

    for(c_map mtc = total.begin(); mtc != total.end(); ++mtc)
    {
      cout.width(3);
      cout<<100*correct[(*mtc).first]/(*mtc).second<<"%-'"<<(*mtc).first<<"'-("
          <<correct[(*mtc).first]<<'/'<<(*mtc).second<<')'<<endl;
    }
}

/*
 * This function takes a keyed sign group and a copied sign group and
 * generates a mistakes string of the same length. The mistakes string
 * contains mistake marker characters at the positions where the keyed
 * and the copied strings differ and unobtrusive spacer characters at
 * the other positions.
 */
string mark_mistakes(const string keyed, const string copied)
{
    string mistakes;     // start with empty string

    c_str kit = keyed.begin();
    c_str cit = copied.begin();

    while(kit != keyed.end())
      if(cit != copied.end())
      {
          if(*kit == *cit)
            mistakes += '.';  // unobtrusive spacer
          else
            mistakes += MISTAKE_MARKER;
          ++kit;
          ++cit;        
      }
      else
      {
          mistakes += MISTAKE_MARKER;
          ++kit;
      }
//    mistakes = string(keyed.size(), MISTAKE_MARKER); // if copied key has a different lenght of keyed all letters are wrong

    return mistakes;
}

list<string> get_marked_strings(const list<string>& lks, const list<string>& 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(), MISTAKE_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.
 */
//[1] How many feedback cells fit horizontally
// The width of the feedback cell for one sign group consists of:
//             1 empty position to separate the cells
// COUNTER_WIDTH positions for the counter
//             1 position between the counter and the sign group
//        strlen positions for the sign group

string padding(unsigned int len, const string& b)
{
    int s = len - b.size();   
    if(s > 0)
      return b + string(s,'@');

    if(s < 0)
      return string(b, 0, len);

    return b;
} 

void display_comparison(const list<string>& lks, const list<string>& lcs)
{
    list<string> lms = get_marked_strings(lks, lcs);
    c_lststr lks_it = lks.begin();
    c_lststr lcs_it = lcs.begin();
    c_lststr lms_it = lms.begin();

    unsigned int columns = TERMINAL_WIDTH / (2 + COUNTER_WIDTH + (*lks_it).size()); // [1]
    string indent = string(COUNTER_WIDTH + 2, ' ');     // indentation string
    string legend_indent = string( string(cmpmsg_group).length() + 2, ' ');     // indentation string

    cout<<endl<<cmpmsg_title<<':'<<endl;     // display feedback category "title"

    cout<<' '<<cmpmsg_group<<':';     // print feedback legend
    cout<<cmpmsg_mistakes<<" '"<<MISTAKE_MARKER<<'\''<<endl;    // e.g. ##:Mistakes - marked with '!'
    cout<<legend_indent<<cmpmsg_keyed<<endl;    //         Keyed signs - what was transmitted
    cout<<legend_indent<<cmpmsg_copied<<endl;   //         Copied signs - what you have input
    cout<<endl;

    // temporary variables for preparing output lines
    ostringstream keyed_row;
    ostringstream copied_row;
    ostringstream mistaken_row;

    unsigned int n = 0; // tracks sign groups

    for(unsigned int i=0; i< lks.size()/columns; i++)     // process full feedback cell rows
    {
      if(lks_it == lks.end() || lcs_it == lcs.end())
          break;

      for(unsigned int j=0; j<columns; j++)
      {
          n = i*columns + j;

          // append cell to output lines
          mistaken_row << " ";
          mistaken_row.width(COUNTER_WIDTH);
          mistaken_row << (n+1) << ":" << *lms_it;
          keyed_row << indent << *lks_it;
          copied_row << indent << padding((*lks_it).size(), *lcs_it);
      }

      // display output lines
      cout << mistaken_row.str() << endl; // e.g. 12:!.!..!!
      cout << keyed_row.str() << endl;    //         eishtmo
      cout << copied_row.str() << endl;   //         aibhtcd
      cout << endl;

      // reset output lines
      keyed_row.clear();
      copied_row.clear();
      mistaken_row.clear();

      ++lks_it;
      ++lcs_it;
      ++lms_it;
      ++i;
    }

    while(lks_it != lks.end() && lcs_it != lcs.end())     // process leftover fedback cells
    {
      // append cell to output lines
      mistaken_row << " ";
      mistaken_row.width(COUNTER_WIDTH);
      mistaken_row << (n+1) << ":" << *lms_it;
      keyed_row << indent << *lks_it;
      copied_row << indent << padding((*lks_it).size(), *lcs_it);
      ++lks_it;
      ++lcs_it;
      ++lms_it;
    }

    // display any leftover feedback cells
    if(lks.size()%columns)
    {
      // display rows
      cout << mistaken_row.str() << endl;
      cout << keyed_row.str() << endl;
      cout << copied_row.str() << endl;
      cout << endl;
    }
}

/*
 * This function lets the user input the copied sign groups
 */
list<string> get_copied_strings(unsigned int num_groups)
{
    list<string> lcs;

    cout << endl << chkmsg_1 << endl;
    cout << chkmsg_2 << endl;

    for(unsigned int i=0; i<num_groups; i++)
    {
      string tmp;
      cout.width(COUNTER_WIDTH);
      cout << (i+1) << ": ";
      cin >> tmp;
      lcs.push_back(tmp);
    }
    return lcs;
}

/*
 * This function compares two strings and returns lets the user input the copied sign groups
 */
unsigned int count_wrong_letters(string keyed, string copied)
{
    unsigned int wrong_letters = 0;

    c_str kit = keyed.begin();
    c_str cit = copied.begin();

    while(kit != keyed.end())
      if(cit != copied.end())
      {
          if(*kit != *cit)
            wrong_letters++;

          ++kit;
          ++cit;        
      }
      else
      {
          wrong_letters++;
          ++kit;
      }

    //wrong_letters = keyed.size(); // if copied key has a different lenght of keyed all letters are wrong

    return wrong_letters;
}

unsigned int get_overall_rate(const list<string>& lks, const list<string>& 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<string> lks = current_exercise.tokenize(); // list of keyed strings
    list<string> 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<<endl;

    return overall_rate;
}

/*
 * This function lets the user input the copied sign groups and displays
 * feedback about how it went.
*/
unsigned int check(const libexercises::Koch& current_exercise)
{
    list<string> lks = current_exercise.tokenize(); // list of keyed strings
    list<string> 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<<endl;

    return overall_rate;
}

Generated by  Doxygen 1.6.0   Back to index