How can I pause a Timer being used in SwiftUI? - swiftui

I have this function that changes the centerLocation of the map, this causes the map to animate over all the locations. The lat and longitude are being incremented and decremented and repeats with the use of a timer. However I am currently trying to pause the timer. I have tried multiple methods and can't seem to get the timer to pause for a few seconds and resume. The only thing that works is using sleep, but that causes the whole UI to pause. This 'move' function is updating an #State CLLocationCoordinate's lat and long. This method is called in .onAppear().
timer.fire() does not work
I also tried something like this:
timer.invalidate()
DispatchQueue.main.asyncAfter(deadline: .now() + 5.00) {
timer.fire()
}
Code above does not work
func moveRegion() {
var currentLatitude = region.center.latitude
var currentLongitude = region.center.longitude
let increment = 0.25
var southAmerica = false
var europe = false
var australia = false
var america = true
Timer.scheduledTimer(withTimeInterval: (1.0/30.0), repeats: true) { (timer) in
//AMERICA CORD 37.0000, -95.000
//MOVING TO SOUTH AMERICA
//SOUTH AMERICA CORD -33.000, -70.000
if (america == true && southAmerica == false && europe == false && australia == false){
if (currentLatitude <= -33.000 && currentLatitude >= 37.0000 || currentLongitude <= -70.0000 && currentLongitude >= -95.0000 || currentLongitude >= -101.69999999998991) {
currentLatitude -= increment
currentLatitude -= increment
currentLatitude -= increment
if currentLongitude < -70.00 {
currentLongitude += increment
}
}
if (currentLatitude == -38.15000000000002 || currentLatitude <= -38.150000000000006 && currentLongitude <= -69.95000000000142){
// sleep(5), works but pauses whole UI
timer.invalidate()
Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { pauseTimer in
timer.fire()
print(timer.isValid)
}
southAmerica = true
australia = false
america = false
europe = false
}
}
//MOVING TO EUROPE
//Europe CORD 48.000, 15.000
//if (currentLongitude > -74.00 && currentLongitude < -4.00)
if (southAmerica == true && australia == false && america == false && europe == false ){
if (currentLatitude > -39.000 && currentLatitude < 55.000 || currentLongitude > -70.00 && currentLongitude < 16.000) {
currentLongitude += increment
currentLongitude += increment
currentLatitude += increment
currentLatitude += increment
}
if (currentLatitude >= 48.04999999999936 || currentLatitude == 48.04999999999937 && currentLongitude <= 16.249999999996835){
sleep(5)
europe = true
southAmerica = false
australia = false
america = false
}
}
//MOVING TO AUSTRALIA
//AUSTRALIA CORD -36.000, 133.000
if (europe == true && southAmerica == false && australia == false && america == false){
if (currentLongitude > 9.00 && currentLongitude < 133.000) {
currentLongitude += increment
currentLongitude += increment
currentLongitude += increment
}
if (currentLatitude >= -38.000 && currentLatitude <= 49.0000){
currentLatitude -= increment
currentLatitude -= increment
}
if (currentLatitude <= -37.05000000000008 && currentLongitude >= 132.04999999999274){
sleep(5)
australia = true
southAmerica = false
europe = false
america = false
}
}
//MOVING TO AMERIA
if (australia == true && southAmerica == false && america == false && europe == false){
if (currentLongitude < 179.55){
currentLongitude += increment
currentLongitude += increment
if (currentLongitude > 179.500){
currentLongitude = -179.000
}
}
if (currentLongitude > -95.100) {
currentLongitude += increment
currentLongitude += increment
}
if (currentLatitude >= -39.000 && currentLatitude <= 37.0000){
currentLatitude += increment
currentLatitude += increment
}
if (currentLatitude >= 37.04999999999998 && currentLongitude >= -95.100){
australia = false
southAmerica = false
europe = false
america = true
currentLatitude = 37.0000
currentLongitude = -95.000
sleep(5)
}
}
region.center.longitude = currentLongitude
region.center.latitude = currentLatitude
centerLocation.latitude = currentLatitude
centerLocation.longitude = currentLongitude
}
}
Then in the view
var body: some View {
SwiftUIMapView(centerLocation: $centerLocation)
.onAppear {
DispatchQueue.main.async {
moveRegion()
}
}
}
Here is the full code bellow:
import SwiftUI
import MapKit
struct MapView: View {
var timer = Timer()
//Start Location of the Map
#State var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 37.0000, longitude: -95.000),
span: MKCoordinateSpan(latitudeDelta: 40, longitudeDelta: 40)
)
#State var centerLocation = CLLocationCoordinate2D()
func moveRegion() {
var currentLatitude = region.center.latitude
var currentLongitude = region.center.longitude
let increment = 0.25
var southAmerica = false
var europe = false
var australia = false
var america = true
Timer.scheduledTimer(withTimeInterval: (1.0/30.0), repeats: true) { (timer) in
//AMERICA CORD 37.0000, -95.000
//MOVING TO SOUTH AMERICA
//SOUTH AMERICA CORD -33.000, -70.000
if (america == true && southAmerica == false && europe == false && australia == false){
if (currentLatitude <= -33.000 && currentLatitude >= 37.0000 || currentLongitude <= -70.0000 && currentLongitude >= -95.0000 || currentLongitude >= -101.69999999998991) {
currentLatitude -= increment
currentLatitude -= increment
currentLatitude -= increment
if currentLongitude < -70.00 {
currentLongitude += increment
}
}
if (currentLatitude == -38.15000000000002 || currentLatitude <= -38.150000000000006 && currentLongitude <= -69.95000000000142){
// sleep(5), works but pauses whole UI
timer.invalidate()
Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { pauseTimer in
timer.fire()
print(timer.isValid)
}
southAmerica = true
australia = false
america = false
europe = false
}
}
//MOVING TO EUROPE
//Europe CORD 48.000, 15.000
//if (currentLongitude > -74.00 && currentLongitude < -4.00)
if (southAmerica == true && australia == false && america == false && europe == false ){
if (currentLatitude > -39.000 && currentLatitude < 55.000 || currentLongitude > -70.00 && currentLongitude < 16.000) {
currentLongitude += increment
currentLongitude += increment
currentLatitude += increment
currentLatitude += increment
}
if (currentLatitude >= 48.04999999999936 || currentLatitude == 48.04999999999937 && currentLongitude <= 16.249999999996835){
sleep(5)
europe = true
southAmerica = false
australia = false
america = false
}
}
//MOVING TO AUSTRALIA
//AUSTRALIA CORD -36.000, 133.000
if (europe == true && southAmerica == false && australia == false && america == false){
if (currentLongitude > 9.00 && currentLongitude < 133.000) {
currentLongitude += increment
currentLongitude += increment
currentLongitude += increment
}
if (currentLatitude >= -38.000 && currentLatitude <= 49.0000){
currentLatitude -= increment
currentLatitude -= increment
}
if (currentLatitude <= -37.05000000000008 && currentLongitude >= 132.04999999999274){
sleep(5)
australia = true
southAmerica = false
europe = false
america = false
}
}
//MOVING TO AMERIA
if (australia == true && southAmerica == false && america == false && europe == false){
if (currentLongitude < 179.55){
currentLongitude += increment
currentLongitude += increment
if (currentLongitude > 179.500){
currentLongitude = -179.000
}
}
if (currentLongitude > -95.100) {
currentLongitude += increment
currentLongitude += increment
}
if (currentLatitude >= -39.000 && currentLatitude <= 37.0000){
currentLatitude += increment
currentLatitude += increment
}
if (currentLatitude >= 37.04999999999998 && currentLongitude >= -95.100){
australia = false
southAmerica = false
europe = false
america = true
currentLatitude = 37.0000
currentLongitude = -95.000
sleep(5)
}
}
region.center.longitude = currentLongitude
region.center.latitude = currentLatitude
centerLocation.latitude = currentLatitude
centerLocation.longitude = currentLongitude
}
}
var body: some View {
SwiftUIMapView(centerLocation: $centerLocation)
.onAppear {
DispatchQueue.main.async {
moveRegion()
}
}
}
}
Any help is greatly appreciated thank you!

