// ktab.C  Version 7.42  Copyleft (c) 杉本典夫
// Time-stamp: <2025-10-30 10:30:48 tac>
//
// 薬剤割り付け用プログラム
//
// 使用ライブラリ:libdans.so, libfun.so
// コンパイル法 :g++ -O -s -W ktab ktab.C -I/usr/local/include
//              -L/usr/local/lib -ldans -lfun

#include <dans.H>               // dans用ヘッダファイル(fun.H含む)

using namespace dans;           // dans名前空間使用(名前空間matvec含む)

const vecstr USAGE =            // プログラム使用法表示用
{
  "ktab  Version 7.42           Copyleft (Vo\\oV) 2025 杉本典夫",
  "書式:ktab [<オプション> …]",
  "機能:薬剤割り付け表(キーテーブル)を出力するんよ。",
  "<オプション>",
  "  -dg=<薬剤名1>,<薬剤名2>[,<薬剤名3>,…]:薬剤名を指定するんよ。",
  "    オプション省略時:-dg=DG1,DG2[,…]",
  "  -f=<ファイル名>:指定されたファイルからオプションを読み込むんよ。",
  "  -h[=<コマンド名>]:オンラインマニュアルを表示するんよ。(-h:-h=man)",
  "  -n=<割り付け例数>:割り付け例数を指定するんよ。(省略時:-n=144)",
  "  -nd=<薬剤数>:薬剤数を指定するんよ。(2-4,省略時:-nd=2)",
  "  -nr=<1組の例数>:1組の例数を指定するんよ。(3,4,6,8,省略時:-nr=6)",
  "    有効な薬剤数と例数の組み合わせ:2-4,2-6,3-3,3-6,4-4,4-8",
  "  -sc=<出力開始組>:出力を開始する組を指定するんよ。(省略時:-sc=1)",
  "  -seed=<乱数のタネ>:乱数のタネを指定するんよ。(省略時:-seed=1)"
};

class option                    // オプションクラス
{
private:
  string v_path;                // プログラムのパス
  string v_pname;               // プログラム名
  vecstr dgvec;                 // 薬剤名ベクトル
  int v_n;                      // 割り付け例数
  int v_nd;                     // 薬剤数
  int v_nr;                     // 1組の例数
  int v_sc;                     // 出力開始組
  uint32 v_seed;                // 乱数のタネ
public:
  option(const char* c_pname = nullptr); // コンストラクタ
  ~option()                              // デストラクタ
  {}
  const string& path() const    // プログラムのパスを返す
  { return v_path; }
  const string& pname() const   // プログラム名を返す
  { return v_pname; }
  const string& dg(size_t idx) const // 薬剤名を返す
  { return (idx < dgvec.size()) ? dgvec[idx] : BLANKs; }
  const string& dg(size_t idx, const string& dg0); // 薬剤名を設定する
  int n() const                 // 割り付け例数を返す
  { return v_n; }
  int nd() const                // 薬剤数を返す
  { return v_nd; }
  int nr() const                // 1組の例数を返す
  { return v_nr; }
  int sc() const                // 出力開始組を返す
  { return v_sc; }
  uint32 seed() const           // 乱数のタネを返す
  { return v_seed; }
  void setdef()                 // 省略時オプション指定を設定する
  { getoptdef(*this); }
  void set(const string& optstr, char devc = OPTdev);
  // オプション指定によってオプションを設定する
};

option::option(const char* c_pname) : v_path(), v_pname(), dgvec(), v_n(144), v_nd(2), v_nr(6), v_sc(1), v_seed(1)
// コンストラクタ
{
  if (c_pname == nullptr) return; // 初期設定せず
  v_pname = getname(c_pname);     // パス名なしのプログラム名取得
  v_path = c_pname;
  strsize_t idx = v_path.find(v_pname);
  if (idx != string::npos) v_path.erase(idx); // プログラム名削除
  if (v_pname.find("ktab24") != string::npos) { v_nd = 2;  v_nr = 4; }
  else if (v_pname.find("ktab26") != string::npos) { v_nd = 2;  v_nr = 6; }
  else if (v_pname.find("ktab33") != string::npos) { v_nd = 3;  v_nr = 3; }
  else if (v_pname.find("ktab36") != string::npos) { v_nd = 3;  v_nr = 6; }
  else if (v_pname.find("ktab44") != string::npos) { v_nd = 4;  v_nr = 4; }
  else if (v_pname.find("ktab48") != string::npos) { v_nd = 4;  v_nr = 8; }
  dgvec.resize(v_nd, BLANKs);
}

