from threading import Thread # потоки
import msvcrt # библиотека неприрывно считывающая нажатие клавиш в консоли
#a = msvcrt.getch() # получает клавишу формат: b'a' - a
#str(a)[2]
import random
import os
import math
import time
import copy

# PixelDisplay(width,height) поле для рисования
# Clear() очистить
# ShowDisplay() обновить
# SetPixel(x,y) нарисовать пиксель
# ClearPixel(x,y) удалить пиксель
# DrawLine(x1,y1,x2,y2) нарисовать линию
# DrawCircul(x,y,r) нарисовать окружность
# DrawPoligon(x1,y1,z1,x2,y2,z2,x3,y3,z3) нарисовать трехмерный полигон

class PixelDisplay:
    h = 10 # 3d projection value
    def __init__(self,width,height):
        self.width = width
        self.height = height
        self.PixelArray = self.CreateDisplay()
        self.cls = copy.deepcopy(self.PixelArray)
    def CreateDisplay(self):
        Y = []
        X = []
        for i in range(self.height):
            for j in range(self.width):
                X.append(" ")
            Y.append(X)
            X = []
        return Y
    def Clear(self):
        self.PixelArray = []
        self.PixelArray = copy.deepcopy(self.cls)
        time.sleep(0.004)
        os.system("cls")
        time.sleep(0.004)
    def ShowDisplay(self):
        st = ""
        for i in range(self.height):
            for j in range(self.width):
                st += self.PixelArray[i][j]
            print(st)
            st = ""
    def SetPixel(self,x,y,pix="*"):
        if (y < self.height and x <self.width and y >= 0 and x>= 0):
            self.PixelArray[y][x] = pix
    def ClearPixel (self,x,y):
        if (y < self.height and x <self.width and y >= 0 and x>= 0):
            self.PixelArray[y][x] = " "
    def DrawLine(self,x1,y1,x2,y2,pix="*"):
        if (abs(x2-x1)>=abs(y2-y1)):
            if (x2 != x1):
                tan = (y2-y1)/(x2-x1)
            if (x2>x1):
                for x in range(x1,x2):
                    y = tan*(x-x1)+y1
                    self.SetPixel(x,int(y),pix)
            elif (x1>x2):
                for x in range(x2,x1):
                    y = tan*(x-x1)+y1
                    self.SetPixel(x,int(y),pix)
            elif (x1 == x2):
                if (y2 > y1):
                    for y in range(y1,y2):
                        self.SetPixel(x1,y,pix)
                elif (y1 > y2):
                    for y in range(y2,y1):
                        self.SetPixel(x1,y,pix)
                else:
                    self.SetPixel(x1,y1,pix)
        if (abs(x2-x1)< abs(y2-y1)):
            if (y2 != y1):
                tan = (x2-x1)/(y2-y1)
            if (y2>y1):
                for y in range(y1,y2):
                    x = tan*(y-y1)+x1
                    self.SetPixel(int(x),y,pix)
            elif (y1>y2):
                for y in range(y2,y1):
                    x = tan*(y-y1)+x1
                    self.SetPixel(int(x),y,pix)
            elif (y1 == y2):
                if (x2 > x1):
                    for x in range(x1,x2):
                        self.SetPixel(x,y1,pix)
                elif (x1 > x2):
                    for x in range(x2,x1):
                        self.SetPixel(x,y1,pix)
                else:
                    self.SetPixel(x1,y1,pix)
    def DrawCircul(self,x,y,r,pix="*"):
        for i in range(360):
            _x = int(x + r*math.cos(i*3.1415926/180))
            _y = int(y + r*math.sin(i*3.1415926/180))
            self.SetPixel(_x,_y,pix)
    def Pixel3d(self,x,y,z):
        if (z > 0):
            _x = int((x/z)*self.h)
            _y = int((y/z)*self.h)
            return [_x, _y]
        else:
            print("error")
    def DrawPoligon(self,x1,y1,z1,x2,y2,z2,x3,y3,z3,pix="*"):
        v1 = [x2-x1,y2-y1,z2-z1]
        v2 = [x3-x2,y3-y2,z3-z2]
        n = [v1[1]*v2[2]-v1[2]*v2[1],v1[2]*v2[0]-v1[0]*v2[2],v1[0]*v2[1]-v1[1]*v2[0]]
        if (n[2]*1< 0):
            P1 = self.Pixel3d(x1,y1,z1)
            P2 = self.Pixel3d(x2,y2,z2)
            P3 = self.Pixel3d(x3,y3,z3)
            x1,y1 = P1[0],P1[1]
            x2,y2 = P2[0],P2[1]
            x3,y3 = P3[0],P3[1]
            self.DrawLine(x1,y1,x2,y2,pix)
            self.DrawLine(x2,y2,x3,y3,pix)
            self.DrawLine(x3,y3,x1,y1,pix)

class Sprite:
    # format
    # A = [
    #[[" ","*"," "],[" ","*"," "],[" ","*"," "]],
    #[[" ","*"," "],["*","*","*"],[" ","*"," "]]
    #]
    def __init__(self,A,x,y,display):
        self.x = x
        self.y = y
        self.display = display
        self.img = A
        self.width = len(self.img[0][0])
        self.height = len(self.img[0])
        self.shoot = len(self.img)
        self.currentShoot = 0
        self.collisionShoot = self.currentShoot
    # отобразить спрайт и переключить на новый кадр
    def Draw(self):
        # i - y
        # j - x
        for i in range(len(self.img[self.currentShoot])):
            for j in range(len(self.img[self.currentShoot][0])):
                self.display.SetPixel(self.x+j,self.y+i,self.img[self.currentShoot][i][j])
        self.collisionShoot = self.currentShoot
        self.currentShoot += 1
        if (self.currentShoot >= len(self.img)):
            self.currentShoot = 0
    # отобразить конкретный кадр (OK)
    def DrawShoot(self,Shoot):
        # i - y
        # j - x
        for i in range(len(self.img[Shoot])):
            for j in range(len(self.img[Shoot][0])):
                self.display.SetPixel(self.x+j,self.y+i,self.img[Shoot][i][j])
        self.collisionShoot = Shoot
        self.currentShoot = Shoot
        self.width = len(self.img[Shoot][0])
        self.height = len(self.img[Shoot])
    # проверка попадания
    def CheckCollision(self,x,y):
        x = x - self.x
        y = y - self.y
        if (abs(x) < self.width and abs(y) < self.height):
            if (self.img[self.collisionShoot][y][x] != " "):
                return True
            else:
                return False
        else:
            return False 
    # обновить координаты
    def updateXY(self,x,y):
        self.x = x
        self.y = y

class Player:
    def __init__(self,playerSprite,x,y,display):
        self.x = x
        self.y = y
        self.sprite = Sprite(playerSprite,x,y,display)
    def move_x(self,value):
        if (value==-1):
            self.x-=1
        if (value==1):
            self.x+=1
        self.sprite.updateXY(self.x,self.y)
    def move_y(self,value):
        if (value==-1):
            self.y-=1
        if (value==1):
            self.y+=1
        self.sprite.updateXY(self.x,self.y)

class bullet:
    def __init__(self,bulletSprite,x,y,display,vx,vy,dist):
        self.x0 = x
        self.y0 = y
        self.x = x
        self.y = y
        self.vx = vx
        self.vy = vy
        self.dist = dist
        self.sprite = Sprite(bulletSprite,x,y,display)
    def move(self):
        self.x = self.x + self.vx
        self.y = self.y + self.vy
        self.sprite.updateXY(self.x,self.y)
    def check(self):
        vector = pow(pow(self.x-self.x0,2)+pow(self.y-self.y0,2),0.5)
        if (vector < self.dist):
            return True
        else:
            return False