Using Timer for this and trying to invalidate, re-fire, etc is going to be difficult (or in fact, impossible -- Timer can't re-fire once it is invalidated). But, this seemed like a pretty good opportunity to user Timer in a publisher with Combine and then just give it some intervals to wait out -- the publisher still fires events, it just doesn't do anything with them until the next wait interval has been hit:
struct ContentView : View {
var body: some View {
MapView()
}
}
class LocationManager : ObservableObject {
#Published var centerLocation = CLLocationCoordinate2D()
#Published var region : MKCoordinateRegion
private var currentLatitude : CLLocationDegrees
private var currentLongitude : CLLocationDegrees
init() {
let region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 37.0000, longitude: -95.000),
span: MKCoordinateSpan(latitudeDelta: 40, longitudeDelta: 40)
)
currentLatitude = region.center.latitude
currentLongitude = region.center.longitude
self.region = region
}
private var cancellable : AnyCancellable?
private var waitUntil : Date?
private var currentFireDate : Date = Date()
func start() {
cancellable = Timer.publish(every: (1.0/30.0), on: .main, in: .default)
.autoconnect()
.sink { val in
if let waitUntil = self.waitUntil {
if val < waitUntil {
return
} else {
self.waitUntil = nil
}
}
self.currentFireDate = val
self.moveRegion()
}
}
let increment = 0.25
var southAmerica = false
var europe = false
var australia = false
var america = true
func moveRegion() {
//AMERICA CORD 37.0000, -95.000
//MOVING TO SOUTH AMERICA
//SOUTH AMERICA CORD -33.000, -70.000
if (america == true && southAmerica == false && europe == false && australia == false){
if (currentLatitude <= -33.000 && currentLatitude >= 37.0000 || currentLongitude <= -70.0000 && currentLongitude >= -95.0000 || currentLongitude >= -101.69999999998991) {
currentLatitude -= increment
currentLatitude -= increment
currentLatitude -= increment
if currentLongitude < -70.00 {
currentLongitude += increment
}
}
if (currentLatitude == -38.15000000000002 || currentLatitude <= -38.150000000000006 && currentLongitude <= -69.95000000000142){
waitUntil = currentFireDate.addingTimeInterval(5.0)
southAmerica = true
australia = false
america = false
europe = false
}
}
//MOVING TO EUROPE
//Europe CORD 48.000, 15.000
//if (currentLongitude > -74.00 && currentLongitude < -4.00)
if (southAmerica == true && australia == false && america == false && europe == false ){
if (currentLatitude > -39.000 && currentLatitude < 55.000 || currentLongitude > -70.00 && currentLongitude < 16.000) {
currentLongitude += increment
currentLongitude += increment
currentLatitude += increment
currentLatitude += increment
}
if (currentLatitude >= 48.04999999999936 || currentLatitude == 48.04999999999937 && currentLongitude <= 16.249999999996835){
waitUntil = currentFireDate.addingTimeInterval(5.0)
europe = true
southAmerica = false
australia = false
america = false
}
}
//MOVING TO AUSTRALIA
//AUSTRALIA CORD -36.000, 133.000
if (europe == true && southAmerica == false && australia == false && america == false){
if (currentLongitude > 9.00 && currentLongitude < 133.000) {
currentLongitude += increment
currentLongitude += increment
currentLongitude += increment
}
if (currentLatitude >= -38.000 && currentLatitude <= 49.0000){
currentLatitude -= increment
currentLatitude -= increment
}
if (currentLatitude <= -37.05000000000008 && currentLongitude >= 132.04999999999274){
waitUntil = currentFireDate.addingTimeInterval(5.0)
australia = true
southAmerica = false
europe = false
america = false
}
}
//MOVING TO AMERIA
if (australia == true && southAmerica == false && america == false && europe == false){
if (currentLongitude < 179.55){
currentLongitude += increment
currentLongitude += increment
if (currentLongitude > 179.500){
currentLongitude = -179.000
}
}
if (currentLongitude > -95.100) {
currentLongitude += increment
currentLongitude += increment
}
if (currentLatitude >= -39.000 && currentLatitude <= 37.0000){
currentLatitude += increment
currentLatitude += increment
}
if (currentLatitude >= 37.04999999999998 && currentLongitude >= -95.100){
australia = false
southAmerica = false
europe = false
america = true
currentLatitude = 37.0000
currentLongitude = -95.000
waitUntil = currentFireDate.addingTimeInterval(5.0)
}
}
region.center.longitude = currentLongitude
region.center.latitude = currentLatitude
centerLocation.latitude = currentLatitude
centerLocation.longitude = currentLongitude
}
}
struct MapView: View {
#ObservedObject var locationManager = LocationManager()
var body: some View {
SwiftUIMapView(centerLocation: $locationManager.centerLocation)
.onAppear {
locationManager.start()
}
}
}
struct SwiftUIMapView : UIViewRepresentable {
#Binding var centerLocation : CLLocationCoordinate2D
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView()
return mapView
}
func updateUIView(_ uiView: MKMapView, context: Context) {
uiView.centerCoordinate = centerLocation
}
}
Here's what happens:
Location is now controlled by an ObservableObject LocationManager
On start(), a publisher that fires once every 1/30 seconds is fired
On each fire, it calls moveLocation()
When moveLocation wants to pause, it sets waitUntil 5 seconds ahead of the last date of the publisher firing
If the the publisher gets fired and the time is before waitUntil, it just returns and waits for the next fire