void option::set(const string& optstr, char devc)
// オプション指定によってオプションを設定する
{
  string opt[2];                // オプションのopt[0]:項目,opt[1]:内容
  if (getopt(opt, optstr, devc) < 1) return; // オプション指定なし
  int err = 0;
  if (opt[0] == "dg")           // 薬剤名の指定
  {
    dgvec.clear();               // druvをクリアする
    if (strsplit(dgvec, opt[1], CHRdelm) < 1) err = badopt(pname(), optstr, USAGE);
  }
  else if (opt[0] == "f")       // オプション指定ファイル
  { err = fgetopt(*this, opt[1], true); }
  else if (opt[0] == "h")       // オンラインヘルプ表示
  { err = help(pname(), USAGE, opt[1]); }
  else if (opt[0] == "n")       // 割り付け例数の指定
  {
    char* ptr = nullptr;
    v_n = strtol(opt[1].c_str(), &ptr, 0);
    if (v_n < 1) err = badopt(pname(), optstr, USAGE, 0.0, (double)(INT_MAX / 2));
  }
  else if (opt[0] == "nd")      // 薬剤数の指定
  {
    char* ptr = nullptr;
    v_nd = strtol(opt[1].c_str(), &ptr, 0);
    if (v_nd < 2 || 4 < v_nd) err = badopt(pname(), optstr, USAGE, 2.0, 4.0);
    dgvec.resize(v_nd);
  }
  else if (opt[0] == "nr")      // 1組の例数の指定
  {
    char* ptr = nullptr;
    v_nr = strtol(opt[1].c_str(), &ptr, 0);
    if (v_nr < 3 || 8 < v_nr) err = badopt(pname(), optstr, USAGE, 3.0, 8.0);
  }
  else if (opt[0] == "sc")      // 出力開始番号の指定
  {
    char* ptr = nullptr;
    v_sc = (opt[1].empty()) ? 1 : strtol(opt[1].c_str(), &ptr, 0);
    if (v_sc < 1) err = badopt(pname(), optstr, USAGE, 1.0, double(n() / nr()));
  }
  else if (opt[0] == "seed")    // 乱数のタネの指定
  {
    char* ptr = nullptr;
    v_seed = (opt[1].empty()) ? 1 : strtol(opt[1].c_str(), &ptr, 0);
    if (v_seed < 1) err = badopt(pname(), optstr, USAGE);
  }
  else                          // 間違ったオプション指定
  { err = nonopt(pname(), optstr, USAGE); }
  if (err > 0) throw help_except("ヘルプ表示");
  if (err < 0) throw option_error(string("オプション指定違反→") + optstr);
}

const string& option::dg(size_t idx, const string& dg0)
// 薬剤名を設定する
{
  if (idx < dgvec.size()) return (dgvec[idx] = dg0);
  dgvec.resize(idx + 1);
  return (dgvec[idx] = dg0);
}

