Showing posts with label code. Show all posts
Showing posts with label code. Show all posts

Monday, September 10, 2007

C++: Fun With Comments

There's much fun to be had with C++ comments, and a lot of seriously usable tricks there as well. Of course, most of programmers already know all I could tell about the subject, but nonetheless, I think I'll take a shot at bringing all the techniques I think might be useful together, and I might be able to use a few possible tricks that a possible visitor would possibly leave on this post!
The first thing any programmer has to realize about comments is that (as their name suggests)
Comments are not the code that the compiler doesn't see, but the sentences that a human would read.
Write comments (and code in general) for another human (or you yourself) to read. This generally means you should generally avoid too clever constructs that have no other advantage. I say it again: Write code for other humans to read, not the compiler to compile.
You can use special comments and tools like doxygen to generate useful, beautiful, always-up-to-date and comprehensive documentation of your source codes automatically, with little extra work (e.g. with putting a line with three slashes ("///") at the beginning and describing the purpose of a function before its prototype.) These kinds of tools make you appreciate the value of comments!
My first advice is never use "//" or "/*" to comment out a piece of code. Those characters are reserved for "comments", i.e for writing descriptions of your code! Always put another character (or sequence of characters) after them, and use different characters to distinguish the different situations in which you've commented out the code. For example, use "//0" and "/*0" for code that you suspect is incorrect, use "//1" and "/*1" for test code, and so on and so forth. Keep in mind that these are only suggestions. Any system you opt to use, must be documented somewhere. Write 10 lines to describe the meaning and connotation of the 10 different types of comments you use. Don't take this lightly! As time goes by and you write more code, you'll accumulate these rules and split or merge them, but your commenting rules become more comprehensive, more concise and more useful.
Anyway, suppose you want to comment a multi-line piece of code. Always put the comment openning and closing on a line by themselves. No code on those lines! Also, use "//*/" for the closing marker (instead of just "*/".) This way, you can uncomment and recomment that part with only a single character; a '/' that you add to or remove from the beginning of the openning marker. Look at snippets 1 and 2.
There are times that you want to switch between commenting two parts of a single line. In these situations, you can put "/**" before the first part, put "/*/" between the two parts and "/**/" after the second part. Like snippets 3 and 4, you can then switch between the first part being commented out and the second one by adding a single '/' after the comment before the first part. (Also note the parsing/formatting bug of jEdit on line 18!)
You can also do it in the slightly prettier way that snippets 5 and 6 demonstrate (I really think so!) but only if you want to switch between two multi-line segments of code.
Commenting large blocks with "/*" and "*/" has a major problem. The commented blocks don't nest. For this reason, I suggest the cleaner method of using "#if 0", "#else" and "#endif" blocks (snippets 7 and 8, but they lack the coloring.) This way, not only you can nest commented out blocks inside of each other and enable/disable them individually just changing the '0' to '1' (provided the outer blocks are not disabled) but also you can comment the commented-outness(!) of these peices, and you can use preprocessor macros instead of just '0' to be able to switch these segments on and off from elsewhere. The only problem is that many editors and IDEs don't process preprocessor directives and they won't colorify the disabled parts as inactive.
In your "comment" comments, you can use well-recognized keywords like "NOTE", "WARNING", "TODO" and "FIXME" to make their meanings more apparent and to searching for them easier. Just remember to use them neatly and consistently.
If you have more ideas for using comments, I'd be happy to hear about them and to include them here. By the way, anybody has a clean and pretty way of switching (commenting/uncommenting) among three or more segments of code?
   1://{Snippet 1}
   2:/*0
   3:    for (unsigned i = 0; i < v.size(); ++i)
   4:        swap (v[i], v[v.size() - 1 - i]);
   5://*/
   6:
   7://{Snippet 2}
   8://*0
   9:    for (unsigned i = 0; i < v.size(); ++i)
  10:        swap (v[i], v[v.size() - 1 - i]);
  11://*/
  12:
  13://{Snippet 3}
  14:    for (unsigned i = 0; i < /**/ v.size() /*/ v.size() / 2 /**/; ++i)
  15:        swap (v[i], v[v.size() - 1 - i]);
  16:        
  17://{Snippet 4}
  18:    for (unsigned i = 0; i < /** v.size() /*/ v.size() / 2 /**/; ++i)
  19:        swap (v[i], v[v.size() - 1 - i]);
  20:        
  21://{Snippet 5}
  22:/*0
  23:    for (unsigned i = 0; i < v.size(); ++i)
  24:        swap (v[i], v[v.size() - 1 - i]);
  25:/*/
  26:    for (unsigned i = 0; i < v.size() / 2; ++i)
  27:        swap (v[i], v[v.size() - 1 - i]);
  28://*/
  29:        
  30://{Snippet 6}
  31://*0
  32:    for (unsigned i = 0; i < v.size(); ++i)
  33:        swap (v[i], v[v.size() - 1 - i]);
  34:/*/
  35:    for (unsigned i = 0; i < v.size() / 2; ++i)
  36:        swap (v[i], v[v.size() - 1 - i]);
  37://*/
  38:        
  39://{Snippet 7}
  40:#if 0
  41:    for (unsigned i = 0; i < v.size(); ++i)
  42:        swap (v[i], v[v.size() - 1 - i]);
  43:#else
  44:    for (unsigned i = 0; i < v.size() / 2; ++i)
  45:        swap (v[i], v[v.size() - 1 - i]);
  46:#endif
  47:        
  48://{Snippet 8}
  49:#if 1
  50:    for (unsigned i = 0; i < v.size(); ++i)
  51:        swap (v[i], v[v.size() - 1 - i]);
  52:#else
  53:    for (unsigned i = 0; i < v.size() / 2; ++i)
  54:        swap (v[i], v[v.size() - 1 - i]);
  55:#endif
UPDATE:I was wrong about the parsing/formatting bug in jEdit I mentioned above. That's a Doxygen comment and jEdit handles it correctly. Oops!

Monday, May 07, 2007

Program Printing Its Source Code

I get asked this a lot. For some reason, many people want to write programs that display their own source code upon execution, and most of those people don't use Google. So I just decided to write something up and put it here. It's by no means short or concise. It's midnight for crying out loud!
   1:#include <stdio.h>
   2:const char pre [] = {32, 32, 32, 32, 34};
   3:const char post [] = {34, 44, 10};
   4:const char * lines [] = {
   5:    "#include <stdio.h>",
   6:    "const char pre [] = {32, 32, 32, 32, 34};",
   7:    "const char post [] = {34, 44, 10};",
   8:    "const char * lines [] = {",
   9:    "};",
  10:    "int main ()",
  11:    "{",
  12:    "    for (size_t i = 0; i < 4; ++i)",
  13:    "        puts (lines[i]);",
  14:    "    for (size_t i = 0; i < sizeof(lines) / sizeof(const char *); ++i)",
  15:    "    {",
  16:    "        printf (pre);",
  17:    "        printf (lines[i]);",
  18:    "        printf (post);",
  19:    "    }",
  20:    "    for (size_t i = 4; i < sizeof(lines) / sizeof(const char *); ++i)",
  21:    "        puts (lines[i]);",
  22:    "    return 0;",
  23:    "}",
  24:};
  25:int main ()
  26:{
  27:    for (size_t i = 0; i < 4; ++i)
  28:        puts (lines[i]);
  29:    for (size_t i = 0; i < sizeof(lines) / sizeof(const char *); ++i)
  30:    {
  31:        printf (pre);
  32:        printf (lines[i]);
  33:        printf (post);
  34:    }
  35:    for (size_t i = 4; i < sizeof(lines) / sizeof(const char *); ++i)
  36:        puts (lines[i]);
  37:    return 0;
  38:}
  39:

This is the simplest exact solution I could come up with (not the shortest.) Note that if you run this program and then run the output again and again, it generates exactly the same result. Note that the indentation is done with spaces, not tab characters.
There's a name for this kind of program and I think it starts with a 'p', but I can't be certain.

Tuesday, December 19, 2006

Sharif ICPC Regionals 2006 - Problem D

   1:#include <map>
   2:#include <string>
   3:#include <vector>
   4:#include <fstream>
   5:#include <iomanip>
   6:#include <iostream>
   7:#include <algorithm>
   8:
   9:using namespace std;
  10:
  11:#define PROB_NAME   "D"
  12:
  13:struct Emp
  14:{
  15:    pair<int, bool> data [2];   
  16:    Emp () {data[0].first = -1; data[0].second = true; data[1].first = -1; data[1].second = true;}
  17:};
  18:
  19:pair<int, bool> Q (int cur, const vector<vector<int> > & children, vector<Emp> & mem);
  20:
  21:pair<int, bool> P (int cur, const vector<vector<int> > & children, vector<Emp> & mem)
  22:{
  23:    if (mem[cur].data[0].first >= 0) return mem[cur].data[0];
  24:    
  25:    pair<int, bool> ret (1, true);
  26:    for (unsigned i = 0; i < children[cur].size(); ++i)
  27:    {
  28:        pair<int, bool> r = Q(children[cur][i], children, mem);
  29:        ret.first += r.first;
  30:        ret.second = (ret.second && r.second);
  31:    }
  32:    return mem[cur].data[0] = ret;
  33:}
  34:
  35:pair<int, bool> Q (int cur, const vector<vector<int> > & children, vector<Emp> & mem)
  36:{
  37:    if (mem[cur].data[1].first >= 0) return mem[cur].data[1];
  38:    
  39:    pair<int, bool> ret (0, true);
  40:    for (unsigned i = 0; i < children[cur].size(); ++i)
  41:    {
  42:        pair<int, bool> rp = P(children[cur][i], children, mem);
  43:        pair<int, bool> rq = Q(children[cur][i], children, mem);
  44:        
  45:        ret.first += max (rp.first, rq.first);
  46:        if (rp.first > rq.first) ret.second = (ret.second && rp.second);
  47:        else if (rp.first < rq.first) ret.second = (ret.second && rq.second);
  48:        else ret.second = false;
  49:    }
  50:    return mem[cur].data[1] = ret;
  51:}
  52:
  53:int main ()
  54:{
  55:    ifstream fin (PROB_NAME ".in");
  56:    
  57:    int n;
  58:    while (fin >> n && n != 0)
  59:    {
  60:        map<string, int> empnum;
  61:        #define EMPNUM(name)    ((empnum.find(name) == empnum.end()) ? empnum[name] = (int)empnum.size() - 1 : empnum[name])
  62:
  63:        vector<int> parent (n, -1);
  64:        vector<vector<int> > children (n);
  65:
  66:        string foo, bar;
  67:        fin >> foo;
  68:        
  69:        empnum[foo] = 0;
  70:        for (int i = 1; i < n; ++i)
  71:        {
  72:            fin >> foo >> bar;
  73:            parent[EMPNUM(foo)] = EMPNUM(bar);
  74:            children[EMPNUM(bar)].push_back (EMPNUM(foo));
  75:        }
  76:        
  77:        vector<Emp> mem (n);
  78:        pair<int, bool> rp = P (0, children, mem);
  79:        pair<int, bool> rq = Q (0, children, mem);
  80:        
  81:        cout 
  82:            << max(rp.first, rq.first) << " "
  83:            << ((rp.first == rq.first ||
  84:                (rp.first > rq.first && !rp.second) ||
  85:                (rq.first > rp.first && !rq.second)
  86:                ) ? "NO" : "YES") << endl;
  87:        cout << rp.first << ", " << rp.second << ", " << rq.first << ", " << rq.second << endl;
  88:    }
  89:    
  90:    return 0;
  91:}
  92:

