Skip to content

Instantly share code, notes, and snippets.

@tomaszbartoszewski
Last active July 11, 2017 21:17
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save tomaszbartoszewski/04aba19fb2b55be7caa3bc2dd22dd983 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Snake
{
class Program
{
static void Main(string[] args)
{
var board = new Board(40, 20);
var sw = Stopwatch.StartNew();
while (true)
{
while (Console.KeyAvailable)
{
var key = Console.ReadKey(true);
Direction direction = Direction.None;
switch (key.Key)
{
case ConsoleKey.UpArrow:
direction = Direction.Up;
break;
case ConsoleKey.DownArrow:
direction = Direction.Down;
break;
case ConsoleKey.LeftArrow:
direction = Direction.Left;
break;
case ConsoleKey.RightArrow:
direction = Direction.Right;
break;
}
board.SetMove(direction);
}
if (sw.ElapsedMilliseconds > 300)
{
if (board.MoveByOneField())
break;
sw.Restart();
}
}
Console.SetCursorPosition(16, 9);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("GAME OVER");
Console.SetCursorPosition(0, 20);
Console.ReadLine();
}
}
public class Board
{
private FieldValue[] boardState;
private Direction[] boardDirections;
private int width;
private int height;
private int snakeHead;
private int snakeTail;
private Direction currentDirection = Direction.Right;
public Board(int width, int height)
{
this.width = width;
this.height = height;
boardDirections = new Direction[width * height];
boardState = GenerateEmptyBoard();
AddSnake();
AddFood();
PrintBoard();
}
public void SetMove(Direction direction)
{
boardDirections[snakeHead] = direction;
currentDirection = direction;
}
public bool MoveByOneField()
{
if (boardDirections[snakeHead] == Direction.None)
boardDirections[snakeHead] = currentDirection;
var fieldsToRefresh = new List<int>();
var nextHeadPosition = GetNextFieldId(snakeHead);
var nextHeadField = boardState[nextHeadPosition];
switch (nextHeadField)
{
case FieldValue.Snake:
case FieldValue.Wall:
return true;
case FieldValue.Food:
boardDirections[nextHeadPosition] = boardDirections[snakeHead];
boardState[nextHeadPosition] = FieldValue.Snake;
fieldsToRefresh.Add(snakeHead);
fieldsToRefresh.Add(nextHeadPosition);
snakeHead = nextHeadPosition;
fieldsToRefresh.Add(AddFood());
break;
case FieldValue.Empty:
fieldsToRefresh = MoveSnake().ToList();
break;
}
RefreshFieldsOnScreen(fieldsToRefresh);
return false;
}
private void AddSnake()
{
snakeHead = width * ((height / 2)-1) + width / 2 + 1;
snakeTail = snakeHead - 2;
boardState[snakeHead] = FieldValue.Snake;
boardState[snakeHead - 1] = FieldValue.Snake;
boardState[snakeHead - 2] = FieldValue.Snake;
boardDirections[snakeHead] = currentDirection;
boardDirections[snakeHead - 1] = currentDirection;
boardDirections[snakeHead - 2] = currentDirection;
}
private IEnumerable<int> MoveSnake()
{
var newBoard = GenerateEmptyBoard();
int newSnakeHead = 0;
int newSnakeTail = 0;
for (var i = 0; i < boardState.Length; i++)
{
if (boardState[i] == FieldValue.Snake)
{
var nextField = GetNextFieldId(i);
newBoard[nextField] = FieldValue.Snake;
if (i == snakeHead)
newSnakeHead = nextField;
if (i == snakeTail)
{
boardDirections[i] = Direction.None;
newSnakeTail = nextField;
}
yield return i;
yield return nextField;
}
else if (boardState[i] == FieldValue.Food)
{
newBoard[i] = FieldValue.Food;
}
}
boardState = newBoard;
snakeHead = newSnakeHead;
snakeTail = newSnakeTail;
}
private FieldValue[] GenerateEmptyBoard()
{
var newBoardState = new FieldValue[width * height];
for (var i = 0; i < width; i++)
newBoardState[i] = FieldValue.Wall;
for (var i = (height - 1) * width; i < newBoardState.Length; i++)
newBoardState[i] = FieldValue.Wall;
for (var i = 1; i < height; i++)
{
newBoardState[i * width] = FieldValue.Wall;
newBoardState[i * width - 1] = FieldValue.Wall;
}
return newBoardState;
}
private int GetNextFieldId(int currentFieldId)
{
var direction = boardDirections[currentFieldId];
switch (direction)
{
case Direction.Right:
return currentFieldId + 1;
case Direction.Left:
return currentFieldId - 1;
case Direction.Up:
return currentFieldId - width;
case Direction.Down:
return currentFieldId + width;
}
return -1;
}
private int AddFood()
{
var rnd = new Random();
while (true)
{
var fieldId = rnd.Next(boardState.Length);
if (boardState[fieldId] == FieldValue.Empty)
{
boardState[fieldId] = FieldValue.Food;
return fieldId;
}
}
}
public void RefreshFieldsOnScreen(IEnumerable<int> fieldsToRefresh)
{
foreach (var fieldId in fieldsToRefresh)
{
var row = fieldId / width;
var column = fieldId % width;
Console.SetCursorPosition(column, row);
var fieldValue = boardState[fieldId];
PrintField(fieldValue, fieldId == snakeHead);
}
Console.SetCursorPosition(0, height);
}
private void PrintBoard()
{
Console.Clear();
for (var h = 0; h < height; h++)
{
for (var w = 0; w < width; w++)
{
var fieldId = h * width + w;
var fieldValue = boardState[fieldId];
PrintField(fieldValue, fieldId == snakeHead);
}
Console.WriteLine();
}
}
private void PrintField(FieldValue fieldValue, bool isHead)
{
switch (fieldValue)
{
case FieldValue.Wall:
Console.BackgroundColor = ConsoleColor.DarkRed;
Console.Write(' ');
Console.ResetColor();
break;
case FieldValue.Snake:
Console.BackgroundColor = isHead ? ConsoleColor.DarkYellow : ConsoleColor.DarkGreen;
Console.Write(' ');
Console.ResetColor();
break;
case FieldValue.Food:
Console.BackgroundColor = ConsoleColor.White;
Console.Write(' ');
Console.ResetColor();
break;
case FieldValue.Empty:
Console.BackgroundColor = ConsoleColor.Green;
Console.Write(' ');
Console.ResetColor();
break;
}
}
}
public enum FieldValue : byte
{
Empty,
Wall,
Snake,
Food
}
public enum Direction : byte
{
None,
Up,
Down,
Left,
Right
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment