Python tkinter中填充正确网格单元的问题

Python tkinter中填充正确网格单元的问题,python,tkinter,Python,Tkinter,我想用tkinter用python制作一个战舰游戏, 最小可再现示例为: from tkinter import * from random import randint import time tk = Tk() class player: def __init__(self, master): self.master = master self.placedships = [] self.bombed = [] s

我想用tkinter用python制作一个战舰游戏, 最小可再现示例为:

from tkinter import *
from random import randint
import time

tk = Tk()


class player:
    def __init__(self, master):
        self.master = master
        self.placedships = []
        self.bombed = []
        self.sunk = []
        self.ship_sizes = [5, 4, 3]
        self.player_canvas = Canvas(master, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
        self.ai_canvas = Canvas(master, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
        self.player_canvas.grid(row=1, column=0, padx=50)
        self.ai_canvas.grid(row=1, column=1, padx=50)
        self.direction = 'v'
        self.shipChosen = 0

        gridLabel_player = Label(master,text="Your grid \nA       B       C       D       E       F       G       H       I       J ")
        gridLabel_player.grid(row=0,column=0)
        gridLabel_ai = Label(master,text="AI's grid \nA       B       C       D       E       F       G       H       I       J ")
        gridLabel_ai.grid(row=0,column=1)

        for x in range(10):
            for y in range(10):
                self.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill = 'white')
                self.ai_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill = 'white')

        #variables to store data for cells on game grid
        #         # self.player_ocean = 10 * [10 * [0]]
        #         # self.ai_ocean = 10 * [10 * [0]]
        self.player_ocean = []
        self.ai_ocean = []
        temp = []
        for i in range(10):
            for y in range(10):
                temp += [0]
            self.player_ocean += [temp]
            self.ai_ocean += [temp]
            temp = []
        self.selectedCoord = [0,0] # [0] = x coord, [1] = y coord




    def placeShip(self):
        def moveShip(event):
            if event.keysym == 'Down' and self.selectedCoord[1] != 9:
                self.selectedCoord[1] += 1
            elif event.keysym == 'Up' and self.selectedCoord[1] != 0:
                self.selectedCoord[1] -= 1
            elif event.keysym == 'Left' and self.selectedCoord[0] != 0:
                self.selectedCoord[0] -= 1
            elif event.keysym == 'Right' and self.selectedCoord[0] != 9:
                self.selectedCoord[0] += 1
            print('selected coord:',self.selectedCoord)

        def selectPlacement(event):
            col = self.selectedCoord[0]
            row = self.selectedCoord[1]
            if self.direction == 'v':
                v_range_start = row - self.ship_sizes[self.shipChosen] + 1
                for y in range(v_range_start, row+1):
                    '''insert validation to reject ship clashing'''
                    self.player_ocean[y][col] = 1
                    self.placedships += [y,col]
                self.refresh_ocean()




        self.master.bind("<Up>", moveShip)
        self.master.bind("<Down>", moveShip)
        self.master.bind("<Left>", moveShip)
        self.master.bind("<Right>", moveShip)
        self.master.bind("<Return>", selectPlacement)

    def refresh_ocean(self): # 1s turns to green
        for y in range(10):
            for x in range(10):
                if self.player_ocean[y][x] == 1:
                    self.player_canvas.itemconfig(self.player_canvas.create_rectangle( (x+1) * 30, (y-1) * 30,x * 30, y * 30, fill='green'))