Related

I am getting a circular dependency error on power Bi when I put a calculation

KPI Value_3 Months =
VAR current_actual =
IF (ISBLANK ([Actual]), FALSE, TRUE)
VAR current_target =
IF (ISBLANK([Target]), FALSE, TRUE)
RETURN
IF(
current_target && current_target,
DIVIDE(CALCULATE(SUM(BI_SC_Perf_Measurement_Lvl2[Actual]),DATESINPERIOD(BI_SC_Perf_Measurement_Lvl2[Reporting_Period],LASTDATE(BI_SC_Perf_Measurement_Lvl2[Reporting_Period]),-3,MONTH))/3 ,
CALCULATE(SUM(BI_SC_Perf_Measurement_Lvl2[Target]),DATESINPERIOD(BI_SC_Perf_Measurement_Lvl2[Reporting_Period],LASTDATE(BI_SC_Perf_Measurement_Lvl2[Reporting_Period]),-3,MONTH))/3),
BLANK ()
)
and I am creating another column with the following code:
KPI Status_3 Months =
VAR _bottomthreshold2 = .55
VAR __middlethreshold2 = .75
VAR _topthreshold2 = 1
RETURN
SWITCH(
TRUE (),
[KPI Value_3 Months] < _bottomthreshold2, -1,
[KPI Value_3 Months] >= _bottomthreshold2
&& [KPI Value_3 Months] <= __middlethreshold2, 0,
[KPI Value_3 Months] > __middlethreshold2
&& [KPI Value_3 Months] < _topthreshold2, 1,
[KPI Value_3 Months] >= _topthreshold2, 2
)
I am getting this error "A circular dependency was detected: BI_SC_Perf_Measurement_Lvl2[KPI Value_3 Months], BI_SC_Perf_Measurement_Lvl2[KPI Color_3 Months], BI_SC_Perf_Measurement_Lvl2[KPI Status_3 Months], BI_SC_Perf_Measurement_Lvl2[KPI Value_3 Months]."