class Game:
    def __init__(self):
        self.A = [[[" ","*"," "],["*","*","*"],[" ","*"," "],["*"," ","*"]],
             [["*"," ","*"," "],[" ","*","*","*"],["*"," ","*"," "]],
             [["*"," ","*"],[" ","*"," "],["*","*","*"],[" ","*"," "]],
             [[" ","*"," ","*"],["*","*","*"," "],[" ","*"," ","*"]]]
        self.plShootNum = 0
        self.pl2ShootNum = 0
        self.bullets = []
        self.bulletsLen = 0
        self.bulletsIndexes = []
        self.key = "b'm'"
        self.GameScreen = PixelDisplay(100,70)
        self.player = Player(self.A,10,25,self.GameScreen)
        self.player2 = Player(self.A,25,25,self.GameScreen)
        self.player2Action = True
        self.playerScore = 0
        self.player2Score = 0
    # рендер игры
    def gameLoop(self):
        while (True):
            # действия игрока2
            vect = [(self.player2.x),(self.player2.y)]
            vect1 = [-15+self.player.x,0+self.player.y]
            vect2 = [15+self.player.x,0+self.player.y]
            vect3 = [0+self.player.x,15+self.player.y]
            vect4 = [0+self.player.x,-15+self.player.y]
            v = [vect1,vect2,vect3,vect4]
            dist = [0,0,0,0]
            index = 0
            while (self.player2Action):
                for i in range(4):
                    dist[i] = pow(pow(v[i][0]-vect[0],2)+pow(v[i][1]-vect[1],2),0.5)
                min_d = dist[0]
                for i in range(4):
                    if dist[i] < min_d:
                        index = i
                target = v[index]
                if (vect[0]<target[0]):
                    self.pl2ShootNum = 1
                    self.player2.move_x(1)
                    self.player2Action = False
                    continue
                if (vect[0]>target[0]):
                    self.pl2ShootNum = 3
                    self.player2.move_x(-1)
                    self.player2Action = False
                    continue
                if (vect[1]<target[1]):
                    self.pl2ShootNum = 2
                    self.player2.move_y(1)
                    self.player2Action = False
                    continue
                if (vect[1]>target[1]):
                    self.pl2ShootNum = 0
                    self.player2.move_y(-1)
                    self.player2Action = False
                    continue
                if index == 1:
                    self.bullets.append(bullet([[['"']]],self.player2.x-5,self.player2.y+1,self.GameScreen,-1,0,20))
                    self.bulletsLen = len(self.bullets)
                    self.pl2ShootNum = 3
                if index == 0:
                    self.bullets.append(bullet([[['"']]],self.player2.x+5,self.player2.y+1,self.GameScreen,1,0,20))
                    self.bulletsLen = len(self.bullets)
                    self.pl2ShootNum = 1
                if index == 2:
                    self.bullets.append(bullet([[['"']]],self.player2.x+1,self.player2.y-4,self.GameScreen,0,-1,20))
                    self.bulletsLen = len(self.bullets)
                    self.pl2ShootNum = 0
                if index == 3:
                    self.bullets.append(bullet([[['"']]],self.player2.x+1,self.player2.y+4,self.GameScreen,0,1,20))
                    self.bulletsLen = len(self.bullets)
                    self.pl2ShootNum = 2
                self.player2Action = False
            self.player2Action = True
            # обработка кнопок
            if (str(self.key)[2]=='a'):
                self.plShootNum = 3
                self.player.move_x(-1)
                self.key = "b'm'"
            if (str(self.key)[2]=='d'):
                self.plShootNum = 1
                self.player.move_x(1)
                self.key = "b'm'"
            if (str(self.key)[2]=='w'):
                self.plShootNum = 0
                self.player.move_y(-1)
                self.key = "b'm'"
            if (str(self.key)[2]=='s'):
                self.plShootNum = 2
                self.player.move_y(1)
                self.key = "b'm'"
            # пули
            if (str(self.key)[2]=='f'):
                if self.plShootNum == 0:
                    self.bullets.append(bullet([[['"']]],self.player.x+1,self.player.y-4,self.GameScreen,0,-1,20))
                elif self.plShootNum == 2:
                    self.bullets.append(bullet([[['"']]],self.player.x+1,self.player.y+4,self.GameScreen,0,1,20))
                elif self.plShootNum == 1:
                    vect = [1,0]
                    self.bullets.append(bullet([[['"']]],self.player.x+5,self.player.y+1,self.GameScreen,1,0,20))
                elif self.plShootNum == 3:
                    vect = [-1,0]
                    self.bullets.append(bullet([[['"']]],self.player.x-5,self.player.y+1,self.GameScreen,-1,0,20))
                self.bulletsLen = len(self.bullets)
                self.key = "b'm'"
            # код
            # пули
            for i in range(self.bulletsLen):
                if (self.bullets[i].check()):
                    self.bullets[i].move()
                else:
                    self.bulletsIndexes.append(i)
            for i in self.bulletsIndexes:
                self.bullets.pop(i)
                self.bulletsLen -= 1
            self.bulletsIndexes = []
            # пули конец
            self.GameScreen.Clear()
            self.player.sprite.DrawShoot(self.plShootNum)
            self.player2.sprite.DrawShoot(self.pl2ShootNum)
            for i in range(self.bulletsLen):
                self.bullets[i].sprite.DrawShoot(0)
            self.GameScreen.ShowDisplay()
            # попадание по игроку
            for b in self.bullets:
                if (self.player.sprite.CheckCollision(b.x,b.y)):
                    self.player = Player(self.A,random.randint(1,99),random.randint(1,69),self.GameScreen)
                    self.bullets = []
                    self.bulletsLen = 0
                    self.player2Score += 1
                if (self.player2.sprite.CheckCollision(b.x,b.y)):
                    self.player2 = Player(self.A,random.randint(1,99),random.randint(1,69),self.GameScreen)
                    self.bullets = []
                    self.bulletsLen = 0
                    self.playerScore += 1
            print("Player Score:",self.playerScore,"Computer Score:",self.player2Score)
    # считка клавиш
    def getKey(self):
        while (True):
            self.key = msvcrt.getch()

game = Game()

thread1 = Thread(target=game.gameLoop)
thread2 = Thread(target=game.getKey)

thread1.start()
thread2.start()
thread1.join()
thread2.join()