player1 = player(tk)
player1.placeShip()
tk.mainloop()
从tkinter导入*
从随机导入randint
导入时间
tk=tk()
职业球员:
定义初始(自我,主):
self.master=master
self.placedships=[]
self.bombed=[]
self.sink=[]
self.ship_大小=[5,4,3]
self.player_canvas=canvas(master,高度=300,宽度=300,highlightbackground='black',highlightthickness=0.5)
self.ai_canvas=canvas(母版,高度=300,宽度=300,highlightbackground='black',highlightthickness=0.5)
self.player\u canvas.grid(行=1,列=0,padx=50)
self.ai_canvas.grid(行=1,列=1,padx=50)
self.direction='v'
self.shipSelected=0
gridLabel\u player=Label(master,text=“您的网格\nA B C D E F G H I J”)
gridLabel\u player.grid(行=0,列=0)
gridLabel_ai=Label(master,text=“ai的网格\nA B C D E F G H I J”)
gridLabel_ai.grid(行=0,列=1)
对于范围(10)内的x:
对于范围(10)内的y:
self.player_canvas.create_矩形(x*30,y*30300300,fill='white')
self.ai_canvas.create_矩形(x*30,y*30300300,fill='white')
#用于在游戏网格上存储单元格数据的变量
##self.player_ocean=10*[10*[0]]
##self.ai_ocean=10*[10*[0]]
self.player_ocean=[]
self.ai_ocean=[]
温度=[]
对于范围(10)内的i:
对于范围(10)内的y:
温度+=[0]
self.player_ocean+=[temp]
self.ai_海洋+=[温度]
温度=[]
self.selectedCoord=[0,0]#[0]=x coord,[1]=y coord
def安置(自我):
def移动船舶(事件):
如果event.keysym=='Down'和self.selectedCoord[1]!=9:
self.selectedCoord[1]+=1
elif event.keysym=='Up'和self.selectedCoord[1]!=0:
自选择坐标[1]-=1
elif event.keysym==‘左’和self.selectedCoord[0]!=0:
self.selectedCoord[0]-=1
elif event.keysym==‘右’和self.selectedCoord[0]!=9:
self.selectedCoord[0]+=1
打印('选定坐标:',self.selectedCoord)
def selectPlacement(事件):
col=self.selectedCoord[0]
行=自选择坐标[1]
如果self.direction='v':
v_range_start=行-self.ship_大小[self.shipSelected]+1
对于范围内的y(v_范围_开始,第+1行):
''插入验证以拒绝装运冲突''
self.player_ocean[y][col]=1
自置芯片+=[y,col]
self.refresh_ocean()
self.master.bind(“,moveShip)
self.master.bind(“,moveShip)
self.master.bind(“,moveShip)
self.master.bind(“,moveShip)
self.master.bind(“,selectPlacement)
def刷新海洋(自我):#1s变为绿色
对于范围(10)内的y:
对于范围(10)内的x:
如果self.player_[y][x]==1:
self.player_canvas.itemconfig(self.player_canvas.create_矩形((x+1)*30,(y-1)*30,x*30,y*30,fill='green'))
player1=播放器(tk)
player1.placeShip()
tk.mainloop()
我遇到的问题是,如果我按下向下箭头,直到我选择的坐标为[0,9],代码应该在第一列中从上到下为第6到第10个方框上色,但它会为第5到第9个方框上色


我试着通过检查上次函数中使用的坐标x和y是否错误来调试它,但它们与预期的一样

您的刷新海洋有一个off by 1错误

def refresh_ocean(self): # 1s turns to green
    for y in range(10):
        for x in range(10):
            if self.player_ocean[y][x] == 1:
                self.player_canvas.itemconfig(self.player_canvas.create_rectangle( x*30, y * 30, x*30+30, y*30+30, fill='green'))
而“选择放置”则是将船只放置在负索引中。 我将迭代从
range(row size,row)
更改为
range(row,row+size)
,并添加了边界检查,但这可能应该移动到移动处理

def selectPlacement(event):
    col = self.selectedCoord[0]
    row = self.selectedCoord[1]
    if self.direction == 'v':
        if row + self.ship_sizes[self.shipChosen] > 9:
            row = 10 - self.ship_sizes[self.shipChosen]
        for y in range(row, row + self.ship_sizes[self.shipChosen]):
            '''insert validation to reject ship clashing'''
            self.player_ocean[y][col] = 1
            self.placedships += [y,col]
        self.refresh_ocean()

附言:你在旧方块上画新方块。您可能希望在绘图之前清除海洋。

因此,简单的解决方法是将
(y-1)更改为(y+1)

