diff --git a/CustomDevice/CustomDevice.csproj b/CustomDevice/CustomDevice.csproj new file mode 100644 index 0000000..5633e6a --- /dev/null +++ b/CustomDevice/CustomDevice.csproj @@ -0,0 +1,105 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {43619745-0A80-499E-907C-E733FF3DA2BE} + Library + Properties + CustomDevice + CustomDevice + + + + + 2.0 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + 512 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + 512 + + + + + + + + + + + + + + Form + + + + + False + .NET Framework Client Profile + false + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + False + .NET Framework 3.5 SP1 + false + + + + + + copy $(TargetPath) $(SolutionDir)\Builds\$(ConfigurationName)\ + + \ No newline at end of file diff --git a/CustomDevice/DeviceGraphics.cs b/CustomDevice/DeviceGraphics.cs new file mode 100644 index 0000000..829b93c --- /dev/null +++ b/CustomDevice/DeviceGraphics.cs @@ -0,0 +1,88 @@ +// Copyright (c) 2009 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Threading; + +namespace CustomDevice { + + public static class DeviceGraphics { + + private const int ScreenX = 320; + private const int ScreenY = 240; + + private static int whichScreen = 0; + + public static int ScreenXSize { + get { + return ScreenX; + } + } + + public static int ScreenYSize { + get { + return ScreenY; + } + } + + public static Graphics GetScreen() { + if (whichScreen == 0) { + if (Utils.IsInterNet2) { + whichScreen = 1; + } else { + whichScreen = 2; + } + } + if (whichScreen == 1) { + return GetScreen_InterNet2(); + } else { + return GetScreen_Windows(); + } + } + + private static Graphics GetScreen_InterNet2() { + // In the InterNet2 System.Drawing dll Graphics.FromHdc() will always + // return the Graphics object for the screen. + return Graphics.FromHdc(IntPtr.Zero); + } + + private static Graphics GetScreen_Windows() { + + if (WindowsScreen.winScreen == null) { + Thread t = new Thread(WindowsScreen.WindowsMessagePump); + t.IsBackground = true; + t.Start(); + while (WindowsScreen.winScreen == null) { + Thread.Sleep(2); + } + } + + lock (WindowsScreen.winScreen) { + Graphics g = Graphics.FromImage(WindowsScreen.winScreen.FormSurface); + return g; + } + } + + } + +} diff --git a/CustomDevice/KeyPad.cs b/CustomDevice/KeyPad.cs new file mode 100644 index 0000000..13c22a3 --- /dev/null +++ b/CustomDevice/KeyPad.cs @@ -0,0 +1,102 @@ +// Copyright (c) 2009 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Drawing; +using System.Threading; + +namespace CustomDevice { + public static class KeyPad { + + [DllImport("libIGraph")] + extern private static bool IsKeyDown_Internal(KeyPadKey key); + + [DllImport("libIGraph")] + extern private static int LatestKeyUp_Internal(); + + [DllImport("libIGraph")] + extern private static int LatestKeyDown_Internal(); + + public static bool IsKeyDown(KeyPadKey key) { + if (Utils.IsInterNet2) { + return IsKeyDown_Internal(key); + } else { + return WindowsScreen.WinScreen.IsKeyDown(key); + } + } + + private static bool WindowsLatestKeyUp(out KeyPadKey key) { + return WindowsScreen.WinScreen.LatestKeyUp(out key); + } + + private static bool WindowsLatestKeyDown(out KeyPadKey key) { + return WindowsScreen.WinScreen.LatestKeyDown(out key); + } + + public static bool LatestKeyUp(out KeyPadKey key) { + if (Utils.IsInterNet2) { + int iKey = LatestKeyUp_Internal(); + if (iKey >= 0) { + key = (KeyPadKey)iKey; + return true; + } else { + key = KeyPadKey.B0; + return false; + } + } else { + return WindowsLatestKeyUp(out key); + } + } + + public static bool LatestKeyDown(out KeyPadKey key) { + if (Utils.IsInterNet2) { + int iKey = LatestKeyDown_Internal(); + if (iKey >= 0) { + key = (KeyPadKey)iKey; + return true; + } else { + key = KeyPadKey.B0; + return false; + } + } else { + return WindowsLatestKeyDown(out key); + } + } + + public static KeyPadKey? ReadKey(int timeoutMs) { + DateTime end = DateTime.UtcNow.AddMilliseconds(timeoutMs); + do { + KeyPadKey key; + if (LatestKeyDown(out key)) { + return key; + } + Thread.Sleep(1); + } while (DateTime.UtcNow < end && timeoutMs >= 0); + return null; + } + + public static KeyPadKey? ReadKey() { + return ReadKey(-1); + } + } +} diff --git a/CustomDevice/KeyPadKey.cs b/CustomDevice/KeyPadKey.cs new file mode 100644 index 0000000..aa5b5a7 --- /dev/null +++ b/CustomDevice/KeyPadKey.cs @@ -0,0 +1,42 @@ +// Copyright (c) 2009 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace CustomDevice { + public enum KeyPadKey { + + B0 = 0, + B1 = 1, + B2 = 2, + B3 = 3, + B4 = 4, + B5 = 5, + B6 = 6, + B7 = 7, + B8 = 8, + B9 = 9, + C = 10, + OK = 11 + + } +} diff --git a/CustomDevice/Properties/AssemblyInfo.cs b/CustomDevice/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..cef3e29 --- /dev/null +++ b/CustomDevice/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DeviceGraphics")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Docobo")] +[assembly: AssemblyProduct("DeviceGraphics")] +[assembly: AssemblyCopyright("Copyright © Docobo 2007")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a7a488bb-a22b-4377-ab45-d2139150ff7d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CustomDevice/Utils.cs b/CustomDevice/Utils.cs new file mode 100644 index 0000000..2f91131 --- /dev/null +++ b/CustomDevice/Utils.cs @@ -0,0 +1,40 @@ +// Copyright (c) 2009 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace CustomDevice { + static class Utils { + + private static bool isInterNet2, isInterNet2Set = false; + public static bool IsInterNet2 { + get { + if (!isInterNet2Set) { + isInterNet2 = Environment.OSVersion.VersionString.EndsWith("(InterNet2)"); + isInterNet2Set = true; + } + return isInterNet2; + } + } + + } +} diff --git a/CustomDevice/WindowsScreen.cs b/CustomDevice/WindowsScreen.cs new file mode 100644 index 0000000..c3f01ff --- /dev/null +++ b/CustomDevice/WindowsScreen.cs @@ -0,0 +1,181 @@ +// Copyright (c) 2009 DotNetAnywhere +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.Threading; +using System.IO; +using System.Runtime.InteropServices; + +namespace CustomDevice { + class WindowsScreen : Form { + + internal static WindowsScreen winScreen = null; + + public static WindowsScreen WinScreen { + get { + if (winScreen == null) { + using (Graphics g = DeviceGraphics.GetScreen()) { + } + } + return winScreen; + } + } + + public WindowsScreen(int width, int height) { + this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); + this.SetStyle(ControlStyles.FixedWidth, true); + this.SetStyle(ControlStyles.FixedHeight, true); + this.SetStyle(ControlStyles.Opaque, true); + this.SetStyle(ControlStyles.UserPaint, true); + + this.formSurface = new Bitmap(width, height); + + this.ClientSize = new Size(width, height); + + this.Show(); + this.Activate(); + + } + + private Bitmap formSurface; + + public Bitmap FormSurface { + get { + return this.formSurface; + } + } + + protected override void OnPaint(PaintEventArgs e) { + lock (this) { + e.Graphics.DrawImageUnscaled(this.formSurface, new Point()); + } + } + + internal static void WindowsMessagePump(object state) { + WindowsScreen.winScreen = new WindowsScreen(DeviceGraphics.ScreenXSize, DeviceGraphics.ScreenYSize); + for (; ; ) { + Application.DoEvents(); + Thread.Sleep(40); + WindowsScreen.winScreen.Refresh(); + } + } + + private bool[] keyState = new bool[12]; + + private KeyPadKey MapKey(Keys pcKey, out bool isValid) { + isValid = true; + switch (pcKey) { + case Keys.D0: + case Keys.NumPad0: + return KeyPadKey.B0; + case Keys.D1: + case Keys.NumPad1: + return KeyPadKey.B1; + case Keys.D2: + case Keys.NumPad2: + return KeyPadKey.B2; + case Keys.D3: + case Keys.NumPad3: + return KeyPadKey.B3; + case Keys.D4: + case Keys.NumPad4: + return KeyPadKey.B4; + case Keys.D5: + case Keys.NumPad5: + return KeyPadKey.B5; + case Keys.D6: + case Keys.NumPad6: + return KeyPadKey.B6; + case Keys.D7: + case Keys.NumPad7: + return KeyPadKey.B7; + case Keys.D8: + case Keys.NumPad8: + return KeyPadKey.B8; + case Keys.D9: + case Keys.NumPad9: + return KeyPadKey.B9; + case Keys.Enter: + return KeyPadKey.OK; + case Keys.Escape: + return KeyPadKey.C; + default: + isValid = false; + return KeyPadKey.B0; + } + } + + protected override void OnKeyDown(KeyEventArgs e) { + bool isValid; + KeyPadKey key = this.MapKey(e.KeyCode, out isValid); + if (isValid) { + e.Handled = true; + this.keyState[(int)key] = true; + this.latestKeyDown = key; + return; + } + base.OnKeyDown(e); + } + + protected override void OnKeyUp(KeyEventArgs e) { + bool isValid; + KeyPadKey key = this.MapKey(e.KeyCode, out isValid); + if (isValid) { + e.Handled = true; + this.keyState[(int)key] = false; + this.latestKeyUp = key; + return; + } + base.OnKeyUp(e); + } + + public bool IsKeyDown(KeyPadKey key) { + return this.keyState[(int)key]; + } + + private KeyPadKey? latestKeyUp = null; + public bool LatestKeyUp(out KeyPadKey key) { + if (this.latestKeyUp.HasValue) { + key = this.latestKeyUp.Value; + this.latestKeyUp = null; + return true; + } else { + key = KeyPadKey.B0; + return false; + } + } + + private KeyPadKey? latestKeyDown = null; + public bool LatestKeyDown(out KeyPadKey key) { + if (this.latestKeyDown.HasValue) { + key = this.latestKeyDown.Value; + this.latestKeyDown = null; + return true; + } else { + key = KeyPadKey.B0; + return false; + } + } + } +} diff --git a/Snake/ASnake.cs b/Snake/ASnake.cs new file mode 100644 index 0000000..a0d32fa --- /dev/null +++ b/Snake/ASnake.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace Snake { + class ASnake { + + private SnakePit snakePit; + private Queue bodyParts = new Queue(); + private Point head; + private int xSpeed, ySpeed; + private Color col; + private int increaseBy; + + public ASnake(SnakePit snakePit, int startLength, Point startPosition, Color col) { + this.snakePit = snakePit; + for (int i = 0; i < startLength; i++) { + Point cell = new Point(startPosition.X - startLength + i + 1, startPosition.Y); + snakePit.SetCell(cell, col); + this.bodyParts.Enqueue(cell); + this.head = cell; + } + this.col = col; + this.xSpeed = 1; + this.ySpeed = 0; + this.increaseBy = 0; + snakePit.AddSnake(this); + } + + public CrashType Move() { + if (this.increaseBy == 0) { + Point tail = this.bodyParts.Dequeue(); + snakePit.ClearCell(tail); + } else { + this.increaseBy--; + } + this.head.X += this.xSpeed; + this.head.Y += this.ySpeed; + if (this.DoesIntersect(this.head)) { + Console.WriteLine("!!!SELF CRASH!!!"); + return CrashType.Self; + } + this.bodyParts.Enqueue(this.head); + snakePit.SetCell(this.head, this.col); + CrashType crash = this.snakePit.IsCrash(head); + return crash; + } + + public void DrawHead() { + snakePit.SetCell(this.head, this.col); + } + + public void SetDirection(int x, int y) { + // Do nothing if trying to set current or opposite direction + if (x != 0 && this.xSpeed != 0) { + return; + } + if (y != 0 && this.ySpeed != 0) { + return; + } + // Set new speeds + this.xSpeed = x; + this.ySpeed = y; + } + + public bool DoesIntersect(IEnumerable cells) { + foreach (Point cell in cells) { + if (this.DoesIntersect(cell)) { + return true; + } + } + return false; + } + + public bool DoesIntersect(Point cell) { + foreach (Point p in this.bodyParts) { + if (p == cell) { + return true; + } + } + return false; + } + + public void IncreaseLength(int amount) { + this.increaseBy += amount; + } + + public Point Head { + get { + return this.head; + } + } + + } +} diff --git a/Snake/CrashType.cs b/Snake/CrashType.cs new file mode 100644 index 0000000..881f514 --- /dev/null +++ b/Snake/CrashType.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Snake { + public enum CrashType { + None, + Self, + Wall, + Food, + } +} diff --git a/Snake/Program.cs b/Snake/Program.cs new file mode 100644 index 0000000..73fdce1 --- /dev/null +++ b/Snake/Program.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Threading; +using CustomDevice; + +namespace Snake { + class Program { + static void Main(string[] args) { + for (; ; ) { + bool res = Play(); + if (!res) { + break; + } + } + } + + static bool Play() { + + Font f = new Font("tahoma", 25); + SnakePit snakePit = new SnakePit(); + Random rnd = new Random(); + int delay = 300; + + ASnake snake = new ASnake(snakePit, 5, snakePit.Centre, Color.Black); + + CrashType crashType; + for (; ; ) { + Thread.Sleep(delay); + KeyPadKey key; + if (KeyPad.LatestKeyDown(out key)) { + switch (key) { + case KeyPadKey.B6: // Left + snake.SetDirection(-1, 0); + break; + case KeyPadKey.B7: // Down + snake.SetDirection(0, 1); + break; + case KeyPadKey.B8: // Up + snake.SetDirection(0, -1); + break; + case KeyPadKey.B9: // Right + snake.SetDirection(1, 0); + break; + case KeyPadKey.C: + return false; + } + } + crashType = snake.Move(); + bool finish = false; + switch (crashType) { + case CrashType.None: + break; + case CrashType.Self: + case CrashType.Wall: + default: + finish = true; + break; + case CrashType.Food: + bool levelUp = snakePit.EatFood(); + if (levelUp) { + delay = (delay * 3) / 4; + } + snake.IncreaseLength(4); + break; + + } + snake.DrawHead(); + if (finish) { + break; + } + + int r = rnd.Next(1000); + if (r < 50) { + snakePit.CreateFood(r < 5); + } + r = rnd.Next(1000); + if (r < 20) { + snakePit.AddObsticle(); + } + } + snakePit.Msg(crashType.ToString()); + Thread.Sleep(5000); + + return true; + } + } +} diff --git a/Snake/Properties/AssemblyInfo.cs b/Snake/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5e7832f --- /dev/null +++ b/Snake/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Snake")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Docobo")] +[assembly: AssemblyProduct("Snake")] +[assembly: AssemblyCopyright("Copyright © Docobo 2007")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a65d79de-9fdb-4e50-aa31-5aff8c5f8744")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Snake/Snake.csproj b/Snake/Snake.csproj new file mode 100644 index 0000000..473c4d1 --- /dev/null +++ b/Snake/Snake.csproj @@ -0,0 +1,108 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {C26A3309-7A61-40B6-9998-69B78CF226C1} + Exe + Properties + Snake + Snake + + + + + 2.0 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + 512 + + + + + + + + + + + + + + + + + {43619745-0A80-499E-907C-E733FF3DA2BE} + CustomDevice + + + + + False + .NET Framework Client Profile + false + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + False + .NET Framework 3.5 SP1 + false + + + + + + copy $(TargetPath) $(SolutionDir)\Builds\$(ConfigurationName)\ + + \ No newline at end of file diff --git a/Snake/SnakePit.cs b/Snake/SnakePit.cs new file mode 100644 index 0000000..b643c3c --- /dev/null +++ b/Snake/SnakePit.cs @@ -0,0 +1,266 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using CustomDevice; +using System.Drawing.Drawing2D; + +namespace Snake { + class SnakePit { + + private const int cellSize = 8; + private const int scoreBoardHeight = 48; + + private Graphics screen; + private int cellOfsX, cellOfsY; + private int numCellsX, numCellsY; + private Random rnd; + private Point[] food; + private List snakes = new List(); + private int score, level; + private List obstacles = new List(); + + public SnakePit() { + this.screen = DeviceGraphics.GetScreen(); + this.screen.Clear(Color.White); + this.numCellsX = (DeviceGraphics.ScreenXSize / cellSize) - 2; + this.numCellsY = ((DeviceGraphics.ScreenYSize - scoreBoardHeight) / cellSize) - 2; + this.cellOfsX = cellSize; + this.cellOfsY = cellSize; + this.rnd = new Random(); + this.food = null; + this.score = 0; + this.level = 1; + + using (Brush brush = new HatchBrush(HatchStyle.DiagonalCross, Color.Black, Color.White)) { + this.screen.FillRectangle(brush, 0, 0, DeviceGraphics.ScreenXSize, cellSize); + this.screen.FillRectangle(brush, 0, cellSize, cellSize, this.numCellsY * cellSize); + this.screen.FillRectangle(brush, (1 + this.numCellsX) * cellSize, cellSize, cellSize, this.numCellsY * cellSize); + this.screen.FillRectangle(brush, 0, (1 + this.numCellsY) * cellSize, DeviceGraphics.ScreenXSize, cellSize); + } + this.screen.DrawRectangle(Pens.Black, cellSize - 1, cellSize - 1, + this.numCellsX * cellSize + 1, this.numCellsY * cellSize + 1); + + using (Font f = new Font("tahoma", 15)) { + using (StringFormat sf = new StringFormat()) { + sf.Alignment = StringAlignment.Center; + sf.LineAlignment = StringAlignment.Center; + this.screen.DrawString("<", f, Brushes.Black, new RectangleF(0, 220, 64, 20), sf); + this.screen.DrawString("v", f, Brushes.Black, new RectangleF(64, 220, 64, 20), sf); + this.screen.DrawString("^", f, Brushes.Black, new RectangleF(128, 220, 64, 20), sf); + this.screen.DrawString(">", f, Brushes.Black, new RectangleF(192, 220, 64, 20), sf); + } + } + + this.ShowScore(); + } + + private void FillCell(Point cell, Color col) { + using (Brush brush = new SolidBrush(col)) { + screen.FillRectangle(brush, + this.cellOfsX + cell.X * cellSize, this.cellOfsY + cell.Y * cellSize, cellSize, cellSize); + } + } + + public void FillAndOutlineCells(IEnumerable points, Color fillCol, Color outlineCol) { + using (Brush brush = new SolidBrush(fillCol)) { + this.FillAndOutlineCells(points, brush, outlineCol); + } + } + + public void FillAndOutlineCells(IEnumerable points, Brush fillBrush, Color outlineCol) { + int minX = int.MaxValue, maxX = int.MinValue; + int minY = int.MaxValue, maxY = int.MinValue; + foreach (Point p in points) { + minX = Math.Min(minX, p.X); + maxX = Math.Max(maxX, p.X); + minY = Math.Min(minY, p.Y); + maxY = Math.Max(maxY, p.Y); + } + int x = this.cellOfsX + minX * cellSize; + int y = this.cellOfsY + minY * cellSize; + int width = (maxX - minX + 1) * cellSize; + int height = (maxY - minY + 1) * cellSize; + this.screen.FillRectangle(fillBrush, x, y, width, height); + using (Pen pen = new Pen(outlineCol)) { + this.screen.DrawRectangle(pen, x, y, width - 1, height - 1); + } + } + + public void AddSnake(ASnake snake) { + this.snakes.Add(snake); + } + + public Point Centre { + get { + return new Point(numCellsX >> 1, numCellsY >> 1); + } + } + + public Size Size { + get { + return new Size(numCellsX, numCellsY); + } + } + + public void SetCell(Point cell, Color col) { + this.FillCell(cell, col); + } + + public void ClearCell(Point cell) { + this.FillCell(cell, Color.White); + } + + public bool IsCrashObstacle(Point cell) { + foreach (Point[] obs in this.obstacles) { + foreach (Point pt in obs) { + if (pt == cell) { + return true; + } + } + } + return false; + } + + public CrashType IsCrash(Point cell) { + if (cell.X < 0 || cell.X >= this.numCellsX || cell.Y < 0 || cell.Y >= this.numCellsY) { + return CrashType.Wall; + } + if (this.IsCrashObstacle(cell)) { + return CrashType.Wall; + } + if (this.food != null) { + for (int i = 0; i < this.food.Length; i++) { + if (this.food[i] == cell) { + return CrashType.Food; + } + } + } + return CrashType.None; + } + + public void CreateFood(bool canMoveFood) { + if (this.food != null && !canMoveFood) { + // Don't move the food + return; + } + this.RemoveFood(); + Point[] newFood; + for (; ; ) { + int x = this.rnd.Next(this.numCellsX - 1); + int y = this.rnd.Next(this.numCellsY - 1); + newFood = new Point[4]; + newFood[0] = new Point(x, y); + newFood[1] = new Point(x + 1, y); + newFood[2] = new Point(x, y + 1); + newFood[3] = new Point(x + 1, y + 1); + bool ok = true; + foreach (ASnake snake in this.snakes) { + if (snake.DoesIntersect(newFood)) { + ok = false; + break; + } + } + if (ok) { + foreach (Point pt in newFood) { + if (IsCrashObstacle(pt)) { + ok = false; + break; + } + } + } + if (ok) { + break; + } + } + this.food = newFood; + this.FillAndOutlineCells(this.food, Color.Gray, Color.Black); + } + + public void RemoveFood() { + if (this.food == null) { + return; + } + for (int i = 0; i < this.food.Length; i++) { + this.ClearCell(this.food[i]); + } + this.food = null; + } + + public bool EatFood() { + this.RemoveFood(); + this.score++; + bool ret = false; + if (this.score >= this.level * 4) { + this.level++; + ret = true; + } + this.ShowScore(); + return ret; + } + + public void Msg(string msg) { + using (Font f = new Font("tahoma", 40)) { + this.screen.DrawString(msg, f, Brushes.Black, 30, 80); + } + } + + public void ShowScore() { + this.screen.FillRectangle(Brushes.White, 0, + DeviceGraphics.ScreenYSize - scoreBoardHeight, DeviceGraphics.ScreenXSize, scoreBoardHeight - 20); + using (Font f = new Font("tahoma", 15)) { + string s = string.Format("Level: {0}", this.level); + this.screen.DrawString(s, f, Brushes.Black, 0, DeviceGraphics.ScreenYSize - scoreBoardHeight); + s = string.Format("Score: {0}", this.score); + this.screen.DrawString(s, f, Brushes.Black, DeviceGraphics.ScreenXSize >> 1, DeviceGraphics.ScreenYSize - scoreBoardHeight); + } + } + + public int Level { + get { + return this.level; + } + } + + private int Dist(Point a, Point b) { + int dx = a.X - b.Y; + int dy = a.Y - b.Y; + return Math.Max(Math.Abs(dx), Math.Abs(dy)); + } + + public void AddObsticle() { + Point[] obs; + for (; ; ) { + int x = this.rnd.Next(this.numCellsX - 1); + int y = this.rnd.Next(this.numCellsY - 1); + obs = new Point[4]; + obs[0] = new Point(x, y); + obs[1] = new Point(x + 1, y); + obs[2] = new Point(x, y + 1); + obs[3] = new Point(x + 1, y + 1); + bool ok = true; + foreach (ASnake snake in this.snakes) { + if (snake.DoesIntersect(obs) || this.Dist(snake.Head, obs[0]) < 10) { + ok = false; + break; + } + } + if (ok) { + break; + } + } + using (HatchBrush brush = new HatchBrush(HatchStyle.DiagonalCross,Color.Black, Color.White)) { + this.FillAndOutlineCells(obs, brush, Color.Black); + } + this.obstacles.Add(obs); + if (this.obstacles.Count > this.Level * 2) { + // Remove an obstacle + obs = this.obstacles[0]; + foreach (Point pt in obs) { + this.ClearCell(pt); + } + this.obstacles.RemoveAt(0); + } + } + } +}