2015年8月28日 星期五

(教學)Visual C++ 2005程式設計: Auto Number Generator新的範例:送貨員送咖啡到機台路線生成器

Auto Number Generator Electronic List應用方式說明(送咖啡到機台計算程式)
詹宗運製作
版本:Visual C++ 2005以上都可以使用

自動號碼產生器是一項超越時代的程式,
這裡A4element已經完全電腦化,
不需要用紙,不需要人力,也不需要印表機。
想想看可以在工業界節省多少費用。
為了要應用這一個好用的程式碼,
比如說現在有工廠裡面有幾個機台,
現在準備要送咖啡到這些機台給工作人員喝,
可以利用這個產生器做初步的路線計算跟評估,
非常方便。
這裡要感謝這一段期間對筆者程式提出建議的網友,
你們改正了我程式中許多不成熟的敘述。
歡迎各種公司行號利用本程式所提到的程式技術,
應用開發更高層次工業化的程式,
拼經濟救台灣。


使用方式:
1.
使用Visual C++ 2005建立一個WIN32主控台應用程式,
命名為"ANG_Example04",
這時候編譯器會自動生成空白檔案"ANG_Example04.cpp"和正常的"stdafx.h",
並且新增一個空白標頭檔,名為
"arrays.h"
然後把下面相同名稱的"ANG_Example04.cpp"和"arrays.h"的檔案內容,
拷貝貼上到相同名稱的空白檔案裡面。

並且要整理程式碼換行的部份,
讓不該換行的程式碼不要換行,
就可以讓程式碼正確執行了。

2.新增程式碼部份
#define DELAYTIME 1500
這裡定義了每次顯示路線數字的間隔時間,
預設值1500是1.5秒的間隔。
如果調大這個數字就可以讓畫面更換的比較慢一點。

3.預設參數可以計算1到10個送咖啡路線數量,
最大值雖然可以調整到10,但是數字會跳的非常慢,
可能要好幾個星期才會顯示完。
使用路線數字10的時候第10個送咖啡路線會以0號顯示。
如果要增加到10以上的數字就要加大switch case敘述,
工作量其實是非常龐大的,
提供給各位做為參考。

SOLUTION的數字必須符合階乘的計算。
5! = 120
6! = 720
7! =5040
8! = 40320
9! =362880
10! = 3628800

//如果要計算送咖啡到生產線的5個機台路線請修改參數如下:
//-------------------------------
#define MAXQUEEN 5
#define TRUE 1
#define FALSE 0
#define SOLUTION 120//SOLUTION = (MAXQUEEN)! 例如5!=120, 3!=6,4!=24,7! = 5040
#define ARRAYSIZE 6//ARRAYSIZE = MAXQUEEN+1




//如果要計算送咖啡到生產線的6個機台路線請修改參數如下:
//-------------------------------
#define MAXQUEEN 6
#define TRUE 1
#define FALSE 0
#define SOLUTION 720//SOLUTION = (MAXQUEEN)! 例如5!=120, 3!=6,4!=24,7! = 5040
#define ARRAYSIZE 7//ARRAYSIZE = MAXQUEEN+1




//如果要計算送咖啡到生產線的7個機台路線請修改參數如下:
//-------------------------------
#define MAXQUEEN 7
#define TRUE 1
#define FALSE 0
#define SOLUTION 5040//SOLUTION = (MAXQUEEN)! 例如5!=120, 3!=6,4!=24,7! = 5040
#define ARRAYSIZE 8//ARRAYSIZE = MAXQUEEN+1




//如果要計算送咖啡到生產線的8個機台路線請修改參數如下:
//-------------------------------
#define MAXQUEEN 8
#define TRUE 1
#define FALSE 0
#define SOLUTION 40320//SOLUTION = (MAXQUEEN)! 例如5!=120, 3!=6,4!=24,7! = 5040
#define ARRAYSIZE 9//ARRAYSIZE = MAXQUEEN+1




//如果要計算送咖啡到生產線的9個機台路線請修改參數如下:
//-------------------------------
#define MAXQUEEN 9
#define TRUE 1
#define FALSE 0
#define SOLUTION 362880//SOLUTION = (MAXQUEEN)! 例如5!=120, 3!=6,4!=24,7! = 5040
#define ARRAYSIZE 10//ARRAYSIZE = MAXQUEEN+1