也就是说,我做了一些改变:

  • 按照PEP8风格指南改写您的一些姓名

  • 转换了
    refresh\u-ocean
    方法来处理初始绘制和所有后续绘制。还添加了一个
    delete('all')
    来清除电路板,这样我们就不会在前面的对象上绘制。这将防止在游戏进行过程中使用更多内存

  • 清理导入并将
    从tkinter导入*
    更改为
    将tkinter作为tk导入
    。这将有助于防止覆盖命名空间中的其他内容

  • 通过编写
    refresh\u ocean
    来处理所有绘图,我们可以指定需要使用标签绘制的内容,如
    'player1'
    'ai'

  • 将列表生成的
    +=
    更改为
    .append()
    ,因为
    append()
    的速度是
    '+=
    的两倍。见此帖:

  • 将标题的单个标签更改为循环,以均匀创建每个标签。这将允许更准确的标题,然后尝试在单个字符串中手动设置空格

  • 最后,因为您已经在检查键是4个箭头键之一,所以我们可以使用单个绑定到
    '
    ,并获得与所有4个绑定相同的结果

  • 更新代码:

    import tkinter as tk
    
    
    class Player(tk.Tk):
        def __init__(self):
            super().__init__()
            self.placed_ships = []
            self.player_ocean = []
            self.ai_ocean = []
            self.bombed = []
            self.sunk = []
            self.bord_size = list('ABCDEFGHIJ')
            self.selected_coord = [0, 0]
            self.ship_sizes = [5, 4, 3]
            self.direction = 'v'
            self.shipChosen = 0
            wh = 300
    
            p_label_frame = tk.Frame(self, width=wh, height=30)
            a_label_frame = tk.Frame(self, width=wh, height=30)
            p_label_frame.grid(row=1, column=0, padx=50)
            a_label_frame.grid(row=1, column=1, padx=50)
            p_label_frame.grid_propagate(False)
            a_label_frame.grid_propagate(False)
    
            for ndex, letter in enumerate(self.bord_size):
                p_label_frame.columnconfigure(ndex, weight=1)
                a_label_frame.columnconfigure(ndex, weight=1)
                tk.Label(p_label_frame, text=letter).grid(row=0, column=ndex)
                tk.Label(a_label_frame, text=letter).grid(row=0, column=ndex)
    
            self.player_canvas = tk.Canvas(self, height=wh, width=wh, highlightbackground='black', highlightthickness=0.5)
            self.ai_canvas = tk.Canvas(self, height=wh, width=wh, highlightbackground='black', highlightthickness=0.5)
            self.player_canvas.grid(row=2, column=0, padx=50)
            self.ai_canvas.grid(row=2, column=1, padx=50)
    
            temp = []
            for i in range(10):
                for y in range(10):
                    temp.append(0)
                self.player_ocean.append(temp)
                self.ai_ocean.append(temp)
                temp = []
    
            self.refresh_ocean()
            self.bind("<Key>", self.move_ship)
            self.bind("<Return>", self.select_placement)
    
        def move_ship(self, event):
            if event.keysym == 'Down' and self.selected_coord[1] < 9:
                self.selected_coord[1] += 1
            elif event.keysym == 'Up' and self.selected_coord[1] > 0:
                self.selected_coord[1] -= 1
            elif event.keysym == 'Left' and self.selected_coord[0] > 0:
                self.selected_coord[0] -= 1
            elif event.keysym == 'Right' and self.selected_coord[0] < 9:
                self.selected_coord[0] += 1
            print('selected coord:', self.selected_coord)
    
        def select_placement(self, _=None):
            col = self.selected_coord[0]
            row = self.selected_coord[1]
            if self.direction == 'v':
                v_range_start = row - self.ship_sizes[self.shipChosen] + 1
                for y in range(v_range_start, row+1):
                    '''insert validation to reject ship clashing'''
                    self.player_ocean[y][col] = 1
                    self.placed_ships += [y, col]
                self.refresh_ocean(side='player1')
    
        def refresh_ocean(self, side=None):
            self.player_canvas.delete('all')
            self.ai_canvas.delete('all')
    
            for y in range(len(self.bord_size)):
                for x in range(len(self.bord_size)):
                    if self.player_ocean[y][x] == 1 and side == 'player1':
                        self.player_canvas.itemconfig(self.player_canvas.create_rectangle(
                            (x+1) * 30, (y+1) * 30, x * 30, y * 30, fill='green'))
                    else:
                        self.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
    
                    if self.ai_ocean[y][x] == 1 and side == 'ai':
                        self.ai_canvas.itemconfig(self.ai_canvas.create_rectangle(
                            (x + 1) * 30, (y + 1) * 30, x * 30, y * 30, fill='green'))
                    else:
                        self.ai_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
    
    
    if __name__ == '__main__':
        Player().mainloop()
    
    将tkinter作为tk导入
    职业玩家(tk.tk):
    定义初始化(自):
    super()。\uuuu init\uuuuu()
    自置_船舶=[]
    self.player_ocean=[]
    self.ai_ocean=[]
    self.bombed=[]
    self.sink=[]