Tetris - Bitte testen



  • muss mich meinem Vorposter (heisst das so?)

    Sag doch einfach "mikey"´ 🤡



  • Lässt sich gut spielen!

    Aber die Hiscore-Liste ist ja mal echt peinlich. 👎

    Da wir ein Programmierer-Forum sind, wären ein paar technische Daten dazu nicht schlecht.



  • WebFritzis Seiten schrieb:

    300 KB

    😮
    guck dir mal das an: http://www.256b.com/demo/477
    🙂



  • Und was hat das jetzt mit WebFritzis Tetris zu tun?



  • http://home.arcor.de/firbach/hmmmmmm.jpg

    Das Programm ist aber trotzdem noch weitergelaufen, bis ich irgendwann verloren hatte. Da ich keine Musik gehört habe, war's vielleicht in diesem Thread.
    Btw. Die Wiederholrate der Tastatur in Windows zu verstellen ist wirklich ein no-go, sehr unschön. 😞



  • Da wir ein Programmierer-Forum sind, wären ein paar technische Daten dazu nicht schlecht.

    Würde ich auch sagen:

    mikey schrieb:

    Kannst du mal ein paar Daten zum Game geben ? Welche GUI Bibliothek hast du verwendet, etc. ?



  • Artchi schrieb:

    vista schrieb:

    WebFritzis Seiten schrieb:

    300 KB

    😮
    guck dir mal das an: http://www.256b.com/demo/477
    🙂

    Und was hat das jetzt mit WebFritzis Tetris zu tun?

    WebFritzis variante ist 300!!? KB gross.



  • Ja und? 😕



  • Artchi schrieb:

    Ja und? 😕

    naja, wenn du schon SO fragst, dann vergiss es einfach... 😃



  • @vista: Die 256Byte Variante würde ich aber nicht mit Webfritzis Variante vergleichen ... da sind Welten dazwischen 🙂



  • Optimizer schrieb:

    http://home.arcor.de/firbach/hmmmmmm.jpg
    Das Programm ist aber trotzdem noch weitergelaufen, bis ich irgendwann verloren hatte. Da ich keine Musik gehört habe, war's vielleicht in diesem Thread.

    Danke für's Testen! Wann ist denn der Fehler aufgetaucht? Direkt nach dem Verlieren?

    Optimizer schrieb:

    Btw. Die Wiederholrate der Tastatur in Windows zu verstellen ist wirklich ein no-go, sehr unschön. 😞

    Wie soll ich das den sonst machen? Wenn jemand ein langsames Delay hat, dann stört das beim Spielen. Beim Schließen des Programmes wird ja wieder der Standard von vorher gesetzt.

    CengizS schrieb:

    @vista: Die 256Byte Variante würde ich aber nicht mit Webfritzis Variante vergleichen ... da sind Welten dazwischen 🙂

    Ja. Auf jeden Fall insofern, dass es bei mir besser aussieht und ich Sound verwende. Alleine das fiese Lachen beim Verlieren hat 70 KB.

    OK, "technische Daten": Als Bibliothek verwende ich die VCL vom Borland C++Builder, die die WinAPI kapselt (und noch mehr tut). Die Tetris-Klasse ist aber plattform-unabhängig. Man muss nur die GUI schreiben. Die benötigten Callback-Funktionen muss man als Members angeben. Ich hau auf Wunsch mal die cpp-Datei hier rein. Wenn es aber zu viel ist, nehm ich es wieder raus. Mal schauen...

    //---------------------------------------------------------------------------
    #include "Tetris.h"
    //---------------------------------------------------------------------------
    
    /*  STONES
    =============
    
    Type 1
    ----  ----  ----  ----
    -##-  -##-  -##-  -##-
    -##-  -##-  -##-  -##-
    ----  ----  ----  ----
    
    Type 2
    ----  --#-  ----  --#-
    ####  --#-  ####  --#-
    ----  --#-  ----  --#-
    ----  --#-  ----  --#-
    
    Type 3
    ----  --#-  ----  --#-
    --##  --##  --##  --##
    -##-  ---#  -##-  ---#
    ----  ----  ----  ----
    
    Type 4
    ----  ---#  ----  ---#
    -##-  --##  -##-  --##
    --##  --#-  --##  --#-
    ----  ----  ----  ----
    
    Type 5
    ----  --#-  ---#  -##-
    -###  --#-  -###  --#-
    -#--  --##  ----  --#-
    ----  ----  ----  ----
    
    Type 6
    ----  --##  -#--  --#-
    -###  --#-  -###  --#-
    ---#  --#-  ----  -##-
    ----  ----  ----  ----
    
    Type 7
    ----  --#-  --#-  --#-
    -###  --##  -###  -##-
    --#-  --#-  ----  --#-
    ----  ----  ----  ----
    
    SCORE: (Level n)
    ------
    four rows ("Tetris"): 1200*(n+1)
    
    three rows          : 300*(n+1)
    
    two rows            : 100*(n+1)
    
    one row             : 40*(n+1)
    
    drop                : n+1
    
    New level after     : 10 deleted rows
    */
    
    //---------------------------------------------------------------------------
    const CPoint stones[7][4][4] =
    {
       { {{1,1},{2,1},{1,2},{2,2}}, {{1,1},{2,1},{1,2},{2,2}}, {{1,1},{2,1},{1,2},{2,2}}, {{1,1},{2,1},{1,2},{2,2}} },
       { {{0,1},{1,1},{2,1},{3,1}}, {{2,0},{2,1},{2,2},{2,3}}, {{0,1},{1,1},{2,1},{3,1}}, {{2,0},{2,1},{2,2},{2,3}} },
       { {{2,1},{3,1},{1,2},{2,2}}, {{2,0},{2,1},{3,1},{3,2}}, {{2,1},{3,1},{1,2},{2,2}}, {{2,0},{2,1},{3,1},{3,2}} },
       { {{1,1},{2,1},{2,2},{3,2}}, {{3,0},{2,1},{3,1},{2,2}}, {{1,1},{2,1},{2,2},{3,2}}, {{3,0},{2,1},{3,1},{2,2}} },
       { {{1,1},{2,1},{3,1},{1,2}}, {{2,0},{2,1},{2,2},{3,2}}, {{3,0},{1,1},{2,1},{3,1}}, {{1,0},{2,0},{2,1},{2,2}} },
       { {{1,1},{2,1},{3,1},{3,2}}, {{2,0},{3,0},{2,1},{2,2}}, {{1,0},{1,1},{2,1},{3,1}}, {{2,0},{2,1},{1,2},{2,2}} },
       { {{1,1},{2,1},{3,1},{2,2}}, {{2,0},{2,1},{3,1},{2,2}}, {{2,0},{1,1},{2,1},{3,1}}, {{2,0},{1,1},{2,1},{2,2}} }
    };
    //---------------------------------------------------------------------------
    CPoint MakePoint(int x, int y)
    {
       CPoint p;
       p.x = x;
       p.y = y;
       return p;
    }
    //---------------------------------------------------------------------------
    
    TRotationStone::TRotationStone()
    {
       FStoneNumber = 0;
       FRotationIndex = 0;
       randomize();
    }
    //---------------------------------------------------------------------------
    
    TRotationStone::TRotationStone(int stone_number, int rotation_index)
    {
       if(stone_number < 7  &&  stone_number > -1)
          FStoneNumber = stone_number;
       else
          FStoneNumber = 0;
    
       if(rotation_index < 4  &&  rotation_index > -1)
          FRotationIndex = rotation_index;
       else
          FRotationIndex = 0;
    
       randomize();
    }
    //---------------------------------------------------------------------------
    
    void TRotationStone::SetStoneNumber(int stone_number)
    {
       if(stone_number < 7  &&  stone_number > -1)
          FStoneNumber = stone_number;
    }
    //---------------------------------------------------------------------------
    
    int TRotationStone::GetStoneNumber()
    {
       return FStoneNumber;
    }
    //---------------------------------------------------------------------------
    
    int TRotationStone::GetRotationIndex()
    {
       return FRotationIndex;
    }
    //---------------------------------------------------------------------------
    
    void TRotationStone::GetCoords(CPoint* p)
    {
       CPoint* stone_coords = (CPoint*)stones[FStoneNumber][FRotationIndex];
    
       for(int n=0; n<4; ++n)
       {
          p[n].x = stone_coords[n].x;
          p[n].y = stone_coords[n].y;
       }
    }
    //---------------------------------------------------------------------------
    
    void TRotationStone::RotateLeft()
    {
       FRotationIndex--;
       if(FRotationIndex < 0)
          FRotationIndex = 3;
    }
    //---------------------------------------------------------------------------
    
    void TRotationStone::RotateRight()
    {
       FRotationIndex++;
       if(FRotationIndex > 3)
          FRotationIndex = 0;
    }
    //---------------------------------------------------------------------------
    
    void TRotationStone::Random()
    {
       int r = random(19) + 1;  // We have 19 different kinds of stones
       int sn; // Ist die zugehörige Nummer in der Auflistung der Steine (siehe oben)
    
       if( r < 8 )
       {
          if( r == 1 )
             sn = 1;
          else
          {
             if(r % 2)
                sn = 2*r;
             else
                sn = 2*r + 1;
          }
       }
       else if( r >= 8 )
          sn = r + 9;
    
       FStoneNumber = (sn - 1) / 4;
       FRotationIndex = sn - (FStoneNumber * 4) - 1;
    }
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    
    /*===========================================================================
    
                                CLASS TTetris
    
    ===========================================================================*/
    
    TTetris::TTetris()
    {
        for(int i=0; i<10; ++i)
           for(int j=0; j<20; ++j)
              FPile[i][j] = 0;  // No stone anywhere
    
        FCurStone.Random();
        FNextStone.Random();
        FStonePos = GetNewStonePos(FCurStone);
        FScore = 0;
        FLevel = 0;
        FLines = 0;
        FStopped = true;
        FOnVisualUpdate = NULL;
        FOnNewNext = NULL;
        FOnGameOver = NULL;
        FOnDeleteLines = NULL;
        FOnTimerGo = NULL;
        FOnTimerStop = NULL;
    }
    //---------------------------------------------------------------------------
    
    void TTetris::Reset()
    {
        for(int i=0; i<10; ++i)
           for(int j=0; j<20; ++j)
              FPile[i][j] = 0;  // No stone anywhere
    
        FCurStone.Random();
        FNextStone.Random();
        FStonePos = GetNewStonePos(FCurStone);
        FScore = 0;
        FLevel = 0;
        FLines = 0;
    }
    //---------------------------------------------------------------------------
    
    TTetris::~TTetris()
    {
    
    }
    //---------------------------------------------------------------------------
    
    void TTetris::Start()
    {
       FStopped = false;
       if(FOnNewNext)
          FOnNewNext(0);
       if(FOnTimerGo)
          FOnTimerGo(0);
       if(FOnVisualUpdate)
          FOnVisualUpdate(1);
    }
    //---------------------------------------------------------------------------
    
    void TTetris::Pause()
    {
       if(FOnTimerStop)
       {
          FOnTimerStop(0);
          FStopped = true;
       }
    }
    //---------------------------------------------------------------------------
    
    void TTetris::DoNextStep()
    {
       static int del_lines[5] = {0,20,20,20,20};
       static int stat_level = 0;
    
       if( IsDownCollision() )
       {
          if(FStonePos.y <= 0)    // Game Over
          {
             if(FOnGameOver)
             {
                if(FOnTimerStop)
                {
                   FOnTimerStop(0);
                   FStopped = true;
                }
                FOnGameOver(0);
             }
             return;
          }
    
          AddStoneToPile(FCurStone, FStonePos);
          GetFullLines(del_lines);
    
          FCurStone = FNextStone;
          FStonePos = GetNewStonePos(FCurStone);
          FNextStone.Random();
    
          if( FOnVisualUpdate )
             FOnVisualUpdate(0); // Draw only pile
    
          if( del_lines[0] )
          {
             FLines += del_lines[0];
    
             ComputeNewScore( del_lines[0] );
    
             stat_level = FLevel;
             FLevel = FLines / 10;
             if(stat_level < FLevel) // Level Jump
             {
                if(FOnNewLevel)
                   FOnNewLevel(FLevel);
             }
    
             if(FOnDeleteLines)  // Blinking lines
             {
                if(FOnTimerStop)
                {
                   FOnTimerStop(0);
                   FStopped = true;
                }
                FOnDeleteLines(del_lines);
             }
    
             DeleteLines(del_lines);
    
             if(FStopped && FOnTimerGo)
             {
                FOnTimerGo(0);
                FStopped = false;
             }
          }
    
          if(FOnNewNext)
             FOnNewNext(0);
       }
       else  // no down-collision
       {
          FStonePos.y++;
       }
    
       if( FOnVisualUpdate )
          FOnVisualUpdate(1);
    }
    //---------------------------------------------------------------------------
    
    void TTetris::GetFullLines(int* out_lines)
    {
       int k = FStonePos.y;
       int min = (k+3 > 19) ? 19 : k+3;
       int m = 0;
    
       for(int j=k; j<=min; ++j)
       {
          if( IsLineFull(j) )
          {
             out_lines[m+1] = j;
             m++;
          }
       }
    
       out_lines[0] = m;
    }
    //---------------------------------------------------------------------------
    
    void TTetris::DeleteLines(int* in_lines)
    {
       /* in_lines is a 5-element array n|m1 m2 m3 m4 where n is the number of
          full lines and m1-m4 are the indices of the full lines */
       int n = in_lines[0];
       for(int m=0; m<n; ++m)
          DeleteLine(in_lines[m+1]);
    }
    //---------------------------------------------------------------------------
    
    void TTetris::DeleteLine(int j)
    {
       if( j==0 ) // Oberste Line
       {
          for(int i=0; i<10; ++i)
             FPile[i][j] = 0;
          return;
       }
    
       for(int k=j; k>0; --k)
       {
          for(int i=0; i<10; ++i)
          {
             FPile[i][k] = FPile[i][k-1];
             FPile[i][k-1] = 0;
          }
       }
    }
    //---------------------------------------------------------------------------
    
    void TTetris::InputRight()
    {
       if( !IsRightCollision() )
          FStonePos.x++;
    
       if( FOnVisualUpdate )
          FOnVisualUpdate(1);
    }
    //---------------------------------------------------------------------------
    
    void TTetris::InputLeft()
    {
       if( !IsLeftCollision() )
          FStonePos.x--;
    
       if( FOnVisualUpdate )
          FOnVisualUpdate(1);
    }
    //---------------------------------------------------------------------------
    
    void TTetris::InputDown()
    {
       if( !IsDownCollision() )
          FStonePos.y++;
    
       if( FOnVisualUpdate )
          FOnVisualUpdate(1);
    }
    //---------------------------------------------------------------------------
    
    void TTetris::InputRotate()
    {
       FCurStone.RotateRight();
       if( IsDirectCollision() )
          FCurStone.RotateLeft();
    
       if( FOnVisualUpdate )
          FOnVisualUpdate(1);
    }
    //---------------------------------------------------------------------------
    
    void TTetris::InputDrop()
    {
       while( !IsDownCollision() )
          FStonePos.y++;
       FScore += FLevel + 1;
       DoNextStep();
    }
    //---------------------------------------------------------------------------
    
    int TTetris::GetPileCoord(int i, int j)
    {
       return FPile[i][j];
    }
    //---------------------------------------------------------------------------
    
    void TTetris::GetCurStoneCoords(CPoint* pp)
    {
       CPoint* stone_coords = (CPoint*)stones[FCurStone.GetStoneNumber()][FCurStone.GetRotationIndex()];
    
       for(int n=0; n<4; ++n)
       {
          int i = stone_coords[n].x + FStonePos.x;
          int j = stone_coords[n].y + FStonePos.y;
          pp[n] = MakePoint(i,j);
       }
    }
    //---------------------------------------------------------------------------
    
    void TTetris::GetNextStoneCoords(CPoint* pp)
    {
       CPoint* stone_coords = (CPoint*)stones[FNextStone.GetStoneNumber()][FNextStone.GetRotationIndex()];
    
       for(int n=0; n<4; ++n)
       {
          pp[n] = stone_coords[n];
       }
    }
    //---------------------------------------------------------------------------
    
    int TTetris::GetCurStoneType()
    {
       return FCurStone.GetStoneNumber();
    }
    //---------------------------------------------------------------------------
    
    int TTetris::GetNextStoneType()
    {
       return FNextStone.GetStoneNumber();
    }
    //---------------------------------------------------------------------------
    
    int TTetris::GetDeletedLines()
    {
       return FLines;
    }
    //---------------------------------------------------------------------------
    
    int TTetris::GetLevel()
    {
       return FLevel;
    }
    //---------------------------------------------------------------------------
    
    int TTetris::GetScore()
    {
       return FScore;
    }
    //---------------------------------------------------------------------------
    
    void TTetris::SetOnVisualUpdateFunc(TCallbackFunc onVisualUpdate)
    {
       FOnVisualUpdate = onVisualUpdate;
    }
    //---------------------------------------------------------------------------
    
    void TTetris::SetOnNewNextFunc(TCallbackFunc onNewNext)
    {
       FOnNewNext = onNewNext;
    }
    //---------------------------------------------------------------------------
    
    void TTetris::SetOnGameOverFunc(TCallbackFunc onGameOver)
    {
       FOnGameOver = onGameOver;
    }
    //---------------------------------------------------------------------------
    
    void TTetris::SetOnTimerGoFunc(TCallbackFunc onTimerGo)
    {
       FOnTimerGo = onTimerGo;
    }
    //---------------------------------------------------------------------------
    
    void TTetris::SetOnTimerStopFunc(TCallbackFunc onTimerStop)
    {
       FOnTimerStop = onTimerStop;
    }
    //---------------------------------------------------------------------------
    
    void TTetris::SetOnNewLevelFunc(TCallbackFunc onNewLevel)
    {
       FOnNewLevel = onNewLevel;
    }
    //---------------------------------------------------------------------------
    
    void TTetris::SetOnDeleteLinesFunc(TDeleteLinesFunc onDeleteLines)
    {
       FOnDeleteLines = onDeleteLines;
    }
    //---------------------------------------------------------------------------
    
    bool TTetris::IsStopped()
    {
       return FStopped;
    }
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    
    /*===========================================================================
    
                            PRIVATE FUNCTIONS
    
    ===========================================================================*/
    
    bool TTetris::IsDownCollision()        // Returns true if one step down causes collision
    {
       bool collision;
    
       FStonePos.y++;
       collision = IsDirectCollision();
       FStonePos.y--;
    
       return collision;
    }
    //---------------------------------------------------------------------------
    
    bool TTetris::IsRightCollision()       // Returns true if one step right causes collision
    {
       bool collision;
    
       FStonePos.x++;
       collision = IsDirectCollision();
       FStonePos.x--;
    
       return collision;
    }
    //---------------------------------------------------------------------------
    
    bool TTetris::IsLeftCollision()        // Returns true if one step left causes collision
    {
       bool collision;
    
       FStonePos.x--;
       collision = IsDirectCollision();
       FStonePos.x++;
    
       return collision;
    }
    //---------------------------------------------------------------------------
    
    void TTetris::AddStoneToPile(TRotationStone stone, CPoint stone_pos)
    {
       CPoint* stone_coords = (CPoint*)stones[stone.GetStoneNumber()][stone.GetRotationIndex()];
    
       for(int n=0; n<4; ++n)
       {
          int i = stone_coords[n].x + stone_pos.x;
          int j = stone_coords[n].y + stone_pos.y;
          FPile[i][j] = stone.GetStoneNumber() + 1;
       }
    }
    //---------------------------------------------------------------------------
    
    bool TTetris::IsDirectCollision()      // Returns true if FCurStone collides with pile
    {
       CPoint* stone_coords = (CPoint*)stones[FCurStone.GetStoneNumber()][FCurStone.GetRotationIndex()];
    
       for(int n=0; n<4; ++n)
       {
          // See if n-th coord of stone collides with pile
          int i = stone_coords[n].x + FStonePos.x;
          int j = stone_coords[n].y + FStonePos.y;
    
          if( i > 9  ||  i < 0  ||  j > 19 )
             return true;
          if( j < 0 )
             return false;
          if( FPile[i][j] )
             return true;
       }
    
       return false;
    }
    //---------------------------------------------------------------------------
    
    CPoint TTetris::GetNewStonePos(TRotationStone stone)
    {
       CPoint p;
       CPoint* stone_coords = (CPoint*)stones[stone.GetStoneNumber()][stone.GetRotationIndex()];
    
       if( stone_coords[0].y == 0 )
          p = MakePoint(3,0);
       else
          p = MakePoint(3,-1);
    
       return p;
    }
    //---------------------------------------------------------------------------
    
    bool TTetris::IsLineFull(int j)
    {
       for(int i=0; i<10; ++i)
          if( !FPile[i][j] )
             return false;
    
       return true;
    }
    //---------------------------------------------------------------------------
    
    void TTetris::ComputeNewScore(int deleted_lines)
    {
       switch(deleted_lines)
       {
          case 1:
             FScore += 40 * (FLevel + 1);
             break;
    
          case 2:
             FScore += 100 * (FLevel + 1);
             break;
    
          case 3:
             FScore += 300 * (FLevel + 1);
             break;
    
          case 4:
             FScore += 1200 * (FLevel + 1);
             break;
       }
    }
    //---------------------------------------------------------------------------
    

Anmelden zum Antworten