Rev 8185 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
10 | reyssat | 1 | /* Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis |
2 | * |
||
3 | * This program is free software; you can redistribute it and/or modify |
||
4 | * it under the terms of the GNU General Public License as published by |
||
5 | * the Free Software Foundation; either version 2 of the License, or |
||
6 | * (at your option) any later version. |
||
7 | * |
||
8 | * This program is distributed in the hope that it will be useful, |
||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
11 | * GNU General Public License for more details. |
||
12 | * |
||
13 | * You should have received a copy of the GNU General Public License |
||
14 | * along with this program; if not, write to the Free Software |
||
15 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
16 | */ |
||
17 | |||
18 | /* Solves cryptarithms, to be interfaced by wims. */ |
||
19 | |||
20 | #define MAX_LINES 64 |
||
21 | #define MAX_CHARS 32 |
||
22 | |||
8185 | bpr | 23 | #include "../includes.h" |
10 | reyssat | 24 | |
25 | char basetab[MAX_LINES][MAX_CHARS]; |
||
26 | int carry[MAX_LINES][MAX_CHARS+8]; |
||
27 | char corresp[32],bcorresp[16]; |
||
28 | int linecnt,charcnt[MAX_LINES],activelen,maxlen; |
||
29 | int active[MAX_LINES]; |
||
30 | int style[MAX_LINES]; |
||
31 | int total=0; |
||
32 | |||
33 | char *input; |
||
34 | |||
7676 | bpr | 35 | /* Print the result */ |
10 | reyssat | 36 | void printresult(char curr[]) |
37 | { |
||
12248 | bpr | 38 | int i,j; |
39 | char ch; |
||
40 | for(i=0;i<linecnt;i++) { |
||
41 | for(j=0;j<charcnt[i];j++) { |
||
42 | ch=basetab[i][j]; |
||
43 | if(ch==0) ch=' '; |
||
44 | else if(ch>='A' && ch<='Z') ch=curr[ch-'A']; |
||
45 | printf(" %d",ch); |
||
10 | reyssat | 46 | } |
47 | printf("\n"); |
||
12248 | bpr | 48 | } |
49 | printf("\n"); |
||
10 | reyssat | 50 | } |
51 | |||
7676 | bpr | 52 | /* returns 1 if OK, 0 if bad. */ |
10 | reyssat | 53 | int putvalue(char ch, char k, char curr[], char currb[]) |
54 | { |
||
12248 | bpr | 55 | int i=ch-'A'; |
56 | if(ch==0) { |
||
57 | if(k>0) return 0; else return 1; |
||
58 | } |
||
59 | if((curr[i]!=-1 && curr[i]!=k) || (currb[k]!=0 && currb[k]!=ch)) |
||
60 | return 0; |
||
61 | curr[i]=k;currb[k]=ch; return 1; |
||
10 | reyssat | 62 | } |
63 | |||
7676 | bpr | 64 | /* check that leading number is not 0. Returns 0 if bad. */ |
10 | reyssat | 65 | int checklead(char curr[]) |
66 | { |
||
12248 | bpr | 67 | int i; |
68 | char ch; |
||
69 | for(i=0;i<linecnt;i++) { |
||
70 | ch=basetab[i][charcnt[i]-1]; |
||
71 | if(curr[ch-'A']<=0) return 0; |
||
72 | } |
||
73 | return 1; |
||
10 | reyssat | 74 | } |
75 | |||
7676 | bpr | 76 | /* returns 0 if fail, 1 if OK. */ |
10 | reyssat | 77 | int colcompute(int c,char curr[],char currb[]) |
78 | { |
||
12248 | bpr | 79 | int i,j,k,sum; |
80 | char ch; |
||
10 | reyssat | 81 | |
12248 | bpr | 82 | switch(style[1]) { |
83 | case '-': |
||
84 | case '+': |
||
85 | case '.': { |
||
86 | for(j=sum=0;j<linecnt;j++) { |
||
87 | if(!active[j]) continue; |
||
88 | ch=basetab[j][c]; |
||
89 | if(ch!=0) { |
||
90 | if(style[j]!='-') sum+=curr[ch-'A']; |
||
91 | else sum-=curr[ch-'A']; |
||
92 | } |
||
7676 | bpr | 93 | } |
12248 | bpr | 94 | lastline: |
95 | sum+=carry[linecnt-1][c]; |
||
96 | carry[linecnt-1][c+1]=(sum+10000)/10-1000; k=(sum+10000)%10; |
||
97 | return putvalue(basetab[linecnt-1][c],k,curr,currb); |
||
98 | } |
||
7676 | bpr | 99 | |
12248 | bpr | 100 | case '*': { |
101 | char c1,c2; |
||
102 | c2=basetab[0][c]; |
||
103 | if(c2!=0) c2=curr[c2-'A']; |
||
104 | for(i=0;i<c && i<linecnt-3;i++) { |
||
105 | c1=basetab[1][i]; |
||
106 | if(c2*c1!=0) sum=c2*curr[c1-'A']+carry[2+i][c]; |
||
107 | else sum=carry[2+i][c]; |
||
108 | carry[2+i][c+1]=sum/10; |
||
109 | if(!putvalue(basetab[2+i][c],sum%10,curr,currb)) |
||
110 | return 0; |
||
7676 | bpr | 111 | } |
12248 | bpr | 112 | c2=basetab[1][c]; |
113 | if(c2!=0) { |
||
114 | c2=curr[c2-'A']; |
||
115 | for(i=0;i<=c;i++) { |
||
116 | c1=basetab[0][i]; |
||
117 | if(c1==0) break; |
||
118 | sum=c2*curr[c1-'A']+carry[2+c][i]; |
||
119 | carry[2+c][i+1]=sum/10; |
||
120 | if(!putvalue(basetab[2+c][i],sum%10,curr,currb)) |
||
121 | return 0; |
||
122 | } |
||
123 | } |
||
124 | for(i=sum=0;i<=c && i<linecnt-3;i++) { |
||
125 | ch=basetab[2+i][c-i]; |
||
126 | if(ch!=0) sum+=curr[ch-'A']; |
||
127 | } |
||
128 | goto lastline; |
||
129 | } |
||
7676 | bpr | 130 | |
131 | /* short multiplication */ |
||
12248 | bpr | 132 | case '$': { |
133 | char c1,c2; |
||
134 | for(j=sum=0;j<=c;j++) { |
||
135 | c1=basetab[0][j]; c2=basetab[1][c-j]; |
||
136 | if(c1==0) break; |
||
137 | if(c2==0) continue; |
||
138 | sum+=curr[c1-'A']*curr[c2-'A']; |
||
7676 | bpr | 139 | } |
12248 | bpr | 140 | goto lastline; |
141 | } |
||
7676 | bpr | 142 | |
12248 | bpr | 143 | default: return 0; |
144 | } |
||
10 | reyssat | 145 | } |
146 | |||
147 | void column(int c, char prev[], char prevb[]) |
||
148 | { |
||
12248 | bpr | 149 | char curr[32], currb[16]; |
150 | int lreg[MAX_LINES],lfix[MAX_LINES]; |
||
151 | int i,j,icarry; |
||
152 | char ch; |
||
10 | reyssat | 153 | |
12248 | bpr | 154 | memset(lreg,0,sizeof(lreg)); |
155 | memset(lfix,0,sizeof(lfix)); |
||
10 | reyssat | 156 | |
12248 | bpr | 157 | for(i=0;i<linecnt;i++) { |
158 | if(!active[i]) continue; |
||
159 | ch=basetab[i][c]; |
||
160 | if(ch==0 || prev[ch-'A']!=-1) lfix[i]=1; |
||
161 | } |
||
162 | for(icarry=0;;icarry=1) { |
||
163 | memmove(curr,prev,sizeof(curr)); |
||
164 | memmove(currb,prevb,sizeof(currb)); |
||
10 | reyssat | 165 | for(i=0;i<linecnt;i++) { |
12248 | bpr | 166 | if(!active[i] || lfix[i]) continue; |
167 | for(j=lreg[i]+icarry;j<10 && prevb[j]!=0;j++); |
||
168 | if(j>=10) { |
||
169 | for(j=0;j<10 && prevb[j]!=0;j++); |
||
170 | if(j>=10) return; |
||
171 | icarry=1; |
||
172 | } |
||
173 | else icarry=0; |
||
174 | lreg[i]=j; |
||
10 | reyssat | 175 | } |
12248 | bpr | 176 | if(icarry) break; |
177 | for(i=0;i<linecnt;i++) { |
||
178 | if(!active[i] || lfix[i]) continue; |
||
179 | if(!putvalue(basetab[i][c],lreg[i],curr,currb)) goto loopend; |
||
180 | } |
||
181 | if(!colcompute(c,curr,currb)) continue; |
||
182 | if(c<activelen-1) column(c+1,curr,currb); |
||
183 | else { |
||
184 | for(i=activelen;i<maxlen;i++) { |
||
185 | if(!colcompute(i,curr,currb)) goto loopend; |
||
7676 | bpr | 186 | } |
187 | for(i=0;i<linecnt;i++) { |
||
12248 | bpr | 188 | if(active[i]) continue; |
189 | if(carry[i][maxlen]) goto loopend; |
||
7676 | bpr | 190 | } |
12248 | bpr | 191 | if(!checklead(curr)) goto loopend; |
192 | total++; |
||
193 | printresult(curr); |
||
10 | reyssat | 194 | } |
12248 | bpr | 195 | loopend: |
196 | } |
||
10 | reyssat | 197 | } |
198 | |||
199 | int main(int argc, char *argv[]) |
||
200 | { |
||
12248 | bpr | 201 | char *p,*p2,*p3; |
202 | int i; |
||
203 | input=getenv("wims_exec_parm"); |
||
7676 | bpr | 204 | /* nothing to do if no problem */ |
12248 | bpr | 205 | if(input==NULL || *input==0) return 0; |
10 | reyssat | 206 | |
12248 | bpr | 207 | memset(basetab,0,sizeof(basetab)); |
208 | memset(corresp,-1,sizeof(corresp)); |
||
209 | memset(bcorresp,0,sizeof(bcorresp)); |
||
210 | memset(carry,0,sizeof(carry)); |
||
211 | memset(active,0,sizeof(active)); |
||
10 | reyssat | 212 | |
12248 | bpr | 213 | for(p=input+strlen(input);p>input && isspace(*(p-1));p--); |
214 | *p=0; |
||
215 | activelen=maxlen=0; |
||
216 | active[0]=active[1]=1; |
||
217 | for(linecnt=0,p=input;*p!=0 && linecnt<MAX_LINES;p=p3) { |
||
218 | p2=strchr(p,'\n'); |
||
219 | if(p2==NULL) { |
||
220 | p2=p+strlen(p);p3=p2; |
||
221 | } |
||
222 | else p3=p2+1; |
||
223 | while(isspace(*p)) p++; |
||
224 | if(strchr("+-*/=.",*p)!=NULL) { |
||
225 | style[linecnt]=*p;p++; |
||
7676 | bpr | 226 | while(isspace(*p)) p++; |
12248 | bpr | 227 | } |
228 | else style[linecnt]='+'; |
||
229 | if(*p3==0) style[linecnt]='='; |
||
230 | if(linecnt>1) { |
||
231 | switch(style[1]) { |
||
232 | case '+': |
||
233 | case '-': { |
||
234 | if(*p3!=0) active[linecnt]=1; |
||
235 | break; |
||
236 | } |
||
7676 | bpr | 237 | |
12248 | bpr | 238 | case '*': |
239 | case '/': |
||
240 | case '=': |
||
241 | break; |
||
242 | } |
||
243 | } |
||
244 | while(p2>p && isspace(*(p2-1))) p2--; |
||
245 | if(p2>p+MAX_CHARS) p2=p+MAX_CHARS; |
||
246 | *p2=0; |
||
247 | if(p2<=p) continue; |
||
248 | for(i=0;i<p2-p;i++) { |
||
249 | char ch; |
||
250 | ch=toupper(*(p2-i-1)); |
||
7676 | bpr | 251 | /* bad char */ |
12248 | bpr | 252 | if(ch<'A' || ch>'Z') return 1; |
253 | basetab[linecnt][i]=ch; |
||
10 | reyssat | 254 | } |
12248 | bpr | 255 | charcnt[linecnt]=p2-p; |
256 | if(active[linecnt] && p2-p>activelen) activelen=p2-p; |
||
257 | if(p2-p>maxlen) maxlen=p2-p; |
||
258 | linecnt++; |
||
259 | } |
||
7676 | bpr | 260 | /* multiplication */ |
12248 | bpr | 261 | if(style[1]=='*') { |
262 | if(linecnt==3) style[1]='$'; |
||
263 | else { |
||
264 | if(linecnt!=charcnt[1]+3) return 1; |
||
265 | for(i=3;i<linecnt-1;i++) |
||
266 | if(charcnt[i]+i-2>maxlen) maxlen=charcnt[i]+i-2; |
||
10 | reyssat | 267 | } |
12248 | bpr | 268 | } |
10 | reyssat | 269 | |
12248 | bpr | 270 | column(0,corresp,bcorresp); |
271 | printf("\n!total %d solution(s).\n\n",total); |
||
272 | return 0; |
||
10 | reyssat | 273 | } |