source: trunk/Utilities/GenerateMathProblem01/GenerateMathProblem01.cpp

Last change on this file was 54, checked in by roman, 12 years ago
  • Property svn:keywords set to Id
File size: 6.3 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2012
3// Created by Roman Ryltsov roman@alax.info
4//
5// $Id: GenerateMathProblem01.cpp 54 2012-02-23 20:33:51Z roman $
6
7#include "stdafx.h"
8#include <assert.h>
9
10class Item
11{
12public:
13// Item
14        virtual INT GetPriority()
15        {
16                return 0;
17        }
18        virtual BOOL IsCommutative()
19        {
20                return TRUE;
21        }
22        virtual CString AsString() = 0;
23        virtual BOOL IsOperation()
24        {
25                return FALSE;
26        }
27};
28
29class ValueItem :
30        public Item
31{
32private:
33        INT m_nValue;
34
35public:
36// ValueItem
37        ValueItem(INT nValue = 0) :
38                m_nValue(nValue)
39        {
40        }
41        INT GetValue() const
42        {
43                return m_nValue;
44        }
45        CString AsString()
46        {
47                CString sString;
48                sString.Format(_T("%d"), m_nValue);
49                return sString;
50        }
51};
52
53class OperationItem :
54        public Item
55{
56public:
57        Item* m_pItem1;
58        CHAR m_nSymbol;
59        Item* m_pItem2;
60
61public:
62// OperationItem
63        OperationItem() :
64                m_pItem1(NULL),
65                m_nSymbol(0),
66                m_pItem2(NULL)
67        {
68        }
69        OperationItem(Item* pItem1, CHAR nSymbol, Item* pItem2) :
70                m_pItem1(pItem1),
71                m_nSymbol(nSymbol),
72                m_pItem2(pItem2)
73        {
74                assert(pItem1 && IsValidSymbol(nSymbol) && pItem2);
75        }
76        static BOOL IsValidSymbol(CHAR nSymbol)
77        {
78                return nSymbol && strchr("+-*:", nSymbol) != NULL;
79        }
80        INT GetPriority()
81        {
82                switch(m_nSymbol)
83                {
84                case '+':
85                case '-':
86                        return 2;
87                case '*':
88                case ':':
89                        return 1;
90                }
91                return 0;
92        }
93        BOOL IsCommutative()
94        {
95                switch(m_nSymbol)
96                {
97                case '-':
98                case ':':
99                        return FALSE;
100                }
101                return __super::IsCommutative();
102        }
103        CString AsString()
104        {
105                CString sString;
106                if(m_pItem1->GetPriority() > GetPriority())
107                        sString.AppendFormat(_T("(%s)"), m_pItem1->AsString());
108                else
109                        sString.Append(m_pItem1->AsString());
110                assert(IsValidSymbol(m_nSymbol));
111                sString.AppendFormat(_T(" %c "), m_nSymbol);
112                if(m_pItem2->GetPriority() > GetPriority() || m_pItem2->IsOperation() && m_pItem2->GetPriority() == GetPriority() && !IsCommutative())
113                        sString.AppendFormat(_T("(%s)"), m_pItem2->AsString());
114                else
115                        sString.Append(m_pItem2->AsString());
116                return sString;
117        }
118        BOOL IsOperation()
119        {
120                return TRUE;
121        }
122};
123
124VOID Generate()
125{
126        const INT nResult = 5 + rand() % 95; // Result would be 5..99
127        Item* pItem = new ValueItem(nResult);
128        #if defined(_DEBUG)
129        for(INT nCount = 3; nCount > 0; )
130        #else
131        for(INT nCount = 7 + rand() % 7; nCount > 0; )
132        #endif // defined(_DEBUG)
133        {
134                Item** ppBrokenItem = &pItem;
135                while((*ppBrokenItem)->IsOperation())
136                {
137                        OperationItem* pBrokenOperationItem = static_cast<OperationItem*>(*ppBrokenItem);
138                        ppBrokenItem = &((rand() % 2) ? pBrokenOperationItem->m_pItem1 : pBrokenOperationItem->m_pItem2);
139                }
140                ValueItem* pBrokenValueItem = static_cast<ValueItem*>(*ppBrokenItem);
141                OperationItem* pNewOperationItem = new OperationItem;
142                static const INT g_nAddWeight = 15;
143                static const INT g_nSubtractWeight = 10;
144                static const INT g_nMultiplyWeight = 70;
145                static const INT g_nDivideWeight = 5;
146                INT nOperation = rand() % (g_nAddWeight + g_nSubtractWeight + g_nMultiplyWeight + g_nDivideWeight);
147                for(; ; )
148                {
149                        #pragma region Add
150                        nOperation -= g_nAddWeight;
151                        if(nOperation < 0)
152                        {
153                                const INT nAddend = 5 + rand() % 95; // Result would be 5..99
154                                if(pBrokenValueItem->GetValue() - nAddend < 0)
155                                {
156                                        pNewOperationItem = NULL;
157                                        break; // New Value Item is Negative
158                                }
159                                if(rand() % 2)
160                                {
161                                        pNewOperationItem->m_pItem1 = new ValueItem(pBrokenValueItem->GetValue() - nAddend);
162                                        pNewOperationItem->m_pItem2 = new ValueItem(nAddend);
163                                } else
164                                {
165                                        pNewOperationItem->m_pItem1 = new ValueItem(nAddend);
166                                        pNewOperationItem->m_pItem2 = new ValueItem(pBrokenValueItem->GetValue() - nAddend);
167                                }
168                                pNewOperationItem->m_nSymbol = '+';
169                                break;
170                        }
171                        #pragma endregion
172                        #pragma region Subtract
173                        nOperation -= g_nSubtractWeight;
174                        if(nOperation < 0)
175                        {
176                                const INT nSubtrahend = 5 + rand() % 95; // Result would be 5..99
177                                pNewOperationItem->m_pItem1 = new ValueItem(pBrokenValueItem->GetValue() + nSubtrahend);
178                                pNewOperationItem->m_nSymbol = '-';
179                                pNewOperationItem->m_pItem2 = new ValueItem(nSubtrahend);
180                                break;
181                        }
182                        #pragma endregion
183                        #pragma region Multiply
184                        nOperation -= g_nMultiplyWeight;
185                        if(nOperation < 0)
186                        {
187                                const INT nFactor = 5 + rand() % 95; // Result would be 5..99
188                                if(pBrokenValueItem->GetValue() % nFactor)
189                                {
190                                        pNewOperationItem = NULL;
191                                        break; // There is a Remainder
192                                }
193                                if(rand() % 2)
194                                {
195                                        pNewOperationItem->m_pItem1 = new ValueItem(pBrokenValueItem->GetValue() / nFactor);
196                                        pNewOperationItem->m_pItem2 = new ValueItem(nFactor);
197                                } else
198                                {
199                                        pNewOperationItem->m_pItem1 = new ValueItem(nFactor);
200                                        pNewOperationItem->m_pItem2 = new ValueItem(pBrokenValueItem->GetValue() / nFactor);
201                                }
202                                pNewOperationItem->m_nSymbol = '*';
203                                break;
204                        }
205                        #pragma endregion
206                        #pragma region Divide
207                        //nOperation -= g_nDivideWeight;
208                        //if(nOperation < 0)
209                        {
210                                const INT nDivisor = 5 + rand() % 95; // Result would be 5..99
211                                pNewOperationItem->m_pItem1 = new ValueItem(pBrokenValueItem->GetValue() * nDivisor);
212                                pNewOperationItem->m_nSymbol = ':';
213                                pNewOperationItem->m_pItem2 = new ValueItem(nDivisor);
214                                break;
215                        }
216                        #pragma endregion
217                }
218                if(!pNewOperationItem)
219                        continue;
220                *ppBrokenItem = pNewOperationItem;
221                nCount--;
222        }
223        _tprintf(_T("%s = %d\n"), pItem->AsString(), nResult);
224}
225
226int _tmain(int argc, _TCHAR* argv[])
227{
228        #pragma region Special Case
229        #if defined(_DEBUG)
230        {
231                // NOTE:
232                //   Actual: (77 + 53503) : 8360 : 88 : 12
233                //   Correct: (77 + 53503) : (8360 : 88) : 12
234                OperationItem* pA = new OperationItem(new ValueItem(77), '+', new ValueItem(53503));
235                OperationItem* pB = new OperationItem(new ValueItem(8630), ':', new ValueItem(88));
236                OperationItem* pC = new OperationItem(pA, ':', pB);
237                OperationItem* pD = new OperationItem(pC, ':', new ValueItem(12));
238                _tprintf(_T("pD->AsString() %s\n"), pD->AsString());
239                pD->AsString();
240        }
241        #endif // defined(_DEBUG)
242        #pragma endregion
243        srand(1);
244        for(INT nCount = 0; nCount < 1000; nCount++)
245        {
246                #if defined(_DEBUG)
247                _tprintf(_T("%d: "), nCount);
248                #endif // defined(_DEBUG)
249                Generate();
250                if(nCount % 10 == 9)
251                        _tprintf(_T("\n"));
252        }
253        // NOTE: Who cares about memory leaks, right?
254        return 0;
255}
256
Note: See TracBrowser for help on using the repository browser.