//如果要計算送咖啡到生產線的10個機台路線請修改參數如下:
//-------------------------------
#define MAXQUEEN 10
#define TRUE 1
#define FALSE 0
#define SOLUTION 3628800//SOLUTION = (MAXQUEEN)! 例如5!=120, 3!=6,4!=24,7! = 5040
#define ARRAYSIZE 11//ARRAYSIZE = MAXQUEEN+1
//-------------------------------
//-------------------------------

//以下是ANG_Example04.cpp程式碼

// ANG_Example04.cpp : 定義主控台應用程式的進入點。
//

//Auto Number Generator
//ANG_Example04.cpp
//by 詹宗運
//這是一個修改ANG_Prototype的範例,
//用來計算自動加工廠的重新最佳化與分流問題的一個計算程式。
//免費授權Microsoft公司進行進一步的修改與工業化
//用來攤平記憶體缺損所造成的工業損失
//並且提供VC++社群做為討論與修改的使用
//version: Visual C++ 2005

#include "stdafx.h"
#include "arrays.h"
typedef struct a4element
{
int identity;
int a_content[3];
} A4element;



#include <windows.h>//myerrorhandler
#include <stdarg.h>//myerrorhandler
#include <stdio.h>//cout
#include <rtcapi.h>//myerrorhandler

#include <ostream>//fopen


#include <stdlib.h>//calloc
#include <iostream>//cout
#include <iomanip>//setw()






#include <fstream>
#include <memory.h>//typeinfo
#include <typeinfo>//typeinfo
#include <string.h>//string
#include <cstring>//string
#include <cstddef>//string


//新增這一行
#define DELAYTIME 1500  //定義每次顯示自動加工廠生產線機台要間隔多少毫秒



#define MAXQUEEN 5//定義最大堆疊容量,如果要超過10請修改switch case敘述
#define TRUE 1
#define FALSE 0
#define SOLUTION 120//SOLUTION = (MAXQUEEN)! 例如5!=120, 3!=6,4!=24,7! = 5040
#define ARRAYSIZE 6//ARRAYSIZE = MAXQUEEN+1
using namespace std;
int queen[MAXQUEEN];//存放8個皇后之列位置
int number=0;//計算總共有幾組解的總數
//決定皇后存放的位置
//輸出所需要的結果
#include "arrays.h"
UnorderedArray<int> array(4);




int SNum[SOLUTION][MAXQUEEN];//SNum = SolutionNumber
char SChar[SOLUTION][MAXQUEEN];//SChar = SolutionChar
char buf[SOLUTION*MAXQUEEN];//buf = bufferNumber

int remain;//remain = remain number

int calculate(int ,int);

#pragma runtime_checks("", off)

void print_table()
{
     int x=0,y=0;
     number+=1;


remain = SOLUTION-number;

     cout<<"自動產生"<<MAXQUEEN<<"個號碼組合的第"\
<<setw(7)<<number<<"組號碼,";
cout<<"進度為剩下"<<remain<<"組尚未處理。"<<endl;



int k=0;
for(x=0;x<MAXQUEEN;x++)
     {
        for(y=0;y<MAXQUEEN;y++)
           if(x==queen[y])
  {
k=y+1;
  array.push(k);
  }

     }


}



void decide_position(int value)
{
   int i=0;// i=行
   while(i<MAXQUEEN)
   {
   //是否受到攻擊的判斷式
      if(calculate(i,value)!=TRUE)
      {
         queen[value]=i;//只有在未受攻擊時將計算值存入皇后陣列

         if(value==MAXQUEEN-1)//列已到末端
            print_table();//只有在未受攻擊時列已到末端時才印出結果
         else
            decide_position(value+1);//只有在未受攻擊時將計算值存入皇后陣列,
//計算完成以後,列+1遞迴重新執行函數( value=列)
      }
 //受攻擊時值不能存入陣列
      i++;//不論是否遭受攻擊都換行重新執行函數 i=行
   }  
}
//0,0 i++
//1,0 queen[0]=1
//1,1 flag=1,i++
//2,1 queen[1]=2
//2,2 flag=1,i++



//測試在(row,col)上的皇后是否遭受攻擊
//若遭受攻擊則傳回值為1,否則傳回0
int calculate(int row,int col)
{
    int i=0,flag=FALSE;
    //int offset_row=0,offset_col=0;
    while((flag!=TRUE)&&i<col)//當未遭受攻擊與i計算值小於VALUE
    {
       //offset_col=abs(i-col);
       //offset_row=abs(queen[i]-row);
       //判斷兩皇后是否在同一列在同一對角線上
       //if((queen[i]==row)||(offset_row==offset_col))
       if((queen[i]==row))//
 //不要在此輸入cout<<"queen["<<i<<"]=="<<row<<endl;
  flag=TRUE;//只有在未受攻擊與計算值小於VALUE,
//當皇后陣列與待求VALUE相同時,判定遭受攻擊
       i++;//逐行檢查
    }
    return flag;
}

#pragma runtime_checks("", off)
//主程式
void construct_A4element(){

int f=0;
int g=0;
int h=0;

remain=0;


A4element *a=(A4element*)calloc(SOLUTION,sizeof(A4element));

while(f<SOLUTION)
{


while(g<(ARRAYSIZE-1))
{
a->identity=f;
a->a_content[g]=array[h];

cout<<"目前核對a["<<f<<"]->a_content["<<g<<"]="<<\
(a->a_content[g])<<endl;//顯示內容

SNum[f][g]=array[h];

//如果要超過10階乘就要加大下面這個switch case敘述
switch(SNum[f][g])
{
case 10:
SChar[f][g]='0';
break;
case 1:
SChar[f][g]='1';
break;
case 2:
SChar[f][g]='2';
break;
case 3:
SChar[f][g]='3';
break;
case 4:
SChar[f][g]='4';
break;
case 5:
SChar[f][g]='5';
break;
case 6:
SChar[f][g]='6';
break;
case 7:
SChar[f][g]='7';
break;
case 8:
SChar[f][g]='8';
break;
case 9:
SChar[f][g]='9';
break;

}


buf[h]=SChar[f][g];

h++;
g++;
}
g=0;
f++;
remain=SOLUTION - f;
cout<<"核對資料結構還剩下"<<remain<<"組。"<<endl;

}

cout<<"計算完成"<<endl;
system("pause");

//----------------------------------------------------------------------


//string str(SOLUTION*MAXQUEEN,' ');

cout<<"號碼產生的數量是 "<<h<<"個。"<<endl;
cout<<"送貨員送咖啡到機台路線計算程式已經計算完成。"<<endl;
cout<<"請按下按鍵顯示結果。"<<endl;
system("pause");


//--------------------------------------------------------
//-------------make SNum----------------------------------

//cout<<"計算SNum當中"<<endl;
int m=0;
int n=0;
int p=0;
    remain=0;

while(m<SOLUTION)
{
while(n<MAXQUEEN)
{
a->identity=m;
a->a_content[n]=array[p];

//cout << "核對SNum[" <<m<< "]["<< n <<"]="<<(SNum[m][n])<<endl;
//cout << "核對SChar["<<m<<"]["<<n<<"]="<<(SChar[m][n])<<endl;

SNum[m][n]=a->a_content[n];




p++;

n++;
}
n=0;
//---遞迴顯示自動號碼----

system("CLS");
cout<<"送貨員送咖啡到機台路線計算程式:"<<endl;
cout<<"送貨員路線組合第"<<(m+1)<<"組的組合是:  首先,"<<endl;
for(int t=0;t<MAXQUEEN;t++)
cout<<"送貨員將咖啡送到生產線第"<<SChar[m][t]<<"號機台。接下來,"<<endl;
cout<<"就完成了咖啡的運送。"<<endl;
//-----------------------
m++;
remain=SOLUTION-m;

cout<<"以上是送貨員送咖啡到機台所有路線的第"<<m<<\
"組的組合,剩下"<<remain<<"組"<<endl;

//system("pause");
Sleep(DELAYTIME);
}

cout<<"以上是自動號碼產生器實作,"<<endl;



//取消了輸出檔案的功能

cout<<"array的型態 = "<<typeid(array).name()<<endl;
cout<<"感謝Allen Sherrod先生的資料結構教科書,僅此致謝。"<<endl;
cout<<"Auto Number Generator: Visual C++ 2005版,"<<endl;
cout<<"詹宗運製作,"<<endl;
cout<<"免費授權Microsoft公司進行進一步的修改與工業化,"<<endl;
cout<<"用來攤平記憶體缺損所造成的工業損失,"<<endl;
cout<<"並且提供VC++社群做為討論與修改的使用。"<<endl;
system("pause");
free(a);

}




//主程式


#pragma runtime_checks("", off)

// RTC Error Handler
int MyErrorHandler(int errType, const char* file, int line,
    const char* module, const char* format, ...)
{
    // 1. Prevent re-entrance
    static long IsRunning = 0;
    while ( InterlockedExchange(&IsRunning, 1) )
        Sleep(1);

    // 2. Get the RTC error number from the var_arg list
    va_list ArgList;
    va_start(ArgList, format);
    _RTC_ErrorNumber ErrorNumber = va_arg(ArgList, _RTC_ErrorNumber);
    va_end(ArgList);

    char s[1024];
    // 3. Get the error description
    const char* ErrorDesc = _RTC_GetErrDesc(ErrorNumber);
    sprintf_s(s, sizeof(s), "%s occured.\nLine: %i\
\nFile: %s\nModule: %s\nClick OK to break into debugger.", \
 ErrorDesc, line, file ? file : "Unknown",\
    module ? module : "Unknown");
 
// 4. Display message box
    MessageBoxA(NULL, s, "Run-Time Error", MB_OK);
    // 5. Go ahead and break into the debugger
    return 1;
}
#pragma runtime_checks("", restore)




int _tmain(int argc, _TCHAR* argv[])
{


cout<<"自動號碼生成器應用:送貨員送咖啡到機台路線計算程式,"<<endl;
cout<<"詹宗運製作。"<<endl;
cout<<"現在送貨員接到訂單要送咖啡到生產線的機台,"<<endl;
cout<<"接下來會自動運算出許多訊息,請耐心等待訊息停止以後,"<<endl;
cout<<"再按下按鍵繼續運算。"<<endl;
cout<<"開始運算,請準備。"<<endl;
system("pause");

    cout<<"\t";



    _RTC_error_fn OldHandler;
    // Set new RTC error handler and save the old one
    OldHandler = _RTC_SetErrorFunc(&MyErrorHandler);



decide_position(0);
construct_A4element();

    _RTC_SetErrorFunc(OldHandler);
system("pause");


return 0;
}

//程式碼到此為止


//以下是arrays.h程式碼
/*
   Array Data Structure
   Chapter 2
   Data Structures for Game Developers
   Created by Allen Sherrod
*/


#include<cassert>


#ifndef _ARRAYS_H_
#define _ARRAYS_H_


template<typename T>
class UnorderedArray
{
   public:
      UnorderedArray(int size, int growBy = 1) :
                     m_array(NULL), m_maxSize(0),
                     m_growSize(0), m_numElements(0)
      {
         if(size)
            {
               m_maxSize = size;
               m_array = new T[m_maxSize];
               memset(m_array, 0, sizeof(T) * m_maxSize);

               m_growSize = ((growBy > 0) ? growBy : 0);
            }
      }

      ~UnorderedArray()
      {
         if(m_array != NULL)
            {
               delete[] m_array;
               m_array = NULL;
            }
      }

      void push(T val)
      {
         assert(m_array != NULL);

         if(m_numElements >= m_maxSize)
            {
               Expand();
            }

         m_array[m_numElements] = val;
         m_numElements++;
      }

      void pop()
      {
         if(m_numElements > 0)
            m_numElements--;
      }

      void remove(int index)
      {
         assert(m_array != NULL);

         if(index >= m_maxSize)
            {
               return;
            }

         for(int k = index; k < m_maxSize - 1; k++)
            m_array[k] = m_array[k + 1];
   
         m_maxSize--;

         if(m_numElements >= m_maxSize)
            m_numElements = m_maxSize - 1;
      }

      T& operator[](int index)
      {
         assert(m_array != NULL && index <= m_numElements);
         return m_array[index];
      }

      int search(T val)
      {
         assert(m_array != NULL);

         for(int i = 0; i < m_numElements; i++)
            {
               if(m_array[i] == val)
                  return i;
            }

         return -1;
      }