Exception based on condition on Apps Script in Google Sheet

With this script I can exclude to insert the same value column in Google Sheet for maximum 100 times.
But I am trying to exclude (with if statement) some values from this script, in particular the date "25/12/2022" and the date "12/01/2012".
How could I proceed?
function onEdit(e) {
var r = e.range;
var s = r.getSheet();
if (s.getName() === 'New Rise 2022' && r.getColumn() === 27) {
var newValue = r.getDisplayValue();
if (newValue == "") return;
var count = s.getRange('AA1:AA').getDisplayValues().filter(([a]) => a === newValue).length;
if (count > 99) {
r.setValue(e.oldValue);
SpreadsheetApp.flush();
SpreadsheetApp.getUi().alert('Questa data è stata già inserita 100 volte');
}
}
}
Update:
function onEdit(e) {
var r = e.range;
var s = r.getSheet();
if (s.getName() === 'New Rise 2022' && r.getColumn() === 27) {
var newValue = r.getDisplayValue();
if (newValue == "") return;
var count = s.getRange('AA1:AA').getDisplayValues().filter(([a]) => a === newValue).length;
if (count > 99 || e.range.getDisplayValue() == "25/12/2012" || e.range.getDisplayValue() == "12/01/2012") {
r.setValue(e.oldValue);
r.setNumberFormat('dd/mm/YYYY');
SpreadsheetApp.flush();
SpreadsheetApp.getUi().alert('Questa data è stata già inserita 100 volte');
}
}
}
How about this?
function onEdit(e) {
const sh = e.range.getSheet();
const x = ["25/12/2022","12/01/2012"];
const idx = x.indexOf(e.value);
if (sh.getName() === 'New Rise 2022' && e.range.columnStart == 27 && e.value && !~idx) {
var count = sh.getRange('AA1:AA' + sh.getLastRow()).getDisplayValues().flat().filter(e => e == e.value).length;
if (count > 99) {
e.range.setValue(e.oldValue);
}
}
}
You can get the newly entered display value and compare it against the "forbidden" values
Therefore, retrieve the latest modified cell with e.range:
...
if (count > 99 || e.range.getDisplayValue() == "25/12/2022" || e.range.getDisplayValue() == "12/01/2012") {
...
}
...
Note:
I understood that what you are interested in is the displayed value (date in this case), but depending on your date formatting the display value will be different from the value you typed in.
If it is the typed in value you are after, you can retrieve it with e.value:
...
console.log("e.value: " + e.value)
console.log("e.range.getDisplayValue(): " + e.range.getDisplayValue())
if (count > 99 || e.value == "25/12/2022" || e.value == "12/01/2012") {
...
}
...
References:
Event Objects
getDisplayValue()
UPDATE:
If you have problems with number formatting you can use the method setNumberFormat().
Modify your code block in the if statement to
r.setValue(e.oldValue);
r.setNumberFormat('dd/mm/YYYY');

Else If - Google Script

this script was working before on my Google Sheet, then all of a sudden, it stopped working. I notice that the first argument (if) is working, but all the codes after that is not working. Any ideas?
function onEdit(event) {
// assumes source data in sheet named Sheet1
// target sheet of move to named Sheet2
// test column with yes is col 7 or G
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Under Contract Response Form" && r.getColumn() == 7 && (r.getValue() == "Closed" || r.getValue() == "Expired" || r.getValue() == "Cancelled")) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Closed/Expired & Cancelled");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);
s.deleteRow(row);
} else if(s.getName() == "Listing Response Form" && r.getColumn() == 7 && r.getValue() == "Pending" ) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Under Contract Response Form");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);
s.deleteRow(row);
} else if(s.getName() == "Listing Response Form" && r.getColumn() == 7 && r.getValue() == "Cancelled" ) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Closed/Expired & Cancelled");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);
s.deleteRow(row);
} else if(s.getName() == "Under Contract Response Form" && r.getColumn() == 7 && (r.getValue() == "Pre-list" || r.getValue() == "Withheld" || r.getValue() == "Coming Soon" || r.getValue() == "Active")) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Listing Response Form");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);
s.deleteRow(row);
} else if(s.getName() == "Closed/Expired & Cancelled" && r.getColumn() == 7 && r.getValue() == "Pending" ) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Under Contract Response Form");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);
s.deleteRow(row);
}
}
The script looks fine, so chances are that one or more sheets has been renamed, or columns inserted or deleted. Check the sheet names and look for things like leading or trailing spaces. Also ensure that the values that should trigger row move appear in column G.
You can make row moves more robust by using column names instead of column numbers. See the moveRowsFromSpreadsheetToSpreadsheet_ script.

Coffeescript syntax issue with for statement

Using Coffeescript, I am trying to set conditionals for setting a fillColor on a graph plot for two variables; lastVisibility and curr_visibility. Something is not right with my syntax. Any suggestions
for set in datasets
line.push
data: set,
lines:
show: true
fill: true
opacity: 0.7
fillColor: if lastVisibilty == 0 & curr_visibility == 0
then "#C90E30"
else lastVisibilty == 0 & curr_visibility == 1
then "#439C32"
else lastVisibilty == 1 & curr_visibility == 0
then "#C90E30"
else
"#439C32"
There are lots of problems here:
You only use then when you're using a one-liner such as a = if b then c else d, if you're using the multi-line form of if then you don't use thens.
You have multiple else branches where you mean else if.
& and && are different things, & is a bit-wise operator, && is the logical conjunction you're looking for.
You need to be very careful and consistent with your indentation.
Applying those adjustments to your code you get:
for set in datasets
line.push
data: set,
lines:
show: true
fill: true
opacity: 0.7
fillColor: if lastVisibilty == 0 && curr_visibility == 0
"#C90E30"
else if lastVisibilty == 0 && curr_visibility == 1
"#439C32"
else if lastVisibilty == 1 && curr_visibility == 0
"#C90E30"
else
"#439C32"
However, the conditional logic inside your loop doesn't depend on set (i.e. is loop invariant) so you should factor that out:
fillColor = if lastVisibilty == 0 && curr_visibility == 0
"#C90E30"
else if lastVisibilty == 0 && curr_visibility == 1
"#439C32"
else if lastVisibilty == 1 && curr_visibility == 0
"#C90E30"
else
"#439C32"
for set in datasets
line.push
data: set,
lines:
show: true
fill: true
opacity: 0.7
fillColor: fillColor
Or better, push all the invariant stuff outside the loop to further clarify the code:
fillColor = if lastVisibilty == 0 && curr_visibility == 0
"#C90E30"
else if lastVisibilty == 0 && curr_visibility == 1
"#439C32"
else if lastVisibilty == 1 && curr_visibility == 0
"#C90E30"
else
"#439C32"
lines =
show: true
fill: true
opacity: 0.7
fillColor: fillColor
for set in datasets
line.push
data: set,
lines: lines
Or, since a for-loop is an expression, you could say:
fillColor = if lastVisibilty == 0 && curr_visibility == 0
"#C90E30"
else if lastVisibilty == 0 && curr_visibility == 1
"#439C32"
else if lastVisibilty == 1 && curr_visibility == 0
"#C90E30"
else
"#439C32"
lines =
show: true
fill: true
opacity: 0.7
fillColor: fillColor
line = ({ data: set, lines: line } for set in datasets)
Assuming that line is empty before your loop of course; if it isn't then you could use Array.prototype.concat:
line = line.concat({data: set, lines: line } for set in datasets)
to append the loop's data to line.

How to make a game over sequence for tic tac toe when there are no winners?

