Tic Tac Toe (Lua (Touch Lua)) detecting 3 in a row? - lua

So I think I have a great setup, each "Button" has a column and row. Here's my current function:
function CheckForWin()
local X = {}
local O = {}
for i,v in pairs(ClosedButtons) do
if v.title == "X" then
table.insert(X, v)
elseif v.title == "O" then
table.insert(O, v)
end
for i,v in pairs(X) do
--Find 3 Xs in a row
end
for i,v in pairs(O) do
--Find 3 Os in a row
end
end
end
My question, is how should I detect?
A 3 in the row would occur if 3 buttons had the same row or column right? But the diagonal one would be a special case, it would be if 3 buttons had the same row and column in them?
Should I keep a table to check and see how many buttons have a column of 1/2/3 and a table to check how many buttons have a row of 1/2/3, and a table to see how many have the same row/column? To me that seems incredibly inefficient.
Is there a better way I should know before I start using a bunch of tables?
EDIT: Just to be clear, the buttons are tables with the properties "column" and "row"

To do this you would have to keep track of every row and column tiles, check for 3 in a row directly. Although inefficient I do not see any other way.

Related

Join two vertical arrays in certain order into new vertical array using a function/formula

For Google Sheets Specifically. I have two vertical arrays of data that I want to combine into one array, that uses first a data point from the first array, then all of the data from the second array, then it uses the next data point from the first array, then all of the data from the second array again, kind of repeating, for length of Array 1. The length of Array 1 and Array 2 can change overtime as data gets input. Example:
A (Length Unknown)
B (Length Unknown)
C (Desired)
A
1
A
B
2
1
C
3
2
D
...
3
...
B
...
1
2
3
C
1
2
3
D
1
2
3
Been trying to use transpose, flatten, split, join, rept, CountA(A:A), and such, etc but not been having much luck. I feel like there should be some type of formula for this.
You may try:
=lambda(z,filter(z,z<>""))(lambda(x,y,reduce(,sequence(counta(x)),lambda(a,c,{a;index(x,c);y})))(filter(A:A,A:A<>""),filter(B:B,B:B<>"")))
Incase new functions have rolled out for you; this works too:
=tocol(reduce(,sequence(counta(tocol(A:A,1))),lambda(a,c,{a;index(tocol(A:A,1),c);tocol(B:B,1)})),1)

Referencing a cell's row value using a formula