      void clear()      { m_numElements = 0; }
      int GetSize()     { return m_numElements; }
      int GetMaxSize()  { return m_maxSize; }
      int GetGrowSize() { return m_growSize; }

      void SetGrowSize(int val)
      {
         assert(val >= 0);
         m_growSize = val;
      }

   private:
      bool Expand()
      {
         if(m_growSize <= 0)
            return false;

         T *temp = new T[m_maxSize + m_growSize];
         assert(temp != NULL);

         memcpy(temp, m_array, sizeof(T) * m_maxSize);

         delete[] m_array;
         m_array = temp;

         m_maxSize += m_growSize;

         return true;
      }

   private:
      T *m_array;

      int m_maxSize;
      int m_growSize;
      int m_numElements;
};


template <typename T>
class OrderedArray
{
   public:
      OrderedArray(int size, int growBy = 1) :
                   m_array(NULL), m_maxSize(0),
                   m_growSize(0), m_numElements(0)
      {
         if(size)
            {
               m_maxSize = size;
               m_array = new T[m_maxSize];
               memset(m_array, 0, sizeof(T) * m_maxSize);

               m_growSize = ((growBy > 0) ? growBy : 0);
            }
      }

      ~OrderedArray()
      {
         if(m_array != NULL)
            {
               delete[] m_array;
               m_array = NULL;
            }
      }

      int push(T val)
      {
         assert(m_array != NULL);

         if(m_numElements >= m_maxSize)
            {
               Expand();
            }

         int i, k;

         for(i = 0; i < m_numElements; i++)
            {
               if(m_array[i] > val)
                  break;
            }

         for(k = m_numElements; k > i; k--)
            {
               m_array[k] = m_array[k - 1];
            }

         m_array[i] = val;
         m_numElements++;

         return i;
      }

      void pop()
      {
         if(m_numElements > 0)
            m_numElements--;
      }

      void remove(int index)
      {
         assert(m_array != NULL);

         if(index >= m_maxSize)
            {
               return;
            }

         for(int k = index; k < m_maxSize - 1; k++)
            m_array[k] = m_array[k + 1];
   
         m_maxSize--;

         if(m_numElements >= m_maxSize)
            m_numElements = m_maxSize - 1;
      }

      // Making this const allows for reading but not writing.
      const T& operator[](int index)
      {
         assert(m_array != NULL && index <= m_numElements);
         return m_array[index];
      }

      int search(T searchKey)
      {
         assert(m_array != NULL);

         int lowerBound = 0;
         int upperBound = m_numElements - 1;
         int current = 0;

         while(1)
            {
               current = (lowerBound + upperBound) >> 1;
             
               if(m_array[current] == searchKey)
                  {
                     return current;
                  }
               else if(lowerBound > upperBound)
                  {
                     return -1;
                  }
               else
                  {
                     if(m_array[current] < searchKey)
                        lowerBound = current + 1;
                     else
                        upperBound = current - 1;
                  }
            }

         return -1;
      }

      void clear()      { m_numElements = 0; }
      int GetSize()     { return m_numElements; }
      int GetMaxSize()  { return m_maxSize; }
      int GetGrowSize() { return m_growSize; }

      void SetGrowSize(int val)
      {
         assert(val >= 0);
         m_growSize = val;
      }

   private:
      bool Expand()
      {
         if(m_growSize <= 0)
            return false;

         T *temp = new T[m_maxSize + m_growSize];
         assert(temp != NULL);

         memcpy(temp, m_array, sizeof(T) * m_maxSize);

         delete[] m_array;
         m_array = temp;

         m_maxSize += m_growSize;

         return true;
      }

   private:
      T *m_array;

      int m_maxSize;
      int m_growSize;
      int m_numElements;
};


#endif
//arrays.h程式碼到此為止


//以下是stdafx.h程式碼
// stdafx.h : 可在此標頭檔中包含標準的系統 Include 檔,
// 或是經常使用卻很少變更的
// 專案專用 Include 檔案
//

#pragma once

#ifndef _WIN32_WINNT // 允許使用 Windows XP (含) 以後版本的特定功能。
#define _WIN32_WINNT 0x0501 // 將它變更為針對 Windows 其他版本的適當值。
#endif

#include <stdio.h>
#include <tchar.h>