I would like to display a label that says game over when there are no winners. I just thought to make an else statement but once there is one click game over would be display since the elif statements are false. Any ideas.
from tkinter import*
#Window stuff
window = Tk()
window.title("Tic Tac Toe")
window.configure(background = "black")
window.geometry("400x400")
#Variables
global clickable
playerXturn = True
ticker = 0
#Display X or O
def buttonClicked(c) :
global playerXturn
if playerXturn == True :
buttonList[c]["image"] = picX
buttonList[c]["state"] = DISABLED
playerXturn = False
labelTurn ["text"] = "O's turn"
elif clickable[c] == "" :
buttonList[c]["image"] = picO
buttonList[c]["state"] = DISABLED
playerXturn = True
labelTurn ["text"] = "X's turn"
#Info for user
global ticker
ticker += 1
if ticker == 500 :
labelInfo["text"] = "Timed Out"
labelInfo["bg"] = "red"
#Three in a row
elif (button1["image"] == str(picX) and button2["image"] == str(picX) and button3["image"] == str(picX) or
button4["image"] == str(picX) and button5["image"] == str(picX) and button6["image"] == str(picX) or
button7["image"] == str(picX) and button8["image"] == str(picX) and button9["image"] == str(picX) or
button1["image"] == str(picX) and button4["image"] == str(picX) and button7["image"] == str(picX) or
button2["image"] == str(picX) and button5["image"] == str(picX) and button8["image"] == str(picX) or
button3["image"] == str(picX) and button6["image"] == str(picX) and button9["image"] == str(picX) or
button1["image"] == str(picX) and button5["image"] == str(picX) and button9["image"] == str(picX) or
button3["image"] == str(picX) and button5["image"] == str(picX) and button7["image"] == str(picX)) :
#print ("X")
labelInfo["text"] = "X Wins"
labelInfo["bg"] = "red"
button1["state"] = DISABLED
button2["state"] = DISABLED
button3["state"] = DISABLED
button4["state"] = DISABLED
button5["state"] = DISABLED
button6["state"] = DISABLED
button7["state"] = DISABLED
button8["state"] = DISABLED
button9["state"] = DISABLED
labelTurn ["bg"] = "black"
elif (button1["image"] == str(picO) and button2["image"] == str(picO) and button3["image"] == str(picO) or
button4["image"] == str(picO) and button5["image"] == str(picO) and button6["image"] == str(picO) or
button7["image"] == str(picO) and button8["image"] == str(picO) and button9["image"] == str(picO) or
button1["image"] == str(picO) and button4["image"] == str(picO) and button7["image"] == str(picO) or
button2["image"] == str(picO) and button5["image"] == str(picO) and button8["image"] == str(picO) or
button3["image"] == str(picO) and button6["image"] == str(picO) and button9["image"] == str(picO) or
button1["image"] == str(picO) and button5["image"] == str(picO) and button9["image"] == str(picO) or
button3["image"] == str(picO) and button5["image"] == str(picO) and button7["image"] == str(picO)) :
#print("O")
labelInfo["text"] = "O Wins"
labelInfo["bg"] = "red"
button1["state"] = DISABLED
button2["state"] = DISABLED
button3["state"] = DISABLED
button4["state"] = DISABLED
button5["state"] = DISABLED
button6["state"] = DISABLED
button7["state"] = DISABLED
button8["state"] = DISABLED
button9["state"] = DISABLED
labelTurn ["bg"] = "black"
#Images
picX = PhotoImage (file = "x.gif")
picO = PhotoImage (file = "o.gif")
picBlank = PhotoImage (file = "sw.gif")
#Buttons
button1 = Button (window, text = "", image = picBlank, command = lambda: buttonClicked(0))
button1.grid (row = 0, column = 0)
#button1["state"] = DISABLED
button2 = Button (window, text = "", image = picBlank, command = lambda: buttonClicked(1))
button2.grid (row = 0, column = 1)
#button2["state"] = DISABLED
button3 = Button (window, text = "", image = picBlank, command = lambda: buttonClicked(2))
button3.grid (row = 0, column = 2)
#button3["state"] = DISABLED
button4 = Button (window, text = "", image = picBlank, command = lambda: buttonClicked(3))
button4.grid (row = 1, column = 0)
#button4["state"] = DISABLED
button5 = Button (window, text = "", image = picBlank, command = lambda: buttonClicked(4))
button5.grid (row = 1, column = 1)
#button5["state"] = DISABLED
button6 = Button (window, text = "", image = picBlank, command = lambda: buttonClicked(5))
button6.grid (row= 1, column = 2)
#button6["state"] = DISABLED
button7 = Button (window, text = "", image = picBlank, command = lambda: buttonClicked(6))
button7.grid (row = 2, column = 0)
#button7["state"] = DISABLED
button8 = Button (window, text = "", image = picBlank, command = lambda: buttonClicked(7))
button8.grid (row = 2, column = 1)
#button8["state"] = DISABLED
button9 = Button (window, text = "", image = picBlank, command = lambda: buttonClicked(8))
button9.grid (row = 2, column = 2)
#button9["state"] = DISABLED
#Lists
buttonList = [button1, button2, button3, button4, button5, button6, button7, button8, button9]
clickable = ["", "", "", "", "", "", "", "", ""]
#Reset
def processReset():
button1["state"] = NORMAL
button2["state"] = NORMAL
button3["state"] = NORMAL
button4["state"] = NORMAL
button5["state"] = NORMAL
button6["state"] = NORMAL
button7["state"] = NORMAL
button8["state"] = NORMAL
button9["state"] = NORMAL
button1["image"] = picBlank
button2["image"] = picBlank
button3["image"] = picBlank
button4["image"] = picBlank
button5["image"] = picBlank
button6["image"] = picBlank
button7["image"] = picBlank
button8["image"] = picBlank
button9["image"] = picBlank
labelTurn["bg"] = "white"
labelInfo["text"] = "Continue Playing"
labelInfo["bg"] = "white"
#Extra labels and buttons
labelMenu = Label (window, text = "Menu and Info", height = 2, width = 24, bg = "yellow")
labelMenu.grid (row = 4, column = 4)
labelTurn = Label (window, text = "X goes first", height = 2, width = 10)
labelTurn.grid (row = 6, column = 4)
labelInfo = Label (window, text = "Continue Playing", height = 2, width = 14)
labelInfo.grid (row = 5, column = 4)
buttonReset = Button(window, text = "Reset/New Game", bg = "Orange", command = processReset)
buttonReset.grid (row = 7, column = 4)
labelNote = Label (window, text = "Note: Losing player goes first next game", bg = "Pink")
labelNote.grid (row = 8, column = 4)
window.mainloop()
You want an elif statement at the end of your else-if chain that checks whether there's any empty spaces left. If there's no spaces left, and a winner wasn't declared by one of the statements before this one, it's necessarily a tie.
Something like:
elif (check that no empty board spaces remain) :
#print("-")
labelInfo["text"] = "It's a tie!"