2009年10月29日 星期四

畫星星

 
純粹打發時間 :-)

#define _ _asm
int main ()??<
    int  i;
    char s[]("*****");  
    _ mov esi,5 
  L:_ dec esi    _ mov i,esi 
    puts (s+i);  _ mov esi,i 
    _ or esi,esi _ jne L??>
*
**
***
****
*****

另一種直觀做法:
int main()
{
    char s[80] = {0};
    int  i = 0, N = 5;
    while (i<N? s[i++]='*':0) puts (s);
}
*
**
***
****
*****

int main() {
    #define for puts
    do; while (
        for ("*"+
            for ("**"+
                for ("***"+
                    for ("****"+
                        for ("*****"))))));
}
*****
****
***
**
*
#define 回圈 _
void 回圈(int n) 
{
    n &&   (回圈(n-2),  1);
    puts   ("*******"+8-n),
    printf ("    "   +n/2);
}
int main()
{
    回圈(10);
}
* *** ***** *******
//執行需求:32 bits 機器 + cdecl 堆疊慣例

#include <stdio.h>
#include <iostream>
using namespace std;

char s[] = "*************************";
void star (int i)
{
    printf ("%*c%s\n",i+1,' ',s+i);
    i&&(*((int volatile*)&--i-1)-=5);
}
int main (/* daviddr 081203 */)
{
    int n; cin>>n;
    s[n]=0; star(n);  
}
* ** *** **** *****
這是一種綁死在 Calling Convention (extern"C" 或 _cdecl)
與 OS 與 Compiler 與 IA32 上的寫法,純粹 for fun。

這一句的邏輯等同:
void star (int i)
{
star_:
    printf ("%*c%s\n",i/2+1,' ',s+i-1);
    if (i != 0)
    {
        i = i - 2;     //----i;
        goto star_;    //(*((int volatile*)&i-1)-=5)
    }
}
觀察呼叫端的 star(n);
她會生成:
位址 組合語言 ---------------------------------------- 00411603 mov eax,dword ptr [n] 00411606 push eax 00411607 call star (411055h) 0041160C add esp,4
進入一個什麼都不做的 void star (int i) 後,
生成如下組語:
void star (int i) { push ebp mov ebp,esp sub esp,0C0h push ebx push esi push edi lea edi,[ebp-0C0h] mov ecx,30h mov eax,0CCCCCCCCh rep stos dword ptr es:[edi] } pop edi pop esi pop ebx mov esp,ebp pop ebp ret
此時參數堆疊內容為:
位址 內容 | | |----------| &i-4 | 0x41160C | <-- 此為 ret 的返回位址 |----------| &i | n | |----------|
我們在程式尾端使用 (int volatile*)&i
來確實取得 i 在記憶體中的位址,之後「-1」
即是扣掉 sizeof (void*),其值為 0x4
再將其內容,也就是 0x41160C,-5,改成 0x411607
於是 ret 又轉跳至 call star (411055h)
等於將函式呼叫轉成一種「迴圈」~
一直執行到 i==0 時才跳離!

當對底層實作有一定的掌握時,
有時可以無視語言規格限制,另闢蹊徑來達成目的..
只是,這些技巧幾乎都不具普適性,僅可視為一種例外;

他們唯二的好處是:
1. 作為一種 coding 上的娛樂。
2. 激發出一種新的程式編寫方法,
    或是為了將別種語言獨有的機制「暫時」引進來「試用」,
    作為開發新程式語言 (or 寫作風格) 的靈感或基礎。

#include <stdio.h>
char*_= 
"                                                 "
"                                                       ";
#define P(L_,__,o) for(;*_;_++)\
    putchar ((*_<3?_++,2:*_&1)[" "#o]);\
        puts (#L_" "#__);

int main() {P(Merry,Christmas!,\n*);}
應景程式,耶誕快樂:
* *** ************* ********* ******* *** *** * * Merry Christmas!
使用格式化字串,再加另一個遞迴就是 BNF 了:
void rep (char c, int n) 
{
    if (n) rep (putchar(c), n-1);
}
 
void put (char* s)
{
    char c = *s++;
    if (c) {
        if (isdigit(*s)) 
            rep (c, strtol (s,&s,10));
        else 
            rep (c==','?'\n':c, 1);
        put (s);
    }
}

int main()
{
    put ("*5,* 3*,*5\n\n");
    put ("*7, 6*, 6*,*7, 6*, 6*,*7");
}
***** * * ***** ******* * * ******* * * *******

變形題,印出如下字母三角,高度為 5~10:
EEEEEEEEE DDDDDDD CCCCC BBB A
#include <stdio.h>
#include <time.h>
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;

//比較快

int f1()
{    
    char s[80] = {0};
    int i,j, n = rand()%6+5
    for (i=0; j=n-i; ++i) 
        printf ("%*s\n", j+n, 
            memset (s+i*2, '@'+j, j*2-1));
}

//使用cout:

int f2()
{
    int i, n = rand()%6+5;
    for (i=0; i<n; ++i) 
        cout << setw(i) <<setfill(' ') 
             << "" << setw((n-i)*2) 
             << setfill (char('@'+n-i)) 
             << "\n";
}

//也可以寫成:

int f3()
{
    int i, n = rand()%6+5;
    for (i=0; i<n; ++i) 
        cout << string (i, ' ')  
             << string ((n-i)*2, '@'+n-i) 
             << "\n";
}

int main ()
{
    srand (time(0));
    f1(); f2(); f3();
}

以星星印字:
#undef UNICODE
#include <windows.h>
int main()
{
    HDC hdc = GetDC (GetConsoleWindow());
    TextOut (hdc, 0,0 ,"永" ,2); 
    for (int x, y=0; y<15; y++, puts(""))
        for (x=0; x<15; x++)
            printf (GetPixel (hdc,x,y)?"  ":"**");
    SelectObject (hdc, GetStockObject (4));
    Rectangle (hdc, 0,0, 16,16);
}
輸出:
****** **** ************ **** **** **** **** ******************** **** ****** **** ****** **** ******** **** **** **** **** **** **** **** **** **** **********
印菱形:
void dia (int n, int i=0, int x=0, int y=2)
{
    if (i++ < n) {
        COORD c = {(n+x)*2, y};
        SetConsoleCursorPosition (
            GetStdHandle (STD_OUTPUT_HANDLE), c);
        cout <<"*";
        dia (n, i, x+1, y+1); 
        dia (n, i, x-1, y+1);
        dia (n, i, x,   y+2);
        if (y == 2*n && x <2*n*(n-1)) 
            dia (n, 0, x+2*n);        
    }    
}
int main()
{
     int n;
     cout << "輸入一個數字: ";
     cin >> n;
     dia (n); 
}
輸出:
   *      *      *      *   * *    * *    * *    * *  * * *  * * *  * * *  * * * * * * ** * * ** * * ** * * *  * * *  * * *  * * *  * * *   * *    * *    * *    * *    *      *      *      *

沒有留言:

張貼留言