线程-贪吃蛇
using System.Security.AccessControl;
namespace 线程
{
//internal class Program
//{
/*public static bool isRunning = true;
public static int exp = 0;
public static object obj=new object();
static void Main(string[] args)
{
//新建一个线程
Thread T = new Thread(ThreadLogic);//入口函数
T.Start();//开启线程
while (false)
{
//Console.BackgroundColor = ConsoleColor.Red;
//给公用数据的地方加锁
lock (obj)//保证锁 里面的代码运行完之 后才会去运行另外一个锁中的代码
{
Console.SetCursorPosition(0, 0);
Console.Write("■");
}
}
//当主线程中所有的代码都运行结束 我们要强制关闭这个新线程 可以给新开的线程设置为后台线程
T.IsBackground = true;//开启后台线程
Console.WriteLine("dfdfdfwef");
//衣示当我按下按键的时候才会执行下面的程序,是用米捕获按键,没按的时候主线程还没结束
Console.WriteLine(Console.ReadKey().Key==ConsoleKey.UpArrow);
Thread.Sleep(1000);
Console.WriteLine("HIHIHOIH");
}
public static void ThreadLogic()
{
*//* while (isRunning)
{
lock (obj)
{
Console.SetCursorPosition(10, 5);
Console.Write("●");
}
}*/
//控制台有一个■通过键盘上的↓,- ,-→键控制方块的移动,通过开启-一个多线程来检测输入控制它的转向,而且要判断边界,方块不能超出边界。
//提示:检测键盘上的按键我们可以通过Console.ReadKey(.key和ConsoleKey,按键名来判断输入的是哪个按键来改变对应方块移动的方向
//创建一个方块类
public class Block
{
public Block(int x, int y)
{
this.x = x * 2;
this.y = y;
}
public int x;
public int y;
public ConsoleColor color = ConsoleColor.White;
//方块都有一个画的方法
public void draw()
{
Console.SetCursorPosition(this.x, this.y);
Console.ForegroundColor = color;
Console.Write("■");
}
//清除的方法
public void clear()
{
Console.SetCursorPosition(this.x, this.y);
Console.Write(" ");
}
}
//创建一个子类 头
public class Head : Block
{
public Head(int x, int y, Dir dir = Dir.right) : base(x, y)
{
this.dir = dir;
base.color = ConsoleColor.Magenta;
}
public Dir dir;
//移动的方法
public void move()
{
switch (dir)
{
case Dir.up:
y--;
break;
case Dir.down:
y++;
break;
case Dir.left:
x -= 2;
break;
case Dir.right:
x += 2;
break;
}
}
//碰撞检测的方法
public bool crash(Block block)
{
if (block.x == this.x && block.y == this.y)
{
return true;
}
return false;
}
}
//创建一个枚举来存方向
public enum Dir
{
up, down, left, right
}
internal class Program
{
public static object obj = new object();
public static int width = Console.BufferWidth;//屏幕宽度
public static int height = Console.BufferHeight;//屏幕高度
public static Block block = new Block(5, 5);
public static Head last = head;//添加一个尾巴结点初始值为头结点,应为一开始只有一个方块
//创建一个头
public static Head head = new Head(0, 0);
//创建一个列表存每一个方块
public static List<Head> list = new List<Head>();
//更新不动的方块
public static void update()
{
Random random = new Random();
int x = random.Next(0, 10) * 2;
int y = random.Next(0, 10);
block.x = x;
block.y = y;
block.draw();
}
static void Main(string[] args)
{
Console.CursorVisible = false;
list.Add(head);
list[0].draw();
block.draw();
//创建一个线程
Thread T = new Thread(ThreadLogic);
T.Start();
T.IsBackground = true;
while (true)
{
lock (obj)
{
Thread.Sleep(200);
//在方块的坐标还没改变之前先获取当前列衣最后个元东的坐标
int x = list[list.Count - 1].x;
int y = list[list.Count - 1].y;
list[0].clear();
//清除所有尾巴的x,y坐标
//所有尾巴要改变坐标为前面的方块的x,y坐标
//变化的坐标
for (int i = list.Count - 1; i >= 1; i--) //3个
{
list[i].clear();//清除原来的位置 遍历到i-1 x,y还没更新
//跟新坐标为前一个方块没更新之前的位置坐标
list[i].x = list[i - 1].x;
list[i].y = list[i - 1].y;
}
list[0].move();
//头移动到下个位置刚好是不动方块的坐标
if (block.x == head.x && block.y == head.y)
{
//添加新的方块到列表中这个时候的坐标应该最后的方块上一次的位置
list.Add(new Head(x / 2, y));//应为我们初始化的时候给x乘以2了所以这里要除以二
//更新一下新的方块的位置
update();
}
for (int i = 0; i < list.Count; i++)
{
list[i].draw();
}
}
/* while (true)
{
lock (obj)
{
Thread.Sleep(200);
//尾巴要更新成头结点 先清除尾巴
last.clear();
//更新头,画新的头
head.move();
if (list.Count > 0)
{
//更新尾节点的x,y坐标为头移动后的x,y坐标
last.x = head.x;
last.y = head.y;
head = last;//更新一下头为尾巴结点
}
//头已经更新了
head.draw();
if (block.x == head.x && block.y == head.y)
{
//添加一个新的节点到列表中
head.move();
Head newHead = new Head(head.x/2,head.y);
list.Add(newHead);
head = newHead;
head.draw();
update();
}
}*/
}
}
static void ThreadLogic2()
{
block.draw();
while (true)
{
lock (obj)
{
if (list[0].crash(block))
{
update();
};//碰完要更新block的位置
}
}
}
static void ThreadLogic()
{
while (true)
{
switch (Console.ReadKey(true).Key)//检测用户输入的按键
{
case ConsoleKey.UpArrow:
//只有一个头随便跑 如果不是一个方块那么不能往反方向走
if (head.dir != Dir.down || list.Count == 1) head.dir = Dir.up;
break;
case ConsoleKey.DownArrow:
//只有一个头随便跑 如果不是一个方块那么不能往反方向走
if (head.dir != Dir.up || list.Count == 1) head.dir = Dir.down;
break;
case ConsoleKey.LeftArrow:
//只有一个头随便跑 如果不是一个方块那么不能往反方向走
if (head.dir != Dir.right || list.Count == 1) head.dir = Dir.left;
break;
case ConsoleKey.RightArrow:
//只有一个头随便跑 如果不是一个方块那么不能往反方向走
if (head.dir != Dir.left || list.Count == 1) head.dir = Dir.right;
break;
}
}
}
}
}
事件和委托
namespace 委托和事件
{
//定义了一个委托
//相当于定义变量,这个变量可以赋值成其他函数
public delegate void Delegate(int i);//定义了一个委托
public class Heater
{
public Action<int> heat;
//怎么声明一个事件 event 委托类型 名字
public event Action<int> Heat;
public void heating()
{
//给事件进行赋值操作
Heat(37);
}
public void test(int i)
{
Console.WriteLine("加热");
}
}
internal class Program
{
static void test(int num)
{
Console.WriteLine(num);
}
static void test1(int num)
{
Console.WriteLine(num);
}
static void Main(string[] args)
{
//声明一个委托
Delegate myDelegate = test;
myDelegate(34);//可以一次性给委托赋值很多个同类型的函数,然后同时调用
myDelegate += test1;//通过相加的形式可以添加多一个函数,然后再调用的时候同时调用
myDelegate -= test1;//通过减掉一个函数,去掉一个函数,再调用的时候就没有该函数了
myDelegate(34);
myDelegate.Invoke(35);//委托的另外一种调用方式
//创建一个Heater对象
//委托可以在类中声明,可以在类的外面进行赋值,也可以进行加减操作,同时在类的外面调用
Heater heater = new Heater();
heater.heat = test;
heater.heat(89);
//heater.Heat = test;//事件不能再类的外面进行赋值
//虽然不能赋值 但是可以加减 ,也不能调用
heater.Heat += test1;
heater.heating();
}
}
}
事件案例
有一个热水器类,里面申明了一个事件myEvent,委托的类型为无返回值,形参为小数(温度值),还有温度的初始值为0度,还有一个报警器类,有一个showInfo的方法会打印出当前的温度为xx度加一度,当水到95度时显示器和报警器中的方法开始调用(使用事件调用)显示器类,也有一个showInfo方法,打印了当前水已烧开,热水器类中有一个加热的方法每隔200毫秒给給水加一度,当水到95度时显示器和报警器中的方法开始调用(使用事件调用)
//定义一个热水器类
public class WaterHeater
{
public double t=0;
public event Action<double> myEvent;//Action封装委托
public void heating()
{
//加热改变温度
while (true)
{
Thread.Sleep(200);
if (t < 100)
{
t += 1.5;
}
else
{
break;
}
if (t <= 95)
{
Console.WriteLine("正常烧水");
}
else
{
if (myEvent != null) myEvent(t);
}
}
}
}
//定义一个报警类
public class Alarm
{
public void showInfo(double t)
{
Console.WriteLine($"当前水已经烧开,温度为{t}度");
}
}
//定义一个显示器类
public class Show
{
public void showInfo(double t)
{
Console.WriteLine($"当前温度为{t}度");
}
}
internal class Program
{
static void Main(string[] args)
{
WaterHeater heat = new WaterHeater();
Alarm alarm = new Alarm();
Show show = new Show();
heat.myEvent += alarm.showInfo;
heat.myEvent += show.showInfo;
heat.heating();
}
}
}
1.插入排序
分为排序区和未排序区
namespace 插入排序
{
internal class Program
{
static void Main(string[] args)
{
//插入排序分为排序区和未排序区
//排序区从第一个元素开始
int[] newArray = new int[] {9,10,34,21,0,3,1};
int temp = newArray[0];
//从未排序区的第一个元素开始遍历,每一次确定一个未排序区中的值
//找到它在排序区中合适的位置然后插入
for(int i = 1; i < newArray.Length; i++)
{
for(int j = i; j > 0; j--)//那当前第i个值和排序区中的值进行比对找到合适的位置
{
if (newArray[j - 1] < newArray[j]) break;
//如果比左边的值要小 要交换值
temp = newArray[j];
newArray[j] = newArray[j - 1];
newArray[j - 1] = temp;
}
}
Console.WriteLine(String.Join(" ", newArray));
}
}
}
2.希尔排序
原理:
namespace 希尔排序
{
internal class Program
{
static void Main(string[] args)
{
//希尔排序
//希尔排序其实还是插入排序,每次比对的步长比1大
int[] intArray = new int[] { 23, 3, 45, 6, 10, 8, 1 };
int temp = intArray[0];
for (int step= intArray.Length / 2; step >= 1; step /= 2)
{
//每一轮进行步长为step的插入排序
for(int start = step; start < intArray.Length; start++)
{
//要拿当前未排序区的值和左边的值进行对比 而且是每隔一个步长为step进行对比
for(int s = start; s>=step; s-=step)
{
//如果左边比右边大 交换值
if (intArray[s] < intArray[s - step])
{
temp = intArray[s];
intArray[s] = intArray[s - step];
intArray[s - step] = temp;
}
}
}
}
Console.WriteLine(String.Join(" ", intArray));
}
}
}
3.快速排序
namespace 快速排序
{
internal class Program
{
static void Main(string[] args)
{
int[] intArray = new int[] { 8, 23, 45, 10, 6, 1 };
//创建一个方法 这个方法要传入中间值,起始坐标,结束坐标
int start = 0;
int end = intArray.Length - 1;
void getMiddle(int s, int e)
{
int start = s;
int end = e;
if (s == e||s>e) return;
int mid = intArray[start];
while (end>start)
{
//一开始从最右边开始比对 如果有一个比中间值小就停下
while (intArray[end] >= mid&&start<end)
{
//右边的值比mid大的时候,最后的游标才进行减减
end--;
}
//到外面来说明 end对应的下标的值要比mid小,把end的值赋值给start位置
intArray[start] = intArray[end];
while (intArray[start] <= mid&&start<end)
{
start++;
}
//到这里说明有一个比它还大那么就将当前start下标对应的值赋给end下标对应的值
intArray[end] = intArray[start];
}
//到这里说明中间值的位置找到了,要在正位置插入中间值
intArray[end] = mid;
//对子序列进行同样的操作
getMiddle(s, end-1);
getMiddle(end + 1, e);
}
getMiddle(start,end);
Console.WriteLine(String.Join(" ", intArray));
}
}
}