#include <iostream>
using namespace std;

class Student
{
private:
  // packing student info in 2 bytes:
  //
  //   13    8  7  6   2   10
  // .. xxxxxx  x  xxxxx   xx
  //
  // Year    in  bits  0..1:  2 bits for 4 options  (00, 01, 10, 11)
  // Credits in  bits  2..6:  5 bits for 32 options (0..31)
  // Major   in  bit      7:  1 bits for 2 options  (T/F)
  // GPA     in  bits 8..13:  6 bits for 45 options (0..44)
  //
  // bits 14 and 15 are not used  
  
  unsigned short data;
  

public:
  Student() : data(0)
  {
  }

  Student( int year, int credits ) : data(0)
  {
    setYear( year );
    setCredits( credits );
  }

  void setYear( int year )
  {
    unsigned short mask = 0x0003; // or 0b0000.0000.0000.0011

    data = data & ~mask;          // last 2 bits of data are 00, rest unchanged
                                  // note mask inverted before use

    year = year - 1;              // convert 1,2,3,4, i.e. 01, 10, 11, 100
                                  // into    0,1,2,3, i.e. 00, 01, 10, 11
    
    data = data | year;           // last 2 bits of data have year, rest unchanged
  }

  int getYear()
  {
    unsigned short mask = 0x0003;      // or 0b0000.0000.0000.0011

    unsigned short year = data & mask; // extract only last two bits, rest are 0

    return year + 1;                   // convert 0,1,2,3 back to 1,2,3,4
  }

  void setCredits( int credits )
  {
    unsigned short mask = 0x001F; // or   0b0000.0000.0001.1111  (5 bits)
    mask = mask << 2;             // move by 2 to position under bits 2..6
                                  //      0b0000.0000.0111.1100
    mask = ~mask;                 // flip 0b1111.1111.1000.0011
                                  // so that desired 5 bits can be cleared

    data = data & mask;           // bits 2..6 are 0, rest unchanged

    credits = credits << 2;       // move by 2 to position under bits 2..6
      
    data = data | credits;        // bits 2..6 have credits, rest unchanged
  }

  int getCredits()
  {
    unsigned short mask = 0x001F;          // or   0b0000.0000.0001.1111  (5 bits)
    
    mask = mask << 2;                      // move by 2 to position under bits 2..6
                                           //      0b0000.0000.0111.1100

    unsigned short credits = data & mask;  // credits has bits 2..6, rest are 0

    credits = credits >> 2;                // move by 2 to position at beginning
    
    return credits;
  }

  void print()
  {
    cout << "Student details:" << endl
	 << "- year   : " << getYear() << endl
	 << "- credits: " << getCredits() << endl;
      // << "- major  : " << getMajor() << endl
      // << "- gpa    : " << getGPA() << endl;
  }
};


int main()
{
  Student s1;              // calls default c-tor
  Student s2( 1, 25 );     // calls 2nd c-tor

  s1.print();
  s2.print();
					 
  s1.setYear(2);
  cout << s1.getYear() << endl;

  s1.setCredits(17);
  cout << s1.getCredits() << endl;

  s1.print();

  s1.setYear(3);
  cout << s1.getYear() << endl;

  s1.setCredits(23);
  cout << s1.getCredits() << endl;
  
  s1.print();
}