class ktabclass                 // ktabメインクラス
{
private:
  int initktab(option& opt, int& id, int& np, int& nc, vecint& rndvec, vecint& idxvec, vecint& dgidxvec) const;
  // 割り付け表を初期設定する
  void setktab(vecint& rndvec, vecint& idxvec, vecint& dgidxvec, int np) const;
  // 割り付け表を設定する
  void put24(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const;
  // 2剤4例表出力
  void put26(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const;
  // 2剤6例表出力
  void put33(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const;
  // 3剤3例表出力
  void put36(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const;
  // 3剤6例表出力
  void put44(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const;
  // 4剤4例表出力
  void put48(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const;
  // 4剤8例表出力
  void put_tab(const option& opt, const vecint& dgidxvec, int cindex) const;
  // 割り付け表を1組出力する
public:
  ktabclass()                   // コンストラクタ
  {}
  ~ktabclass()                  // デストラクタ
  {}
  void put(option& opt) const;  // 割り付け表を出力する
};

int ktabclass::initktab(option& opt, int& id, int& np, int& nc, vecint& rndvec, vecint& idxvec, vecint& dgidxvec) const
// 割付表を初期設定する
{
  switch (opt.nd())
  {
  case 2 :
    switch (opt.nr())
    {
    case 4 : id = 24;  np = nc = 4; // 2剤4例割り付け
      break;
    case 6 : id = 26;  np = nc = 8; // 2剤6例割り付け
      break;
    default : return -1;        // 不適当な組み合わせ
    }
    break;
  case 3 :
    switch (opt.nr())
    {
    case 3 : id = 33;  np = nc = 6; // 3剤3例割り付け
      break;
    case 6 : id = 36;  np = 6;  nc = 3; // 3剤6例割り付け
      break;
    default : return -1;        // 不適当な組み合わせ
    }
    break;
  case 4 :
    switch (opt.nr())
    {
    case 4 : id = 44;  np = nc = 24; // 4剤4例割り付け
      break;
    case 8 : id = 48;  np = 24;  nc = 12; // 4剤8例割り付け
      break;
    default : return -1;        // 不適当な組み合わせ
    }
    break;
  default : return -1;          // 不適当な組み合わせ
  }
  rndvec.resize(np);  idxvec.resize(np);
  for (int i = 0; i < np; ++i) rndvec[i] = idxvec[i] = i;
  dgidxvec.resize(opt.nr());
  ostringstream ostr;
  for (int i = 0; i < opt.nd(); ++i)
  {
    if (opt.dg(i) == BLANKs)
    {
      ostr.str("");
      ostr << "DG" << i + 1;
      opt.dg(i, ostr.str());
    }
  }
  return 0;
}

void ktabclass::setktab(vecint& rndvec, vecint& idxvec, vecint& dgidxvec, int np) const
// 割り付け表を設定する
{
  for (int i = 0; i < np; ++i) rndvec[i] = rand();
  for (int i = 1; i < np; ++i)
  {
    int rtmp = rndvec[i], itmp = idxvec[i];
    int j = i - 1;
    while (j >= 0 && rndvec[j] > rtmp)
    {
      rndvec[j + 1] = rndvec[j];  idxvec[j + 1] = idxvec[j];
      --j;
    }
    rndvec[j + 1] = rtmp;  idxvec[j + 1] = itmp;
  }
}

void ktabclass::put24(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const
// 2剤4例の1連の割り付け表を出力する
{
  for (int i = 0; i < nc; ++i)
  {
    switch (idxvec[i])
    {
    case 0 : dgidxvec[0] = 0;  dgidxvec[1] = 1;
      dgidxvec[2] = 0;  dgidxvec[3] = 1;
      break;
    case 1 : dgidxvec[0] = 1;  dgidxvec[1] = 0;
      dgidxvec[2] = 1;  dgidxvec[3] = 0;
      break;
    case 2 : dgidxvec[0] = 1;  dgidxvec[1] = 0;
      dgidxvec[2] = 0;  dgidxvec[3] = 1;
      break;
    case 3 : dgidxvec[0] = 0;  dgidxvec[1] = 1;
      dgidxvec[2] = 1;  dgidxvec[3] = 0;
      break;
    default : return;
    }
    put_tab(opt, dgidxvec, cindex + i);
  }
}

void ktabclass::put26(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const
// 2剤6例の1連の割り付け表を出力する
{
  for (int i = 0; i < nc; ++i)
  {
    switch (idxvec[i])
    {
    case 0 : dgidxvec[0] = 0;  dgidxvec[1] = 1;  dgidxvec[2] = 0;
      dgidxvec[3] = 1;  dgidxvec[4] = 0;  dgidxvec[5] = 1;
      break;
    case 1 : dgidxvec[0] = 1;  dgidxvec[1] = 0;  dgidxvec[2] = 1;
      dgidxvec[3] = 0;  dgidxvec[4] = 1;  dgidxvec[5] = 0;
      break;
    case 2 : dgidxvec[0] = 1;  dgidxvec[1] = 0;  dgidxvec[2] = 0;
      dgidxvec[3] = 1;  dgidxvec[4] = 1;  dgidxvec[5] = 0;
      break;
    case 3 : dgidxvec[0] = 0;  dgidxvec[1] = 1;  dgidxvec[2] = 1;
      dgidxvec[3] = 0;  dgidxvec[4] = 0;  dgidxvec[5] = 1;
      break;
    case 4 : dgidxvec[0] = 1;  dgidxvec[1] = 0;  dgidxvec[2] = 1;
      dgidxvec[3] = 0;  dgidxvec[4] = 0;  dgidxvec[5] = 1;
      break;
    case 5 : dgidxvec[0] = 0;  dgidxvec[1] = 1;  dgidxvec[2] = 0;
      dgidxvec[3] = 1;  dgidxvec[4] = 1;  dgidxvec[5] = 0;
      break;
    case 6 : dgidxvec[0] = 0;  dgidxvec[1] = 1;  dgidxvec[2] = 1;
      dgidxvec[3] = 0;  dgidxvec[4] = 1;  dgidxvec[5] = 0;
      break;
    case 7 : dgidxvec[0] = 1;  dgidxvec[1] = 0;  dgidxvec[2] = 0;
      dgidxvec[3] = 1;  dgidxvec[4] = 0;  dgidxvec[5] = 1;
      break;
    default : return;
    }
    put_tab(opt, dgidxvec, cindex + i);
  }
}

void ktabclass::put33(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const
// 3剤3例の割り付け表を出力する
{
  for (int i = 0; i < nc; ++i)
  {
    switch (idxvec[i])
    {
    case 0 : dgidxvec[0] = 0;  dgidxvec[1] = 1;  dgidxvec[2] = 2;
      break;
    case 1 : dgidxvec[0] = 0;  dgidxvec[1] = 2;  dgidxvec[2] = 1;
      break;
    case 2 : dgidxvec[0] = 1;  dgidxvec[1] = 0;  dgidxvec[2] = 2;
      break;
    case 3 : dgidxvec[0] = 1;  dgidxvec[1] = 2;  dgidxvec[2] = 0;
      break;
    case 4 : dgidxvec[0] = 2;  dgidxvec[1] = 0;  dgidxvec[2] = 1;
      break;
    case 5 : dgidxvec[0] = 2;  dgidxvec[1] = 1;  dgidxvec[2] = 0;
      break;
    default : return;
    }
    put_tab(opt, dgidxvec, cindex + i);
  }
}

void ktabclass::put36(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const
// 3剤6例の割り付け表を出力する
{
  for (int i = 0; i < nc; ++i)
  {
    for (int j = 0; j < 2; ++j)
    {
      int k = j * 3;
      switch (idxvec[i * 2 + j])
      {
      case 0 : dgidxvec[k] = 0;  dgidxvec[k + 1] = 1;  dgidxvec[k + 2] = 2;
        break;
      case 1 : dgidxvec[k] = 0;  dgidxvec[k + 1] = 2;  dgidxvec[k + 2] = 1;
        break;
      case 2 : dgidxvec[k] = 1;  dgidxvec[k + 1] = 0;  dgidxvec[k + 2] = 2;
        break;
      case 3 : dgidxvec[k] = 1;  dgidxvec[k + 1] = 2;  dgidxvec[k + 2] = 0;
        break;
      case 4 : dgidxvec[k] = 2;  dgidxvec[k + 1] = 0;  dgidxvec[k + 2] = 1;
        break;
      case 5 : dgidxvec[k] = 2;  dgidxvec[k + 1] = 1;  dgidxvec[k + 2] = 0;
        break;
      default : return;
      }
    }
    put_tab(opt, dgidxvec, cindex + i);
  }
}

void ktabclass::put44(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const
// 4剤4例の割り付け表を出力する
{
  for (int i = 0; i < nc; ++i)
  {
    switch (idxvec[i])
    {
    case 0 : dgidxvec[0] = 0;  dgidxvec[1] = 1;
      dgidxvec[2] = 2;  dgidxvec[3] = 3;
      break;
    case 1 : dgidxvec[0] = 0;  dgidxvec[1] = 1;
      dgidxvec[2] = 3;  dgidxvec[3] = 2;
      break;
    case 2 : dgidxvec[0] = 0;  dgidxvec[1] = 2;
      dgidxvec[2] = 1;  dgidxvec[3] = 3;
      break;
    case 3 : dgidxvec[0] = 0;  dgidxvec[1] = 2;
      dgidxvec[2] = 3;  dgidxvec[3] = 1;
      break;
    case 4 : dgidxvec[0] = 0;  dgidxvec[1] = 3;
      dgidxvec[2] = 1;  dgidxvec[3] = 2;
      break;
    case 5 : dgidxvec[0] = 0;  dgidxvec[1] = 3;
      dgidxvec[2] = 2;  dgidxvec[3] = 1;
      break;
    case 6 : dgidxvec[0] = 1;  dgidxvec[1] = 0;
      dgidxvec[2] = 2;  dgidxvec[3] = 3;
      break;
    case 7 : dgidxvec[0] = 1;  dgidxvec[1] = 0;
      dgidxvec[2] = 3;  dgidxvec[3] = 2;
      break;
    case 8 : dgidxvec[0] = 1;  dgidxvec[1] = 2;
      dgidxvec[2] = 0;  dgidxvec[3] = 3;
      break;
    case 9 : dgidxvec[0] = 1;  dgidxvec[1] = 2;
      dgidxvec[2] = 3;  dgidxvec[3] = 0;
      break;
    case 10 : dgidxvec[0] = 1;  dgidxvec[1] = 3;
      dgidxvec[2] = 0;  dgidxvec[3] = 2;
      break;
    case 11 : dgidxvec[0] = 1;  dgidxvec[1] = 3;
      dgidxvec[2] = 2;  dgidxvec[3] = 0;
      break;
    case 12 : dgidxvec[0] = 2;  dgidxvec[1] = 0;
      dgidxvec[2] = 1;  dgidxvec[3] = 3;
      break;
    case 13 : dgidxvec[0] = 2;  dgidxvec[1] = 0;
      dgidxvec[2] = 3;  dgidxvec[3] = 1;
      break;
    case 14 : dgidxvec[0] = 2;  dgidxvec[1] = 1;
      dgidxvec[2] = 0;  dgidxvec[3] = 3;
      break;
    case 15 : dgidxvec[0] = 2;  dgidxvec[1] = 1;
      dgidxvec[2] = 3;  dgidxvec[3] = 0;
      break;
    case 16 : dgidxvec[0] = 2;  dgidxvec[1] = 3;
      dgidxvec[2] = 0;  dgidxvec[3] = 1;
      break;
    case 17 : dgidxvec[0] = 2;  dgidxvec[1] = 3;
      dgidxvec[2] = 1;  dgidxvec[3] = 0;
      break;
    case 18 : dgidxvec[0] = 3;  dgidxvec[1] = 0;
      dgidxvec[2] = 1;  dgidxvec[3] = 2;
      break;
    case 19 : dgidxvec[0] = 3;  dgidxvec[1] = 0;
      dgidxvec[2] = 2;  dgidxvec[3] = 1;
      break;
    case 20 : dgidxvec[0] = 3;  dgidxvec[1] = 1;
      dgidxvec[2] = 0;  dgidxvec[3] = 2;
      break;
    case 21 : dgidxvec[0] = 3;  dgidxvec[1] = 1;
      dgidxvec[2] = 2;  dgidxvec[3] = 0;
      break;
    case 22 : dgidxvec[0] = 3;  dgidxvec[1] = 2;
      dgidxvec[2] = 0;  dgidxvec[3] = 1;
      break;
    case 23 : dgidxvec[0] = 3;  dgidxvec[1] = 2;
      dgidxvec[2] = 1;  dgidxvec[3] = 0;
      break;
    default : return;
    }
    put_tab(opt, dgidxvec, cindex + i);
  }
}

void ktabclass::put48(const option& opt, int nc, const vecint& idxvec, vecint& dgidxvec, int cindex) const
// 4剤8例の割り付け表を出力する
{
  for (int i = 0; i < nc; ++i)
  {
    for (int j = 0; j < 2; ++j)
    {
      int k = j * 4;
      switch (idxvec[i * 2 + j])
      {
      case 0 : dgidxvec[k] = 0;  dgidxvec[k + 1] = 1;
        dgidxvec[k + 2] = 2;  dgidxvec[k + 3] = 3;
        break;
      case 1 : dgidxvec[k] = 0;  dgidxvec[k + 1] = 1;
        dgidxvec[k + 2] = 3;  dgidxvec[k + 3] = 2;
        break;
      case 2 : dgidxvec[k] = 0;  dgidxvec[k + 1] = 2;
        dgidxvec[k + 2] = 1;  dgidxvec[k + 3] = 3;
        break;
      case 3 : dgidxvec[k] = 0;  dgidxvec[k + 1] = 2;
        dgidxvec[k + 2] = 3;  dgidxvec[k + 3] = 1;
        break;
      case 4 : dgidxvec[k] = 0;  dgidxvec[k + 1] = 3;
        dgidxvec[k + 2] = 1;  dgidxvec[k + 3] = 2;
        break;
      case 5 : dgidxvec[k] = 0;  dgidxvec[k + 1] = 3;
        dgidxvec[k + 2] = 2;  dgidxvec[k + 3] = 1;
        break;
      case 6 : dgidxvec[k] = 1;  dgidxvec[k + 1] = 0;
        dgidxvec[k + 2] = 2;  dgidxvec[k + 3] = 3;
        break;
      case 7 : dgidxvec[k] = 1;  dgidxvec[k + 1] = 0;
        dgidxvec[k + 2] = 3;  dgidxvec[k + 3] = 2;
        break;
      case 8 : dgidxvec[k] = 1;  dgidxvec[k + 1] = 2;
        dgidxvec[k + 2] = 0;  dgidxvec[k + 3] = 3;
        break;
      case 9 : dgidxvec[k] = 1;  dgidxvec[k + 1] = 2;
        dgidxvec[k + 2] = 3;  dgidxvec[k + 3] = 0;
        break;
      case 10 : dgidxvec[k] = 1;  dgidxvec[k + 1] = 3;
        dgidxvec[k + 2] = 0;  dgidxvec[k + 3] = 2;
        break;
      case 11 : dgidxvec[k] = 1;  dgidxvec[k + 1] = 3;
        dgidxvec[k + 2] = 2;  dgidxvec[k + 3] = 0;
        break;
      case 12 : dgidxvec[k] = 2;  dgidxvec[k + 1] = 0;
        dgidxvec[k + 2] = 1;  dgidxvec[k + 3] = 3;
        break;
      case 13 : dgidxvec[k] = 2;  dgidxvec[k + 1] = 0;
        dgidxvec[k + 2] = 3;  dgidxvec[k + 3] = 1;
        break;
      case 14 : dgidxvec[k] = 2;  dgidxvec[k + 1] = 1;
        dgidxvec[k + 2] = 0;  dgidxvec[k + 3] = 3;
        break;
      case 15 : dgidxvec[k] = 2;  dgidxvec[k + 1] = 1;
        dgidxvec[k + 2] = 3;  dgidxvec[k + 3] = 0;
        break;
      case 16 : dgidxvec[k] = 2;  dgidxvec[k + 1] = 3;
        dgidxvec[k + 2] = 0;  dgidxvec[k + 3] = 1;
        break;
      case 17 : dgidxvec[k] = 2;  dgidxvec[k + 1] = 3;
        dgidxvec[k + 2] = 1;  dgidxvec[k + 3] = 0;
        break;
      case 18 : dgidxvec[k] = 3;  dgidxvec[k + 1] = 0;
        dgidxvec[k + 2] = 1;  dgidxvec[k + 3] = 2;
        break;
      case 19 : dgidxvec[k] = 3;  dgidxvec[k + 1] = 0;
        dgidxvec[k + 2] = 2;  dgidxvec[k + 3] = 1;
        break;
      case 20 : dgidxvec[k] = 3;  dgidxvec[k + 1] = 1;
        dgidxvec[k + 2] = 0;  dgidxvec[k + 3] = 2;
        break;
      case 21 : dgidxvec[k] = 3;  dgidxvec[k + 1] = 1;
        dgidxvec[k + 2] = 2;  dgidxvec[k + 3] = 0;
        break;
      case 22 : dgidxvec[k] = 3;  dgidxvec[k + 1] = 2;
        dgidxvec[k + 2] = 0;  dgidxvec[k + 3] = 1;
        break;
      case 23 : dgidxvec[k] = 3;  dgidxvec[k + 1] = 2;
        dgidxvec[k + 2] = 1;  dgidxvec[k + 3] = 0;
        break;
      default : return;
      }
    }
    put_tab(opt, dgidxvec, cindex + i);
  }
}

void ktabclass::put_tab(const option& opt, const vecint& dgidxvec, int cindex) const
// 割り付け表を1組出力する
{
  cout << setw(3) << cindex << setw(0) << "組- 1番:" << opt.dg(dgidxvec[0]) << "\n";
  for (int i = 2; i <= opt.nr(); ++i) cout << "     -" << setw(2) << i << setw(0) << "番:" << opt.dg(dgidxvec[i - 1]) << "\n";
  cout << endl;
}

void ktabclass::put(option& opt) const // 割り付け表を出力する
{
  int id = 0;                   // 薬剤数と1組の例数識別コード
  int np = 0;                   // 割り付けパターン数
  int nc = 0;                   // 割り付けパターン1セット分の組数
  vecint rndvec;                // 乱数ベクトル
  vecint idxvec;                // インデックスベクトル
  vecint dgidxvec;              // 薬剤名インデックスベクトル
  if (initktab(opt, id, np, nc, rndvec, idxvec, dgidxvec) != 0) throw runtime_error("薬剤数と1組例数の組み合わせが無効なんよ！");
  srand(opt.seed());            // 乱数の種を撒く
  int p = (int)((double)(opt.n()) / (double)(opt.nr()) / (double)nc + 0.99);
  for (int i = 0; i < p; ++i)
  {
    setktab(rndvec, idxvec, dgidxvec, np);
    int cindex = opt.sc() + i * nc;
    switch (id)
    {
    case 24 : put24(opt, nc, idxvec, dgidxvec, cindex);
      break;
    case 26 : put26(opt, nc, idxvec, dgidxvec, cindex);
      break;
    case 33 : put33(opt, nc, idxvec, dgidxvec, cindex);
      break;
    case 36 : put36(opt, nc, idxvec, dgidxvec, cindex);
      break;
    case 44 : put44(opt, nc, idxvec, dgidxvec, cindex);
      break;
    case 48 : put48(opt, nc, idxvec, dgidxvec, cindex);
    }
  }
}

int main(int argc, char* argv[]) // メインルーチン
{
  ktabclass ktab;               // メインクラス変数
  option opt(argv[0]);          // オプション
  try
  {
    opt.setdef();               // オプションの初期設定
    for (int i = 1; i < argc; ++i) opt.set(argv[i] + 1);
    ktab.put(opt);
  }
  catch (help_except& helpex)   // ヘルプファイル表示
  { return 0; }
  catch (option_error& opterr)  // オプション指定エラー
  { return 1; }
  catch (runtime_error& rterr)  // 実行時エラー
  {
    disperr(opt.pname(), rterr.what());
    return 2;
  }
  catch (...)                   // 予期せぬ例外
  {
    disperr(opt.pname(), "内容不明なエラー発生！");
    return 255;
  }
  return 0;
}
