これは岩手県立大学アドベントカレンダー7日目の記事です。
まず大学のアドベントカレンダーなので少々内輪なネタがあることをご了承ください。
アドベントカレンダー7日目の今日ですが、IPU Slack という岩手県立大学卒業生が100人以上いるSlackにこんなことを書いている方がいらっしゃいました。
エンジニアたるもの納品日に「まだできていないので納品できません」といってはいけないんですね。事前調整して、遅れそうならば解決するための策をたてるべきです。
そこで今日は、ここぞとばかりに老害力を発揮して代理で投稿します。
(知り合いだったのでここまでネタです。思いやりに満ちあふれたマサカリのない社会を望んでいます。)
ソフトウェア演習B
いまはカリキュラムが変わってしまいましたが、懐かしの講義といえば、そう「ソフトウェア演習B」ですね。
たしか1年生の後期に受けるC言語を学ぶ演習科目で、必修科目ですね。これを落とすと進級できないやつです。
当時は、研究室毎に10人程度の学生と先生1名という少人数教育で、必ず毎回提出が必要なレポートがありました。
研究室によっては先輩のプレチェックをして、先輩のOKをもらってから先生に提出するというフローがあったりします。
岩手県立大学ソフトウェア情報学部は、1年生から研究室配属される(これは珍しいらしい?)ので、この特色をうまく活かしたいい演習科目でした。
いま僕がプログラミングを生業にして食って行けているのはこの講義のおかげだと思います。(ぉ
オセロ(リバーシ)の課題
さて、ソフトウェア演習Bで一番の山場といえば、「C言語でリバーシを作る課題」ではないでしょうか。
この課題ではじめて研究室に寝泊まりするという人が現れたりしますね。
ちょうど僕も10年前の今頃受けていたのだと思います。この記事ではそのときの思い出話を書きたいと思います。
リバーシをどれだけ短く作れるか?
当時、僕の研究室はソフトウェア情報学部B棟3Fにある研究室で、いじわるな先輩がいまして、リバーシを可能なかぎり短い行で書けというのです。
いまではバイト数でもなくなぜ行にこだわったか、さっぱり思い出せないのですが、ある一定のコーディング規約(これも思い出せない)にのっとってリバーシを作りました。
(そもそも改行なくせば1行なるじゃん、という話もあったんですが)
25行版
なるべく短くしたのがこれです。でも先輩は「21行(だったか)で過去につくったことあるからもっと短くできるよ」いうのです。
#include <stdio.h>
void displaymap(int a[][8]){
int i,j,symbol[]={'X','-','O'};
for(i=0;i<8;i++)for(j=0;j<8;j++) printf("%c%c",symbol[a[j][i]+1], j/7 * 10) ;
}
int reverse(int a[][8], int c, int x, int y, int dx, int dy, int *g){
if(x <= 0 || x > 8 || y <= 0 || y > 8 || a[x][y]==0 )return 0;
if(a[x][y]==c) return c;
if(reverse(a,c,x+dx,y+dy,dx,dy, g) == c) a[x][y] *= -1 + 0 * (*g)++;
else return 0;
return c;
}
int main(){
int i,j,dx,dy,x,y,c=1,g=0,turn=0,cnt=2,a[8][8]={0},symbol[]={'X','-','O'};
a[3][3]=a[4][4]=-1 * (a[3][4]=a[4][3]=-1);
while(turn <= 60){
displaymap(a);
printf("turn: %d (O:%d, X:%d)\n\n%c x y>", turn, cnt, turn + 4 - cnt,symbol[c+1]);
scanf("%d %d",&x,&y);
if(a[x][y]==0)for(dx=-1;dx<=1;dx++) for(dy=-1;dy<=1;dy++) reverse(a, c, x+dx, y+dy, dx, dy, &g);
if(g!=0)cnt += g + (g=0) * ((a[x][y] = c) * (turn++) * (cnt+=(c+1)/2) * (c*=-1));
else printf("Can't put it here\n");
}
return 0;
}
17行版
朝5時くらいまでずっと短くしようとがんばっていました。ひらめいたときはひとりモニタに向かってにやけた記憶をいまでも鮮明に覚えています。
短くするうえでネックだったのは、if 文を 1行に複数書けないということだったんですね。
ただ、&& と || を組み合わせれば、if 文と同等の手段を実現できるということに気づいて、短くすることができました。
#include <stdio.h>
void displaymap(int a[][8]){
int i,j,symbol[]={'X','-','O'};
for(i=0;i<8;i++)for(j=0;j<8;j++) if(j==7 || 0 * printf("%c",symbol[a[j][i]+1]))printf("%c\n",symbol[a[j][i]+1]);
}
int reverse(int a[][8], int c, int x, int y, int dx, int dy, int *g){
if (!(x <= 0 || x > 8 || y <= 0 || y > 8 || a[x][y]==0 ) &&((a[x][y] == c) || ((reverse(a,c,x+dx,y+dy,dx,dy, g) == c) && (dx=2) ))||dy==2)return c + 0 * ((dx!=2 ) || ( dy!=2 && (dx!=2 || (a[x][y] *= -1) * (*g)++)) - c * (!(x <= 0 || x > 8 || y <= 0 || y > 8 || a[x][y]==0 )));
}
int main(){
int i,j,dx,dy,x,y,c=1,g=0,turn=0,cnt=2,a[8][8]={0},symbol[]={'X','-','O'};
while(turn<=61 && (turn > 0 || (a[3][3]=a[4][4]=-1 * (a[3][4]=a[4][3]=-1)))){
displaymap(a);
if(a[x][y]== 0 * (printf("turn: %d (O:%d, X:%d)\n\n%c x y>", turn, cnt, turn + 4 - cnt,symbol[c+1]) + scanf("%d %d",&x,&y)))for(dx=-1;dx<=1;dx++) for(dy=-1;dy<=1;dy++) reverse(a, c, x+dx, y+dy, dx, dy, &g);
if(((g!=0) && (cnt+=c*g) && !(g = 0 * (a[x][y] = c) * (turn++) * (cnt+=(c+1)/2) * (c*=-1))) || printf("Can't put it here\n"));
}
return 0;
}
おわりに
いま実際に動かしてみたら、25行版は動くんですが17行版はたまにセグフォ起きるんですよね。。。当時は先輩にもしっかりみせて動かしてドヤった記憶はあるのですが...
もしかしたら、Solaris / SPARC アーキテクチャじゃないと動かないようなバグを活用していたかもしれません。(コードを読む気力はないです)
Sun Blade を自宅にお持ちのかたはぜひ試しいただけないでしょうか。
明日は @zaku1992 さんです。よろしくお願いします。