Sharif ICPC Regionals 2006 - Problem C

   1:#include <string>
   2:#include <vector>
   3:#include <fstream>
   4:#include <iomanip>
   5:#include <iostream>
   6:#include <algorithm>
   7:
   8:using namespace std;
   9:
  10:#define PROB_NAME   "C"
  11:
  12:bool duringnight (int b, int e) // [b,e)
  13:{
  14:    b %= 24 * 60; e %= 24 * 60;
  15:    if (0 <= b && b < 6 * 60 + 1) return true;  // Rules are not clear about the length
  16:    if (0 < e && e <= 6 * 60 + 1) return true;  // of night. Is it 6 hours or 361 minutes?
  17:    return false;
  18:}
  19:
  20:int main ()
  21:{
  22:    ifstream fin (PROB_NAME ".in");
  23:    
  24:    while (0 == 0)
  25:    {
  26:        vector<string> name;
  27:        vector<int> length, minute;
  28:        
  29:        string foo;
  30:        while ((fin >> foo) && foo != "$" && foo != "--")
  31:        {
  32:            name.push_back (foo); length.push_back (-1); minute.push_back (-1);
  33:            fin >> length.back() >> minute.back();
  34:        }
  35:        if (foo == "--") break;
  36:        
  37:        string stname, enname;
  38:        int sth = -1, stm = -1;
  39:        char bar;
  40:        
  41:        fin >> stname >> enname >> sth >> bar >> stm;
  42:        fin >> foo;
  43:        
  44:        int st = int(find(name.begin(), name.end(), stname) - name.begin());
  45:        int en = int(find(name.begin(), name.end(), enname) - name.begin());
  46:        
  47:        int stt = (sth * 60 + stm) % (24 * 60);
  48:        int curt = stt;
  49:        int totallen = 0;
  50:        double fare = 0.0;
  51:        for (int i = st; i <= en; ++i)
  52:        {
  53:            for (int j = 0; j < length[i]; ++j)
  54:            {
  55:                bool night = duringnight (curt, curt + minute[i]);
  56:                double rate = (night ? 1.2 : 1.0);
  57:                
  58:                if (totallen < 10) fare += 1000 * rate;
  59:                else if (totallen < 30) fare += 250 * rate;
  60:                else fare += 100 * rate;
  61:                
  62:                totallen++;
  63:                curt += minute[i];
  64:            }
  65:        }
  66:        double avgkph = totallen / (60 * (curt - stt));
  67:        if (avgkph < 30) fare *= 1.1;
  68:        
  69:        cout << fare << endl;
  70:    }
  71:    return 0;
  72:}
  73:

Monday, December 18, 2006

Sharif ICPC Regionals 2006 - Problem B

   1:#include <string>
   2:#include <vector>
   3:#include <fstream>
   4:#include <iomanip>
   5:#include <iostream>
   6:#include <algorithm>
   7:
   8:using namespace std;
   9:
  10:#define PROB_NAME   "B"
  11:
  12:typedef unsigned long long u64;
  13:
  14:u64 Pow10 [14] = {
  15:    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
  16:    100000000, 1000000000, 10000000000, 100000000000,
  17:    1000000000000, 10000000000000
  18:};
  19:
  20:u64 WildCount (const string & w, const string & x, unsigned i, unsigned remw)
  21:{
  22:    if (i >= w.size()) return 0;
  23:    else if (w[i] == '?') return WildCount(w, x, i + 1, remw - 1) + Pow10[remw - 1] * ('9' - x[i]);
  24:    else if (w[i] > x[i]) return Pow10[remw];
  25:    else if (w[i] < x[i]) return 0;
  26:    else return WildCount(w, x, i + 1, remw);
  27:}
  28:
  29:int main ()
  30:{
  31:    ifstream fin (PROB_NAME ".in");
  32:  
  33:    string w, x;
  34:    while ((fin >> w >> x) && w != "#")
  35:        cout << WildCount(w, x, 0, (unsigned)count(w.begin(), w.end(), '?')) << endl;
  36:  
  37:    return 0;
  38:}
  39:

Sharif ICPC Regionals 2006 - Problem A

   1:#include <string>
   2:#include <vector>
   3:#include <fstream>
   4:#include <sstream>
   5:#include <cassert>
   6:#include <iostream>
   7:#include <algorithm>
   8:
   9:using namespace std;
  10:
  11:#define PROB_NAME   "A"
  12:
  13:struct Player
  14:{
  15:    string name;
  16:    int number, role, exp;
  17:    bool captain, inarrange;
  18:   
  19:    Player (const string & line)
  20:        : number (0), exp (0), captain (false), inarrange (false)
  21:    {
  22:        stringstream ss (line);
  23:        ss >> number;
  24:        if (0 == number) return;
  25:
  26:        char foo;
  27:        ss >> name >> foo;
  28:        role = (int)string("GDMS").find(foo);
  29:        assert (role >= 0 && role < 4);
  30:       
  31:        int y1, y2;
  32:        while (ss >> y1 >> foo >> y2)
  33:            exp += y2 - y1 + 1;
  34:    }
  35:    // Compare according to precedence in arrange
  36:    static bool CompArrange (const Player & p1, const Player & p2)
  37:    {
  38:        if (p1.role != p2.role) return p1.role < p2.role;
  39:        else return p1.number < p2.number;
  40:    }
  41:    // Compare according to precedence for captaincy(!)
  42:    static bool CompCaptaincy (const Player & p1, const Player & p2)
  43:    {
  44:        if (p1.inarrange != p2.inarrange) return p1.inarrange;
  45:        else if (p1.exp != p2.exp) return p1.exp > p2.exp;
  46:        else return p1.number > p2.number;
  47:    }
  48:    // Compare according to precedence for display
  49:    static bool CompListing (const Player & p1, const Player & p2)
  50:    {
  51:        if (p1.inarrange != p2.inarrange) return p1.inarrange;
  52:        else if (p1.captain != p2.captain) return p1.captain;
  53:        else if (p1.role != p2.role) return p1.role < p2.role;
  54:        else return p1.number < p2.number;
  55:    }
  56:};
  57:
  58:int main ()
  59:{
  60:    ifstream fin (PROB_NAME ".in");
  61:   
  62:    while (0 == 0)
  63:    {
  64:        vector<Player> p;
  65:        int avroles [4] = {0, 0, 0, 0};
  66:       
  67:        for (unsigned i = 0; i < 22; ++i)
  68:        {
  69:            string ln;
  70:            getline (fin, ln);
  71:            p.push_back (Player(ln));
  72:            if (0 == p.back().number) break;
  73:            avroles[p.back().role]++;
  74:        }
  75:        if (0 == p.size() || 0 == p.back().number) break;
  76:
  77:        int a[4] = {1, 0, 0, 0};
  78:        char foo;
  79:        fin >> a[1] >> foo >> a[2] >> foo >> a[3];
  80:       
  81:        if (a[0] > avroles[0] || a[1] > avroles[1] ||
  82:            a[2] > avroles[2] || a[3] > avroles[3])
  83:            cout << "IMPOSSIBLE TO ARRANGE" << endl;
  84:        else
  85:        {
  86:            sort (p.begin(), p.end(), Player::CompArrange);
  87:            for (unsigned i = 0; i < p.size(); ++i)
  88:                if (a[p[i].role]-- > 0) p[i].inarrange = true;
  89:            sort (p.begin(), p.end(), Player::CompCaptaincy);
  90:            p[0].captain = true;
  91:            sort (p.begin(), p.end(), Player::CompListing);
  92:            for (unsigned i = 0; i < 11; ++i)
  93:                cout << p[i].number << " " << p[i].name
  94:                << " " << "GDMS"[p[i].role] << endl;
  95:            cout << endl;
  96:        }
  97:    }
  98:    return 0;
  99:}