Python Turtle Collision Detection via “not in” list. Why doesn't it work?
The goal of this test code is to make a player that moves with W,A,S,D and starts or stops building a wall with the ENTER key. I would appreciate it if someone could tell me why he only sometimes collides with his walls. Feel free to critique my code in a general sense as well! Thanks in advance.
import turtle
grid_size = 10
t1 = turtle.Pen()
t1.width(grid_size)
t1.up()
walls = [[0,0]]
walls.clear()
def toggle_building():
if t1.isdown():
t1.up()
else:
t1.down()
def lay_brick():
if t1.isdown() and t1.pos() not in walls:
walls.append(t1.pos())
print("Brick layed.")
def print_pos():
print(t1.pos())
def move_up():
t1.setheading(90)
if t1.pos() + [0, grid_size] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_left():
t1.setheading(180)
if t1.pos() - [grid_size, 0] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_down():
t1.setheading(270)
if t1.pos() - [0, grid_size] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_right():
t1.setheading(0)
if t1.pos() + [grid_size, 0] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
turtle.onkeypress(move_up, "w")
turtle.onkeypress(move_left, "a")
turtle.onkeypress(move_down, "s")
turtle.onkeypress(move_right, "d")
turtle.onkeypress(toggle_building, "Return")
turtle.listen()
python python-3.x turtle-graphics
add a comment |
The goal of this test code is to make a player that moves with W,A,S,D and starts or stops building a wall with the ENTER key. I would appreciate it if someone could tell me why he only sometimes collides with his walls. Feel free to critique my code in a general sense as well! Thanks in advance.
import turtle
grid_size = 10
t1 = turtle.Pen()
t1.width(grid_size)
t1.up()
walls = [[0,0]]
walls.clear()
def toggle_building():
if t1.isdown():
t1.up()
else:
t1.down()
def lay_brick():
if t1.isdown() and t1.pos() not in walls:
walls.append(t1.pos())
print("Brick layed.")
def print_pos():
print(t1.pos())
def move_up():
t1.setheading(90)
if t1.pos() + [0, grid_size] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_left():
t1.setheading(180)
if t1.pos() - [grid_size, 0] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_down():
t1.setheading(270)
if t1.pos() - [0, grid_size] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_right():
t1.setheading(0)
if t1.pos() + [grid_size, 0] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
turtle.onkeypress(move_up, "w")
turtle.onkeypress(move_left, "a")
turtle.onkeypress(move_down, "s")
turtle.onkeypress(move_right, "d")
turtle.onkeypress(toggle_building, "Return")
turtle.listen()
python python-3.x turtle-graphics
Ispos()
a floating-point number?
– Robert Harvey♦
Nov 19 '18 at 21:15
If I'm not mistaken, pos() returns a Vec2D with two floating points, like so: [20.00, 10.00] @RobertHarvey
– user9694049
Nov 19 '18 at 21:17
Floating point numbers cannot be reliably compared using equals. Granted, it shouldn't matter if you're storingpos()
directly, but you are doing some arithmetic there, so.
– Robert Harvey♦
Nov 19 '18 at 21:18
Thank you @RobertHarvey ! I added some code to convert the floating points into ints and then append them to the list, plus some code to make sure the ints are always multiples of 10.
– user9694049
Nov 19 '18 at 21:58
add a comment |
The goal of this test code is to make a player that moves with W,A,S,D and starts or stops building a wall with the ENTER key. I would appreciate it if someone could tell me why he only sometimes collides with his walls. Feel free to critique my code in a general sense as well! Thanks in advance.
import turtle
grid_size = 10
t1 = turtle.Pen()
t1.width(grid_size)
t1.up()
walls = [[0,0]]
walls.clear()
def toggle_building():
if t1.isdown():
t1.up()
else:
t1.down()
def lay_brick():
if t1.isdown() and t1.pos() not in walls:
walls.append(t1.pos())
print("Brick layed.")
def print_pos():
print(t1.pos())
def move_up():
t1.setheading(90)
if t1.pos() + [0, grid_size] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_left():
t1.setheading(180)
if t1.pos() - [grid_size, 0] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_down():
t1.setheading(270)
if t1.pos() - [0, grid_size] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_right():
t1.setheading(0)
if t1.pos() + [grid_size, 0] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
turtle.onkeypress(move_up, "w")
turtle.onkeypress(move_left, "a")
turtle.onkeypress(move_down, "s")
turtle.onkeypress(move_right, "d")
turtle.onkeypress(toggle_building, "Return")
turtle.listen()
python python-3.x turtle-graphics
The goal of this test code is to make a player that moves with W,A,S,D and starts or stops building a wall with the ENTER key. I would appreciate it if someone could tell me why he only sometimes collides with his walls. Feel free to critique my code in a general sense as well! Thanks in advance.
import turtle
grid_size = 10
t1 = turtle.Pen()
t1.width(grid_size)
t1.up()
walls = [[0,0]]
walls.clear()
def toggle_building():
if t1.isdown():
t1.up()
else:
t1.down()
def lay_brick():
if t1.isdown() and t1.pos() not in walls:
walls.append(t1.pos())
print("Brick layed.")
def print_pos():
print(t1.pos())
def move_up():
t1.setheading(90)
if t1.pos() + [0, grid_size] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_left():
t1.setheading(180)
if t1.pos() - [grid_size, 0] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_down():
t1.setheading(270)
if t1.pos() - [0, grid_size] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
def move_right():
t1.setheading(0)
if t1.pos() + [grid_size, 0] not in walls:
t1.forward(grid_size)
lay_brick()
else:
print("wall")
print_pos()
turtle.onkeypress(move_up, "w")
turtle.onkeypress(move_left, "a")
turtle.onkeypress(move_down, "s")
turtle.onkeypress(move_right, "d")
turtle.onkeypress(toggle_building, "Return")
turtle.listen()
python python-3.x turtle-graphics
python python-3.x turtle-graphics
asked Nov 19 '18 at 21:14
user9694049user9694049
132
132
Ispos()
a floating-point number?
– Robert Harvey♦
Nov 19 '18 at 21:15
If I'm not mistaken, pos() returns a Vec2D with two floating points, like so: [20.00, 10.00] @RobertHarvey
– user9694049
Nov 19 '18 at 21:17
Floating point numbers cannot be reliably compared using equals. Granted, it shouldn't matter if you're storingpos()
directly, but you are doing some arithmetic there, so.
– Robert Harvey♦
Nov 19 '18 at 21:18
Thank you @RobertHarvey ! I added some code to convert the floating points into ints and then append them to the list, plus some code to make sure the ints are always multiples of 10.
– user9694049
Nov 19 '18 at 21:58
add a comment |
Ispos()
a floating-point number?
– Robert Harvey♦
Nov 19 '18 at 21:15
If I'm not mistaken, pos() returns a Vec2D with two floating points, like so: [20.00, 10.00] @RobertHarvey
– user9694049
Nov 19 '18 at 21:17
Floating point numbers cannot be reliably compared using equals. Granted, it shouldn't matter if you're storingpos()
directly, but you are doing some arithmetic there, so.
– Robert Harvey♦
Nov 19 '18 at 21:18
Thank you @RobertHarvey ! I added some code to convert the floating points into ints and then append them to the list, plus some code to make sure the ints are always multiples of 10.
– user9694049
Nov 19 '18 at 21:58
Is
pos()
a floating-point number?– Robert Harvey♦
Nov 19 '18 at 21:15
Is
pos()
a floating-point number?– Robert Harvey♦
Nov 19 '18 at 21:15
If I'm not mistaken, pos() returns a Vec2D with two floating points, like so: [20.00, 10.00] @RobertHarvey
– user9694049
Nov 19 '18 at 21:17
If I'm not mistaken, pos() returns a Vec2D with two floating points, like so: [20.00, 10.00] @RobertHarvey
– user9694049
Nov 19 '18 at 21:17
Floating point numbers cannot be reliably compared using equals. Granted, it shouldn't matter if you're storing
pos()
directly, but you are doing some arithmetic there, so.– Robert Harvey♦
Nov 19 '18 at 21:18
Floating point numbers cannot be reliably compared using equals. Granted, it shouldn't matter if you're storing
pos()
directly, but you are doing some arithmetic there, so.– Robert Harvey♦
Nov 19 '18 at 21:18
Thank you @RobertHarvey ! I added some code to convert the floating points into ints and then append them to the list, plus some code to make sure the ints are always multiples of 10.
– user9694049
Nov 19 '18 at 21:58
Thank you @RobertHarvey ! I added some code to convert the floating points into ints and then append them to the list, plus some code to make sure the ints are always multiples of 10.
– user9694049
Nov 19 '18 at 21:58
add a comment |
1 Answer
1
active
oldest
votes
As noted in the comments to your question, the turtle wanders a floating point plane and even though you believe it has returned to the exact same spot as before, there's always a little bit of floating point noise added to the location. Converting positions to int
for comparison definitely helps but may not be sufficient.
Below is my attempt to make this robust by changing the coordinate system itself so it appears we're moving by 1 instead of 10. It also attempts to reduce the number of places the floating point to integer conversion needs to occur:
from turtle import Screen, Turtle
GRID_SIZE = 10
def toggle_building():
if turtle.isdown():
turtle.penup()
else:
turtle.pendown()
def lay_brick(position):
if turtle.isdown():
walls.add(position)
def move_up():
turtle.setheading(90)
position = int(turtle.xcor()), int(turtle.ycor()) + 1
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_left():
turtle.setheading(180)
position = int(turtle.xcor()) - 1, int(turtle.ycor())
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_down():
turtle.setheading(270)
position = int(turtle.xcor()), int(turtle.ycor()) - 1
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_right():
turtle.setheading(0)
position = int(turtle.xcor()) + 1, int(turtle.ycor())
if position not in walls:
turtle.goto(position)
lay_brick(position)
screen = Screen()
WIDTH, HEIGHT = (screen.window_width() / 2) // GRID_SIZE, (screen.window_height() / 2) // GRID_SIZE
screen.setworldcoordinates(-WIDTH, -HEIGHT, WIDTH, HEIGHT)
turtle = Turtle()
turtle.width(GRID_SIZE)
turtle.fillcolor('red')
turtle.penup()
walls = set()
screen.onkeypress(move_up, "w")
screen.onkeypress(move_left, "a")
screen.onkeypress(move_down, "s")
screen.onkeypress(move_right, "d")
screen.onkeypress(toggle_building, "Return")
screen.listen()
screen.mainloop()
It also uses a set
to contain the walls. Since order doesn't matter, this will make the test faster.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53382728%2fpython-turtle-collision-detection-via-not-in-list-why-doesnt-it-work%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
As noted in the comments to your question, the turtle wanders a floating point plane and even though you believe it has returned to the exact same spot as before, there's always a little bit of floating point noise added to the location. Converting positions to int
for comparison definitely helps but may not be sufficient.
Below is my attempt to make this robust by changing the coordinate system itself so it appears we're moving by 1 instead of 10. It also attempts to reduce the number of places the floating point to integer conversion needs to occur:
from turtle import Screen, Turtle
GRID_SIZE = 10
def toggle_building():
if turtle.isdown():
turtle.penup()
else:
turtle.pendown()
def lay_brick(position):
if turtle.isdown():
walls.add(position)
def move_up():
turtle.setheading(90)
position = int(turtle.xcor()), int(turtle.ycor()) + 1
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_left():
turtle.setheading(180)
position = int(turtle.xcor()) - 1, int(turtle.ycor())
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_down():
turtle.setheading(270)
position = int(turtle.xcor()), int(turtle.ycor()) - 1
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_right():
turtle.setheading(0)
position = int(turtle.xcor()) + 1, int(turtle.ycor())
if position not in walls:
turtle.goto(position)
lay_brick(position)
screen = Screen()
WIDTH, HEIGHT = (screen.window_width() / 2) // GRID_SIZE, (screen.window_height() / 2) // GRID_SIZE
screen.setworldcoordinates(-WIDTH, -HEIGHT, WIDTH, HEIGHT)
turtle = Turtle()
turtle.width(GRID_SIZE)
turtle.fillcolor('red')
turtle.penup()
walls = set()
screen.onkeypress(move_up, "w")
screen.onkeypress(move_left, "a")
screen.onkeypress(move_down, "s")
screen.onkeypress(move_right, "d")
screen.onkeypress(toggle_building, "Return")
screen.listen()
screen.mainloop()
It also uses a set
to contain the walls. Since order doesn't matter, this will make the test faster.
add a comment |
As noted in the comments to your question, the turtle wanders a floating point plane and even though you believe it has returned to the exact same spot as before, there's always a little bit of floating point noise added to the location. Converting positions to int
for comparison definitely helps but may not be sufficient.
Below is my attempt to make this robust by changing the coordinate system itself so it appears we're moving by 1 instead of 10. It also attempts to reduce the number of places the floating point to integer conversion needs to occur:
from turtle import Screen, Turtle
GRID_SIZE = 10
def toggle_building():
if turtle.isdown():
turtle.penup()
else:
turtle.pendown()
def lay_brick(position):
if turtle.isdown():
walls.add(position)
def move_up():
turtle.setheading(90)
position = int(turtle.xcor()), int(turtle.ycor()) + 1
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_left():
turtle.setheading(180)
position = int(turtle.xcor()) - 1, int(turtle.ycor())
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_down():
turtle.setheading(270)
position = int(turtle.xcor()), int(turtle.ycor()) - 1
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_right():
turtle.setheading(0)
position = int(turtle.xcor()) + 1, int(turtle.ycor())
if position not in walls:
turtle.goto(position)
lay_brick(position)
screen = Screen()
WIDTH, HEIGHT = (screen.window_width() / 2) // GRID_SIZE, (screen.window_height() / 2) // GRID_SIZE
screen.setworldcoordinates(-WIDTH, -HEIGHT, WIDTH, HEIGHT)
turtle = Turtle()
turtle.width(GRID_SIZE)
turtle.fillcolor('red')
turtle.penup()
walls = set()
screen.onkeypress(move_up, "w")
screen.onkeypress(move_left, "a")
screen.onkeypress(move_down, "s")
screen.onkeypress(move_right, "d")
screen.onkeypress(toggle_building, "Return")
screen.listen()
screen.mainloop()
It also uses a set
to contain the walls. Since order doesn't matter, this will make the test faster.
add a comment |
As noted in the comments to your question, the turtle wanders a floating point plane and even though you believe it has returned to the exact same spot as before, there's always a little bit of floating point noise added to the location. Converting positions to int
for comparison definitely helps but may not be sufficient.
Below is my attempt to make this robust by changing the coordinate system itself so it appears we're moving by 1 instead of 10. It also attempts to reduce the number of places the floating point to integer conversion needs to occur:
from turtle import Screen, Turtle
GRID_SIZE = 10
def toggle_building():
if turtle.isdown():
turtle.penup()
else:
turtle.pendown()
def lay_brick(position):
if turtle.isdown():
walls.add(position)
def move_up():
turtle.setheading(90)
position = int(turtle.xcor()), int(turtle.ycor()) + 1
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_left():
turtle.setheading(180)
position = int(turtle.xcor()) - 1, int(turtle.ycor())
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_down():
turtle.setheading(270)
position = int(turtle.xcor()), int(turtle.ycor()) - 1
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_right():
turtle.setheading(0)
position = int(turtle.xcor()) + 1, int(turtle.ycor())
if position not in walls:
turtle.goto(position)
lay_brick(position)
screen = Screen()
WIDTH, HEIGHT = (screen.window_width() / 2) // GRID_SIZE, (screen.window_height() / 2) // GRID_SIZE
screen.setworldcoordinates(-WIDTH, -HEIGHT, WIDTH, HEIGHT)
turtle = Turtle()
turtle.width(GRID_SIZE)
turtle.fillcolor('red')
turtle.penup()
walls = set()
screen.onkeypress(move_up, "w")
screen.onkeypress(move_left, "a")
screen.onkeypress(move_down, "s")
screen.onkeypress(move_right, "d")
screen.onkeypress(toggle_building, "Return")
screen.listen()
screen.mainloop()
It also uses a set
to contain the walls. Since order doesn't matter, this will make the test faster.
As noted in the comments to your question, the turtle wanders a floating point plane and even though you believe it has returned to the exact same spot as before, there's always a little bit of floating point noise added to the location. Converting positions to int
for comparison definitely helps but may not be sufficient.
Below is my attempt to make this robust by changing the coordinate system itself so it appears we're moving by 1 instead of 10. It also attempts to reduce the number of places the floating point to integer conversion needs to occur:
from turtle import Screen, Turtle
GRID_SIZE = 10
def toggle_building():
if turtle.isdown():
turtle.penup()
else:
turtle.pendown()
def lay_brick(position):
if turtle.isdown():
walls.add(position)
def move_up():
turtle.setheading(90)
position = int(turtle.xcor()), int(turtle.ycor()) + 1
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_left():
turtle.setheading(180)
position = int(turtle.xcor()) - 1, int(turtle.ycor())
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_down():
turtle.setheading(270)
position = int(turtle.xcor()), int(turtle.ycor()) - 1
if position not in walls:
turtle.goto(position)
lay_brick(position)
def move_right():
turtle.setheading(0)
position = int(turtle.xcor()) + 1, int(turtle.ycor())
if position not in walls:
turtle.goto(position)
lay_brick(position)
screen = Screen()
WIDTH, HEIGHT = (screen.window_width() / 2) // GRID_SIZE, (screen.window_height() / 2) // GRID_SIZE
screen.setworldcoordinates(-WIDTH, -HEIGHT, WIDTH, HEIGHT)
turtle = Turtle()
turtle.width(GRID_SIZE)
turtle.fillcolor('red')
turtle.penup()
walls = set()
screen.onkeypress(move_up, "w")
screen.onkeypress(move_left, "a")
screen.onkeypress(move_down, "s")
screen.onkeypress(move_right, "d")
screen.onkeypress(toggle_building, "Return")
screen.listen()
screen.mainloop()
It also uses a set
to contain the walls. Since order doesn't matter, this will make the test faster.
answered Nov 20 '18 at 1:37
cdlanecdlane
18.6k21144
18.6k21144
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53382728%2fpython-turtle-collision-detection-via-not-in-list-why-doesnt-it-work%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Is
pos()
a floating-point number?– Robert Harvey♦
Nov 19 '18 at 21:15
If I'm not mistaken, pos() returns a Vec2D with two floating points, like so: [20.00, 10.00] @RobertHarvey
– user9694049
Nov 19 '18 at 21:17
Floating point numbers cannot be reliably compared using equals. Granted, it shouldn't matter if you're storing
pos()
directly, but you are doing some arithmetic there, so.– Robert Harvey♦
Nov 19 '18 at 21:18
Thank you @RobertHarvey ! I added some code to convert the floating points into ints and then append them to the list, plus some code to make sure the ints are always multiples of 10.
– user9694049
Nov 19 '18 at 21:58