Skip to content

Instantly share code, notes, and snippets.

@JerryNixon
Created January 8, 2020 13:53
Show Gist options
  • Select an option

  • Save JerryNixon/f3e101c5de50b2069867e83060156db4 to your computer and use it in GitHub Desktop.

Select an option

Save JerryNixon/f3e101c5de50b2069867e83060156db4 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
namespace SnakePrep
{
internal class Program
{
private static Game _game;
private static int _iteration = 0;
private static Direction _direction;
private static void Main(string[] args)
{
_game = new Game();
Start();
}
private static void Start()
{
Setup();
while (_game.GameOver == false)
{
Input();
Logic();
Draw();
System.Threading.Thread.Sleep(100);
}
_game.Input.WaitForSpacebar();
Start();
}
public static void Setup()
{
_game.Reset();
_game.Border.Draw();
}
public static void Input()
{
_direction = _game.Input.Read();
}
public static void Draw()
{
_game.Ship.Draw();
_game.Fruit.Draw();
_game.Tail.Draw();
_game.Score.Draw(_game.GameOver);
if (_game.GameOver)
{
Game.Draw(" ", _game.Ship.Previous, ConsoleColor.Black, ConsoleColor.Black);
Game.Draw("!", _game.Ship.Current, ConsoleColor.Red, ConsoleColor.Red);
}
}
public static void Logic()
{
_game.Ship.Move(_direction);
if (_game.Tail.IntersectsWith(_game.Ship.Previous))
{
_game.GameOver = true;
}
else if (_game.Ship.Current == _game.Fruit.Location)
{
IncreaseScore();
}
else if (_game.Input.Current != Direction.Stop)
{
_game.Tail.Move(_game.Ship.Current, false);
}
ReduceFruit();
void IncreaseScore()
{
_game.Score.Add(_game.Fruit.Value);
_game.Fruit.Move(_game.Ship.Previous, 9);
_game.Tail.Move(_game.Ship.Current, true);
}
void ReduceFruit()
{
if (_game.Fruit.Value > 0
&& _game.Input.Current != Direction.Stop
&& ++_iteration % 10 == 0)
{
_game.Fruit.Value--;
}
}
}
}
public enum Direction { Up, Down, Left, Right, Stop }
public class Game
{
public static Size GameSize;
public bool GameOver;
public Game(Size? size = null)
{
GameSize = size ?? new Size(40, 20);
Reset();
}
public void Reset()
{
Console.CursorVisible = false;
Console.Clear();
GameOver = false;
Input.Reset();
Score.Reset();
Ship.Reset();
Tail.Reset();
Fruit.Move(Ship.Previous);
}
public ScoreLogic Score = new ScoreLogic();
public BorderLogic Border = new BorderLogic();
public InputLogic Input = new InputLogic();
public ShipLogic Ship = new ShipLogic();
public FruitLogic Fruit = new FruitLogic();
public TailLogic Tail = new TailLogic();
public static void Draw(string text, Point location, ConsoleColor foreground, ConsoleColor background)
{
Draw(text, location.X, location.Y, foreground, background);
}
public static void Draw(string text, int x, int y, ConsoleColor foreground, ConsoleColor background)
{
Console.ForegroundColor = foreground;
Console.BackgroundColor = background;
Console.SetCursorPosition(x, y);
Console.Write(text);
Console.ResetColor();
}
}
public class TailLogic
{
public readonly List<Point> Points = new List<Point>();
public readonly List<Point> Previous = new List<Point>();
public void Move(Point point, bool grow)
{
Points.Add(point);
if (!grow)
{
Previous.Add(Points.First());
Points.Remove(Points.First());
}
}
public void Draw()
{
ErasePrevious();
DrawCurrent();
}
public void DrawCurrent(char text = '+', ConsoleColor foreground = ConsoleColor.Gray, ConsoleColor background = ConsoleColor.Black)
{
foreach (var point in Points)
{
Game.Draw(text.ToString(), point, foreground, background);
}
}
public void ErasePrevious(ConsoleColor foreground = ConsoleColor.Black, ConsoleColor background = ConsoleColor.Black)
{
foreach (var point in Previous.ToArray())
{
Previous.Remove(point);
Game.Draw(" ", point, foreground, background);
}
}
public bool IntersectsWith(Point point)
{
return Points.Contains(point);
}
public void Reset()
{
Points.Clear();
Previous.Clear();
}
}
public class ScoreLogic
{
public int Value;
public int Count;
public Stopwatch Timer = new Stopwatch();
public void Reset()
{
Value = 0;
Count = 0;
Timer.Restart();
}
public void Add(int value)
{
Value += value;
Count++;
}
public void Draw(bool gameOver, ConsoleColor foreground = ConsoleColor.White, ConsoleColor background = ConsoleColor.Black)
{
var value = $"Score: {Value} Length: {Count} Seconds: {Timer.Elapsed.TotalSeconds.ToString("#,###")}";
Game.Draw(value.PadLeft(10), 3, Game.GameSize.Height + 1, foreground, background);
if (gameOver)
{
Game.Draw("Game Over", 3, Game.GameSize.Height + 2, ConsoleColor.White, ConsoleColor.Red);
}
}
}
public class BorderLogic
{
public void Draw(char text = '+', ConsoleColor foreground = ConsoleColor.White, ConsoleColor background = ConsoleColor.Black)
{
var line = new string(text, Game.GameSize.Width);
Game.Draw(line, 0, 0, foreground, background);
Game.Draw(line, 0, Game.GameSize.Height - 1, foreground, background);
line = $"{text}{new string(' ', Game.GameSize.Width - 2)}{text}";
for (var i = 1; i < Game.GameSize.Height - 1; i++)
{
Game.Draw(line, 0, i, foreground, background);
}
}
public static bool Intersects(Point point)
{
return (point.X <= 0
|| point.Y <= 0
|| point.X >= Game.GameSize.Width - 1
|| point.Y >= Game.GameSize.Height - 1);
}
}
public class InputLogic
{
public Direction Current = Direction.Stop;
public void Reset()
{
Current = Direction.Stop;
}
public Direction Read()
{
if (Console.KeyAvailable)
{
var key = Console.ReadKey(true).Key;
if (key == ConsoleKey.UpArrow && Current != Direction.Down)
{
return Current = Direction.Up;
}
else if (key == ConsoleKey.DownArrow && Current != Direction.Up)
{
return Current = Direction.Down;
}
else if (key == ConsoleKey.LeftArrow && Current != Direction.Right)
{
return Current = Direction.Left;
}
else if (key == ConsoleKey.RightArrow && Current != Direction.Left)
{
return Current = Direction.Right;
}
else if (key == ConsoleKey.Escape)
{
return Current = Direction.Stop;
}
else
{
return Current;
}
}
else
{
return Current;
}
}
public void WaitForSpacebar()
{
if (Console.ReadKey(true).Key == ConsoleKey.Spacebar) { return; }
}
}
public class ShipLogic
{
public Point Previous = new Point(10, 10);
public Point Current = new Point(10, 10);
public void Move(Direction direction)
{
var newLocation = GetMovedPoint(direction);
if (BorderLogic.Intersects(newLocation))
{
newLocation = GetWrappedPoint(newLocation, direction);
}
Current = Previous;
Previous = newLocation;
}
public void Draw()
{
ErasePrevious();
DrawCurrent();
}
public void DrawCurrent(char text = 'X', ConsoleColor foreground = ConsoleColor.White, ConsoleColor background = ConsoleColor.Black)
{
Game.Draw(text.ToString(), Previous, foreground, background);
}
public void ErasePrevious(char text = ' ', ConsoleColor foreground = ConsoleColor.Black, ConsoleColor background = ConsoleColor.Black)
{
Game.Draw(" ", Current, foreground, background);
}
private Point GetMovedPoint(Direction direction)
{
var point = Previous;
if (direction == Direction.Up)
{
point.Y--;
}
else if (direction == Direction.Down)
{
point.Y++;
}
else if (direction == Direction.Left)
{
point.X--;
}
else if (direction == Direction.Right)
{
point.X++;
}
return point;
}
private Point GetWrappedPoint(Point point, Direction direction)
{
if (direction == Direction.Up)
{
point.Y = Game.GameSize.Height - 2;
}
else if (direction == Direction.Down)
{
point.Y = 1;
}
else if (direction == Direction.Left)
{
point.X = Game.GameSize.Width - 2;
}
else if (direction == Direction.Right)
{
point.X = 1;
}
return point;
}
public void Reset()
{
var random = new Random();
Previous = new Point(0, 0);
while (BorderLogic.Intersects(Previous))
{
var x = random.Next(1, Game.GameSize.Width - 1);
var y = random.Next(1, Game.GameSize.Height - 1);
Previous = new Point(x, y);
}
}
}
public class FruitLogic
{
public Point Location;
public Point Previous;
public int Value;
public void Move(Point avoid, int? value = null)
{
var random = new Random();
Previous = Location;
Location = avoid;
while (Location == avoid)
{
var x = random.Next(1, Game.GameSize.Width - 1);
var y = random.Next(1, Game.GameSize.Height - 1);
Location = new Point(x, y);
}
Value = value ?? 9;
}
public void Draw()
{
ErasePrevious();
DrawCurrent();
}
public void DrawCurrent(ConsoleColor foreground = ConsoleColor.Red, ConsoleColor background = ConsoleColor.Black)
{
Game.Draw(Value.ToString(), Location, foreground, background);
}
public void ErasePrevious(char text = ' ', ConsoleColor foreground = ConsoleColor.Black, ConsoleColor background = ConsoleColor.Black)
{
Game.Draw(" ", Previous, foreground, background);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment