diff -r 000000000000 -r 7f656887cf89 commands/snake/snake.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commands/snake/snake.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,473 @@ +// snake.cpp +// +// Copyright (c) 2009 - 2010 Accenture. All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Accenture - Initial contribution +// + +#include +#include + +using namespace IoUtils; + +_LIT(KSnakeSeg, "*"); +_LIT(KBait, "$"); + +class CKeyWatcher; + +class CCmdSnake : public CCommandBase + { +public: + static CCommandBase* NewLC(); + ~CCmdSnake(); + + void Up(); + void Down(); + void Left(); + void Right(); + void Exit(); + void OnTimer(); +private: + CCmdSnake(); +private: // From CCommandBase. + virtual const TDesC& Name() const; + virtual void DoRunL(); + virtual void ArgumentsL(RCommandArgumentList& aArguments); + virtual void OptionsL(RCommandOptionList& aOptions); + + void ConstructL(); + void InitBoardL(); + void SetBoard(TInt aX, TInt aY, TBool aSet); + TBool GetBoard(TInt aX, TInt aY); + void DrawBoardL(); + void InitSnakeL(TInt aLen, TPoint aPos); + void DrawSnakeL(); + void DrawScore(); + void PlaceBait(); + void Grow(); + + void Dead(); +private: + RIoConsoleWriteHandle iCons; + RIoConsoleReadHandle iConsIn; + TSize iBoardSize; + RArray iSnake; + TInt iSnakeHead; + RArray iBoard; + TInt iBoardWidthWords; + TPoint iDirection; + TPoint iBait; + TInt iScore; + TInt iSpeed; + + CKeyWatcher* iKeys; + CPeriodic* iTimer; + TInt64 iRandomSeed; + TBool iInCollisionGracePeriod; + }; + +class CKeyWatcher : public CActive + { +public: + CKeyWatcher(CCmdSnake& aOwner, RIoConsoleReadHandle& aCons); + ~CKeyWatcher(); + void Request(); + +private: + virtual void RunL(); + virtual void DoCancel(); +private: + CCmdSnake& iOwner; + RIoConsoleReadHandle& iCons; + }; + + +CCommandBase* CCmdSnake::NewLC() + { + CCmdSnake* self = new(ELeave) CCmdSnake(); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +CCmdSnake::~CCmdSnake() + { + delete iKeys; + delete iTimer; + iSnake.Close(); + iBoard.Close(); + } + +CCmdSnake::CCmdSnake() + : CCommandBase(EManualComplete), iSpeed(50000) + { + } + +const TDesC& CCmdSnake::Name() const + { + _LIT(KName, "snake"); + return KName; + } + +TInt OnTimerS(TAny* aSnake) + { + ((CCmdSnake*)aSnake)->OnTimer(); + return KErrNone; + } + +void CCmdSnake::DoRunL() + { + if (!Stdout().AttachedToConsole()) + { + LeaveIfErr(KErrNotSupported, _L("Stdout must be connected to a console")); + } + iCons = Stdout(); + if (!Stdin().AttachedToConsole()) + { + LeaveIfErr(KErrNotSupported, _L("Stdin must be connected to a console")); + } + iConsIn = Stdin(); + iKeys = new(ELeave)CKeyWatcher(*this, iConsIn); + iCons.SetCursorHeight(0); + + User::LeaveIfError(iCons.GetScreenSize(iBoardSize)); + iBoardSize.iHeight--; // space for status bar, plus to ensure that the console doesn't scroll when we draw the bottom line + iBoardWidthWords = iBoardSize.iWidth / 32; + if (iBoardSize.iWidth % 32) ++iBoardWidthWords; + InitBoardL(); + + DrawBoardL(); + + TPoint centre; + centre.iX = iBoardSize.iWidth / 2; + centre.iY = iBoardSize.iHeight / 2; + InitSnakeL(10, centre); + DrawSnakeL(); + PlaceBait(); + DrawScore(); + + iTimer = CPeriodic::NewL(CActive::EPriorityStandard); + iTimer->Start(iSpeed, iSpeed, TCallBack(OnTimerS, this)); + } + +void CCmdSnake::ArgumentsL(RCommandArgumentList& /*aArguments*/) + { + } + +void CCmdSnake::OptionsL(RCommandOptionList& aOptions) + { + _LIT(KOptSpeed, "speed"); + aOptions.AppendIntL(iSpeed, KOptSpeed); + } + +void CCmdSnake::ConstructL() + { + BaseConstructL(); + TTime now; + now.HomeTime(); + iRandomSeed = now.Int64(); + } + +void CCmdSnake::InitBoardL() + { + // first, zero the whole board + iBoard.Reset(); + for (TInt y=0; y buf; + buf.AppendFormat(KQuitFmt, iScore); + iCons.Write(buf); + Complete(iScore); + } + +_LIT(KDeadFmt, "Game over; score: %d\n"); + +void CCmdSnake::Dead() + { + iKeys->Cancel(); + iCons.SetCursorPosAbs(TPoint(0, iBoardSize.iHeight)); + iCons.SetCursorHeight(20); + TBuf<0x20> buf; + buf.AppendFormat(KDeadFmt, iScore); + iCons.Write(buf); + Complete(iScore); + } + +void CCmdSnake::OnTimer() + { + iKeys->Request(); + if (!(iDirection.iX || iDirection.iY)) return; + TPoint newHead = iSnake[iSnakeHead] + iDirection + iBoardSize; + newHead.iX %= iBoardSize.iWidth; + newHead.iY %= iBoardSize.iHeight; + + // check for obstacles + if (GetBoard(newHead.iX, newHead.iY)) + { + if (iInCollisionGracePeriod) + { + Dead(); + } + else + { + iInCollisionGracePeriod = ETrue; + } + return; + } + iInCollisionGracePeriod = EFalse; + for (TInt i=0; i score; + score.AppendFormat(KScoreFormat, iScore); + iCons.Write(score); + } + +void CCmdSnake::PlaceBait() + { + TBool ok; + do + { + ok = ETrue; + iBait.iX = Math::Rand(iRandomSeed) % iBoardSize.iWidth; + iBait.iY = Math::Rand(iRandomSeed) % iBoardSize.iHeight; + + if (GetBoard(iBait.iX, iBait.iY)) ok = EFalse; + if (ok) + { + for (TInt i=0; i