// TODO: 在此參考您的程式所需要的其他標頭
//程式碼到此為止

5 則留言:

  1. 2015/8/29 網誌已經更新,加上了我本人的簽名。

    回覆刪除
  2. 請教一下,雖然聽此功能可以節省人力,程式也有編譯成功,但執行完後,我還是不知道要如何應用,
    而八皇后的演算法我也有練習寫過,實際上在自動化領域,操作的流程反而是最重要的,而驗算法最多是用到一些數學,但關於計算維度,還真的沒有用過。
    可以請大大在具體說明,算出來後,有什麼東西可以實踐。

    回覆刪除
  3. 首先很高興見到你的留言,
    謝謝你到我的部落格觀看程式碼。

    我的作品Auto Number Generator會自動產生一個叫做
    AutoNumberGeneratorElectronicList.txt的數字階乘檔案,
    直接讀取該文字檔案就可以得到八皇后問題的排列解法,
    在應用上面十分方便。
    生成txt原始網址:
    http://joeymovieyoutube.blogspot.tw/2014/11/visual-c-2005auto-number-generator.html

    比如說現在有5個人要去買星際大戰的公仔,
    不同的攤位賣的是不同的公仔。
    為了決定第幾個人可以到第幾個攤位去買公仔,
    想做路線評估的組合跟研究,
    就可以用這個自動產生器做初步的評估和研究。
    我的買公仔程式範例網址:
    http://joeymovieyoutube.blogspot.tw/2015/08/visual-c-2005-auto-number-generator.html

    未來如果增加到10個人要到10個不同攤位買不同公仔,
    就要調整增加階乘的數字來計算出所有排列的更多結果。
    10階乘的顯示所有解,可能要長達好幾個星期之久,
    算是相當大型的程式。
    接下來你就可以透過改寫程式來處理一些工業化問題,
    像是「某人必定購買特定一個攤位的公仔的所有排列解法共有哪些路線」
    或是「某人避免購買某一個攤位的公仔的所有排列解法」
    這些都可以透過改寫程式來計算。

    再舉一個例子,
    比如說現在有一個美女要去美容,
    她的表皮一共有5層,
    每一層分別要打一種玻尿酸,
    請問如何決定第幾層表皮可以打第幾種玻尿酸。
    這時候就可以用這個程式計算出所有排列120種的解答。
    這對臨床研究的案例使用也會有幫助的。
    如果到民國150年的時候她的表皮增加到10層,
    這時候就要調整階乘的維度,計算出3628800種解答。
    再用這個程式計算出第幾層表皮可以打第幾種玻尿酸。
    越大的層數就要計算更大的階乘數目這一點是不會錯的。
    接下來你就可以處理一些工程問題,像是「
    「避免施打某種玻尿酸在某一層皮膚的所有排列解法」
    或是「必須施打某種玻尿酸在某一層皮膚的所有排列解法」
    這些都可以透過改寫本程式算出所有解法來。
    至於這個2005的程式要如何改寫,
    就交給2015的程式員來繼續努力吧。
    歡迎大家多多利用本留言版來討論。

    階乘排列的應用是相當多的,
    我在部落格有一些範例像是宅男買公仔,工廠機台送咖啡,
    或是如何坐捷運到基隆共有幾條路線。
    你可以到我的部落格點選拷貝範例來跑跑看程式碼。

    如果要計算更進一步的排列組合,
    你可以參考另一位網友CxxlMan改編我的程式所寫的排列組合產生器,
    網址是:
    http://blog.cxxl3d.tk/2015/03/blog-post.html

    最後歡迎大家有心得要分享都可以留言給我或是留言在這個留言版。

    回覆刪除
  4. 2016/6/26 網誌已經更新。
    這是一個比較多人留言的範例,
    這個範例可以計算送咖啡到機台給工作人員共有幾種路線排列組合,
    如果有時間的網友都可以試試看!
    10條路線的排列組合一共有3628800組路線,
    請大家有空的時候改數字到10條路線,
    親身體驗本程式讓電腦連續計算好幾個星期的壯觀畫面。

    回覆刪除
  5. 2016/11/7 網誌已經更新,參考了美國大選的英文用法,把build_A4element()改名成較為正確的construct_A4element()。

    回覆刪除