Suppose my excel sheet looks like this:
Name
Houses
Cars owned
column D
John
3
3
=A&MAX(30,3)
Harry
2
4
..
Vik
5
1
..
..
p
k
..
...
q
n
..
In column D, I want to return the row in column A that corresponds to the larger of the two values in cells B2 and C2. So in cell D2, I would want to return "Vik" because the larger of the two values in B2 (3) and C2 (3) is 3. And the value in cell A3 is Vik.
So in order to arrive at my result, I would input something like ="A"&MAX(B2,C2) in D2.
But suppose my formula was a lot more complex and with different data.
=IFERROR(ArrayFormula(ADDRESS(MAX(index(IF($A$1:$D6=B7,ROW($A$1:$D6),""),,IF($A$1:$D6=B7,COLUMN($A$1:$D6)),"")),MAX(IF($A$1:$D6=B7,COLUMN($A$1:$D6),"")))),"")
and I wanted the result of the first chunk of the formula (from ADDRESS() onwards)
MAX(index(IF($A$1:$D6=B7,ROW($A$1:$D6),"") (which is 3, say) to be the row number that is input into
MAX(IF($A$3:$D3=B7,COLUMN($A$1:$D6),"")) for the range inside the IF condition.
(notice how $A$1:$D6 changed to $A$3:$D6)
So, going by the tabular example above, I would simply input MAX(IF("$A$"&MAX(index(IF($A$1:$D6=B7,ROW($A$1:$D6),""):$D6=B7,COLUMN($A$1:$D6),"")) and that should do the trick. Except it doesn't and I get a formula parse error which I cannot resolve.
Here is the specific excel sheet I'm working on: https://docs.google.com/spreadsheets/d/12U8U7Jp4FscobIvgr4_sADJB_oSdIHrboCk02cxF_u0/edit?usp=sharing
Can anyone see what I'm doing wrong? The solution, I think, should be simple enough but I can't seem to figure it out.
Sorry if it's a bit long but I've been struggling with this for a while now.
I hope this formula will help
=ARRAYFORMULA(IFNA(VLOOKUP(QUERY(TRANSPOSE(QUERY(TRANSPOSE(B2:C6);"select "&JOIN(",";"max(Col"&row(B2:C6)-1&")")));"select Col2+1 label Col2+1''");{row(A:A)\A:A};2;False)))
Solved using the indirect function and ampersand concatenation.
New function would be: =IFERROR(ArrayFormula(ADDRESS(MAX(index(IF($A$1:$D6=B7,ROW($A$1:$D6),""),,IF($A$1:$D6=B7,COLUMN($A$1:$D6),""))),MAX(IF(INDIRECT("$A$"&(MAX(index(IF($A$1:$D6=B7,ROW($A$1:$D6),""))))):$D6=B7,COLUMN($A$1:$D6),"")))),"")

Multiple queries by date in the same row in google sheets

I need to sum the daily sales of each product ASIN. Sounds easy but I can`t do it.
On the left, you can see the data. At the right, the empty table that I need to create.
use:
=QUERY(K2:M; "select K,sum(M) where M is not null group by K pivot L")
Use an IF statement on the columns that you want summed.
For your example, it would be something like this:
in Cell P2
=IF($L2 = P$1, $M2, 0)
This translates to
If ((the text in column L row 2 = the text in p1), take the units from column m row 2, else take 0)
The $ are there to indicate you always want that column/row. So we always want to evaluate column L at the start and Row 1 in the comparison.
Then at the last row of the sheet you have a SUM function for the column
=SUM(P2:P100)
or whatever the end is
Working example here: https://docs.google.com/spreadsheets/d/1zhQMV6o1tF2P_kWbXDPdnVKzYnd-Dsvg2h7YiHWSaNI/edit?usp=sharing

calculate value string that is in a list

Data:
Row A
House;Farm;Zoo
House;Farm
House, Zoo
Row B
Dog;Cat;Lamb;Tiger
Dog;Bunny;Chicken,Fish
Lizard;Cat;Cow
Table 1
House
Dog
Cat
Mouse
Fish
Chicken
Table 2
Zoo
Tiger
Bear
Seal
Table 3
Farm
Bunny
Duck
Lamb
Cow
Horse
Question In Google Sheets
Ok I am trying to figure out how to calc the Column A based on what string is in the Column B The definition of what is in the B Column comes form the three tables in the bottom. Any help would be wonderful!
So here is one way. In some other region of the table, from which you will copy column A at the end, set up the following expression for each row, starting in column B. I am imagining your =original list with column A to be calculated starts in row 1 (so B1 is dog, C1 is cat, and so on).
Suppose your 3 tables sit in rows 6 to 8.
Some rows below, in column A, paste the following:
=IF(ISBLANK(B1),"",IFERROR(QUERY($A$6:$F$8,"Select A where "&"(B = '"&B1&"') OR " & "(C= '"&B1&"') OR "& "(D= '"&B1&"') OR "& "(E= '"&B1&"') OR (F='"&B1&"')")))
Let me unpack that. If the entry is blank, we will leave the corresponding item empty. Similarly, if our query fails, leave it blank. But the query says look in the tables, find the match, and give us the corresponding column A value.
Drag this formula right 3 more columns for a total of 4, which is the longest length of animal list we're trying to cover. You end up with the corresponding places (if any), cell by cell. Also drag this formula down 2 more columns so you get each row.
Clinch by doing the following one column further over. I was in row 10, your row may vary.:
=textjoin(";",true,transpose(unique(transpose(A10:D10))))
this puts togethjer a list of the unique, noempty, values, separated by semicolons.
Drag this down 2 columns, and then go back let you A1=the top corresponding entry, drag down, and you're set.
EDIT: The above assumes Dog, Cat, Lamb, and Tiger are spread across cells in columns B, C, D, and E. If not and they are in just one cell, you may need something like in the C column =split(B1,";") and to adjust columns in my formulas over by 1.

How to find the first cell in a row where value is not empty and check if the number is less or equal the number in other cell

I've got the following Google spreadsheet:
item have ready need1 need2 need3
A 1 2 1
B 1 2 1 1
C 2 2
etc
I want to fill ready column as follows:
find the first column in need1, ..., needN range which has a non-empty value
if the value found is less or equals the value in have column, set ready column to something cheerful (e.g. yes)
if the value found is larger than the value in have column, don't do anything
So above input, when processed should look like this:
item have ready need1 need2 need3
A 1 2 1
B 1 2 1 1
C 2 yes 2
For the first step I found a suggested solution, which did not work for me:
=INDEX( SORT( FILTER( D10:H10 , LEN( D10:H10 ) ) ,
FILTER( COLUMN( D10:H10 ) , LEN( D10:H10 ) ) , 0 ) , 1 )
(it returns #REF!) Not sure what's wrong with it or how to proceed to the next step.
Thanks in advance!
If you know how many need columns you have, or even just how many columns are on the sheet, this is quite straightforward. If not and you need to look at the entire row, you might have to redesign a bit to avoid a circular reference from the cell with the formula being part of that row.
Your second two steps are fairly simple either way - you want one of two results based on a condition, so you're going to want to use =IF. Your condition is that the 'need' number is less than or equal to the 'have' number, and you want it to say 'yes' if that's true, and nothing if it isn't. So, that gives us:
=IF(need<=have, "Yes", "")
The examples below assume your table above starts from cell A1 in the top left, and that the last column in your sheet is Z
Next we need to find 'need' and 'have'. Finding 'have' is pretty easy - it's just the number in column B.
Finding 'need' is slightly more complicated. You've got the right idea using INDEX and FILTER, but your formula seems a little overcomplicated. Basically we can use FILTER to filter out the blank values, and INDEX to find the first one that is left. First, FILTER:
The range you want to filter from is everything in the same row from column D to column Z (or whatever the final column is), and the condition you want to filter for is that those same cells are not blank. For the formula you're typing into cell C2, that gives us:
=FILTER(D2:Z2, D2:Z2<>"")
Next, INDEX: If you give INDEX an array, a row number, and a column number, it will tell you what is at that the cell where that row and column meet. As we've filtered out the blanks, we just want whatever is left in the first column of our filtered array, which gives us:
=INDEX(FILTER(D2:Z2, D2:Z2<>""), 1, 1)
Or, as we only have one row in our array, and INDEX is pretty smart, simply:
=INDEX(FILTER(D2:Z2, D2:Z2<>""), 1)
So to bring it all together, our final formula for cell C2 is:
=IF(INDEX(FILTER(D2:Z2, D2:Z2<>""), 1)<=B2, "Yes", "")
Then just drag the formula down for as many rows as you need. If your sheet is or becomes wider, just change Z to whatever your last column is.
When you don't know the size of a range, use functions row, column, rows, columns.
Simple formula
Here's an example of what you are looking:
=if(INDEX(FILTER(OFFSET(D2,,,1,COLUMNS(1:1)-column(D2)+1),OFFSET(D2,,,1,COLUMNS(1:1)-column(D2)+1)<>""),1)<=B2,"yes","")
this part of formula:
OFFSET(D2,,,1,COLUMNS(1:1)-column(D2)+1)
returns the range starting from given cell (D2) to the end of Sheet (COLUMNS(1:1)-column(D2)+1)
ArrayFormula
I suggest using ArrayFormula, it'll expand automatically:
=ARRAYFORMULA(if(REGEXEXTRACT(SUBSTITUTE(trim(transpose(query(transpose(OFFSET(D2,,,COUNTA(A2:A),COLUMNS(1:1)-column(D2)+1)),,COLUMNS(OFFSET(D2,,,COUNTA(A2:A),COLUMNS(1:1)-column(D2)+1)))))," ",", "),"\d+")*1<=OFFSET(B2,,,COUNTA(A2:A)),"yes",""))
It assumes that 'Item' column has no blank values.
The solution from #Max Makhrov works, and has the advantage of using a single formula for the whole column.
However, it assumes that all of your columns at the right from your ready column (D) will be need_ columns.
The solution from #dmusgrave also works, provided you remove the extra "=" before INDEX:
=IF(INDEX(FILTER(D2:Z2,D2:Z2<>""),1)<=B2,"Yes","").
However, it makes the same assumption, and also limits at column Z.
Such assumptions seem reasonable, but if they are limiting you, here's how you can have any number of need_ columns starting right of your ready column:
=IF(INDEX(FILTER(INDIRECT( "D"&ROW()&":"&CHAR(67+COLUMNS(FILTER($1:$1,LEFT($1:$1, 4)="need")))&row() ), INDIRECT( "D"&ROW()&":"&CHAR(67+COLUMNS(FILTER($1:$1,LEFT($1:$1,4)="need")))&row() )<>""),1)<=B2,"Yes","")
The idea is simply to replace D2:Z2 (in #dmusgrave's solution) by :
INDIRECT( "D"&ROW()&":"&CHAR(67+COLUMNS(FILTER($1:$1,LEFT($1:$1, 4)="need")))&row() )
Explanation: You start from D at current row, and you go until the last need_ column on the same current row.
CHAR(68) is D, to which you add the number of columns titled need.*, minus one (hence the 67).
Using the same logic, you can easily make your formula more robust/generic, such as not having the need_ columns starting right form the ready column, etc.

Resources