Chess bitboard move generation - chess

I am writing a chess engine, and I'm understanding how chess engines store game positions (in 64-bit bitboards) and how to generate moves from them. When you get your final bitboard of moves, how do you know what piece moves where? For example, take a white knight. You can easily bitshift the white knight bitboard to get the squares the knight/s would move to, and then use other binary operators to make sure that those squares are not occupied by your own pieces and the knight did not move out of bounds.
If this is the white knight bitboard:
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0
0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0
you can figure out that these are the legal moves (assuming there are no friendly pieces on the squares but they are irrelevant for this example)
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 1 0 1 0 0 0 0
1 0 1 0 1 0 0 0
0 0 * 1 0 0 0 0
1 * 0 0 1 0 0 0
0 1 0 1 0 0 0 0
(*s are used for the knight's positions, just so it's easier to visualize).
Now that you know that a knight can move to e2, what does that do? How do you know which white knight. How do you know that both white knights could move to d1? The binary and bitboard operators are used because they are very efficient, but I cannot see how they help getting a final list of legal moves.

I do this by storing an array of 64-bit unsigned integers that contains attack maps for knights on each square of the chessboard:
uint64_t knight_attacks[64];
This array can be populated when the program starts. In this array index 0 represents A1 and index 63 represents H8. So:
knight_attacks[0]: knight_attacks[9]: knight_attacks[18]
(Knight on A1) (Knight on B2) (Knight on C3)
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0
0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 * 0 0 0 0 0
0 0 1 0 0 0 0 0 0 * 0 0 0 0 0 0 1 0 0 0 1 0 0 0
* 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0
And then you have your knight bitboard knight_bb:
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0
0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0
You will require some sort of pop LSB function, i.e., a function that returns the position of the least significant bit in a bitboard and then zeros the bit.
Square square_of_first_knight = pop_LSB(&knight_bb);
This will return 9 (the index of square B2), now you can get all of the squares attacked by this knight from the look up table:
uint64_t knight_attack_bb = knight_attacks[square_of_first_knight];
Now you can pop all of the bits out of the knight_attack_bb (using pop_LSB and pair them with the knight square to make up your moves:
Squares_idx Algebraic
9, 3 B2, D1 1st call: pop_LSB(&atk_bb) returns 3
9, 19 B2, D3 2nd call: pop_LSB(&atk_bb) returns 19
9, 24 B2, A4 3rd call: pop_LSB(&atk_bb) returns 24
9, 26 B2, C4 4th call: pop_LSB(&atk_bb) returns 26
At this point, all of the bits have been popped out of atk_bb so it equals zero. You can use this as a check for when to stop popping bits.
You now repeat this process for the second knight, and you will get a list of (from, to) pairs for all the knight moves.

When you generate moves you go through each bit in e.g. the knights bitboard. You will then store both the knight bit (start square) and each possible square it can move to (end square) which will get you all legal moves for the piece. I usually store the information either as an object or encode it as a bit number.
During move generation you will also store other information about the move such as if it is a capture move, castling, e.p. etc. Basically any information that is cheap and helpful/needed in later stages of your AI.
I think this is what you are looking for. I also suggest looking at the really nice serie from Code Monkey King about chess programming, if you aren't writing in C you can still get the concepts pretty easily from it. I used it as a guide for both my Python and C# engine.

Related

Seminar Scheduling Problem Modeling - Julia

I am trying to learn Julia with optimization problems. I tried to solve a scheduling problem.
Here is the question that I want to solve with Cbc library.
- There are 6 time periods, 10 seminar, 5 speaker, 15 audience, and 4 conference room.
Which speaker offer which seminar is given as a matrix (5x10) Speaker, and which audience will participate in which seminar is shown in below matrix Audience:
Speaker = [1 1 0 0 0 0 0 0 0 0;
0 0 1 1 0 0 0 0 0 0;
0 0 0 0 1 1 0 0 0 0;
0 0 0 0 0 0 1 1 0 0;
0 0 0 0 0 0 0 0 1 1 ];
Audience = [1 1 0 1 0 0 0 0 0 0;
0 0 1 0 1 0 0 1 0 0;
0 0 1 0 1 0 0 1 0 0;
0 0 1 0 1 0 0 1 0 0;
0 0 1 0 1 0 0 1 0 0;
1 1 0 1 0 0 0 0 0 0;
0 0 0 0 0 1 1 0 0 1;
0 0 0 0 0 1 1 0 0 1;
0 0 0 0 0 1 1 0 0 1;
1 1 0 1 0 0 0 0 0 0;
1 1 0 1 0 0 0 0 0 0;
0 0 0 0 0 0 1 0 1 1;
0 0 0 0 0 0 1 0 1 1;
0 0 0 0 0 0 1 0 1 1;
0 0 0 0 0 0 1 0 1 1];
numberOfSeminar = 10; # Number of seminars
numberOfAudience = 15; # Number of audience
numberOfSpeakers = 5; # Number of speakers
numberOfTimePeriods = 6; # Number of time periods
numberOfRooms = 4; # Number of conference room
using JuMP, Cbc
model = Model(with_optimizer(Cbc.Optimizer))
#variable(
#CONSTRAINTS
#1.In a time and place, at most one seminar will be schedule.
#constraint()
#2. All seminars get two time periods.
#constraint()
#3. A seminar cannot be scheduled to two different conference room at the same time (no sections)
#constraint()
#4. A speaker cannot be in two different seminar at the same time
#constraint()
#5. A audience cannot be in two different seminar at the same time
#constraint()
I also can not configure its model. I know some constraints are needed and at the end of the code I must optimize it with
optimize!(model)
By the way can I print the schedule after optimization? Is there any way? I want to print out the result.

Get rows with some value next to threshold

I'm processing data from some simulations and I need some support with SQL to get the data I need. Having a reference table with some times, I need to retrieve the state of the simulation at this particular time: this will be the row with nearest (but below) simulation time to the reference time.
Having this example
Simulation TimeS P1 P2 P2F P3 P3F P4 P4F P5 P5F P6
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
1 0.0 1 0 0 0 0 0 0 0 0 0
1 0.0 0 1 0 0 0 0 0 0 0 0
1 28.0 0 1 0 0 0 0 0 0 0 0
1 28.0 0 1 0 0 0 0 0 0 0 0
1 2190.0 0 1 0 0 0 0 0 0 0 0
1 2190.33333 0 1 0 0 0 0 0 0 0 0
2 0.0 1 0 0 0 0 0 0 0 0 0
2 0.0 0 1 0 0 0 0 0 0 0 0
2 28.0 0 1 0 0 0 0 0 0 0 0
2 28.0 0 1 0 0 0 0 0 0 0 0
2 817.859662 0 0 1 0 0 0 0 0 0 0
2 840.0 0 0 1 0 0 0 0 0 0 0
2 840.0 0 0 1 0 0 0 0 0 0 0
2 840.0 0 0 1 0 0 0 0 0 0 0
2 840.0 0 0 1 0 0 0 0 0 0 0
2 1018.65247 0 0 0 1 0 0 0 0 0 0
2 1036.0 0 0 0 1 0 0 0 0 0 0
2 1036.0 0 0 0 1 0 0 0 0 0 0
2 2190.0 0 0 0 1 0 0 0 0 0 0
2 2190.0 0 0 0 1 0 0 0 0 0 0
2 2190.0 0 0 0 1 0 0 0 0 0 0
2 2190.04166 0 0 0 1 0 0 0 0 0 0
2 2190.20833 0 0 0 1 0 0 0 0 0 0
2 2190.25 1 0 0 0 0 0 0 0 0 0
2 2190.25 0 1 0 0 0 0 0 0 0 0
2 2190.33333 0 1 0 0 0 0 0 0 0 0
2 2212.0 0 1 0 0 0 0 0 0 0 0
2 2212.0 0 1 0 0 0 0 0 0 0 0
2 2472.94974 0 0 1 0 0 0 0 0 0 0
2 2492.0 0 0 1 0 0 0 0 0 0 0
2 2492.0 0 0 1 0 0 0 0 0 0 0
2 2492.0 0 0 1 0 0 0 0 0 0 0
2 2492.0 0 0 1 0 0 0 0 0 0 0
and some reference times
value
----------
0
365
730
1095
1460
1825
2190
2555
2920
I need a new table with only the values from the reference table (in this time 9 rows only) with this output
Simulation TimeV P1 P2 P2F P3 P3F P4 P4F P5 P5F P6
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
1 0.0 0 1 0 0 0 0 0 0 0 0
1 365.0 0 1 0 0 0 0 0 0 0 0
1 730.0 0 1 0 0 0 0 0 0 0 0
1 1095.0 0 1 0 0 0 0 0 0 0 0
1 1460.0 0 1 0 0 0 0 0 0 0 0
1 1825.0 0 1 0 0 0 0 0 0 0 0
1 2190.0 0 1 0 0 0 0 0 0 0 0
2 0.0 0 1 0 0 0 0 0 0 0 0
2 365.0 0 0 1 0 0 0 0 0 0 0
2 730.0 0 0 1 0 0 0 0 0 0 0
...
I have tried this, I think the approach is near to the actual solution but is not working as I need. generate_series is a SQLite module I imported to my session to generate a table with numbers from 0 to 3000 with 365 step.
I have limited the output with the where clause.
select P.Simulation, S.value as TimeV, P.Time as TimeS,
"P.Track.Initial" as P1,
"P.Track.Good.U" as P2, "P.Track.Good.Finishing.U" as P2F ,"P.Track.Satisfactory.U" as P3, "P.Track.Satisfactory.Finishing.U" as P3F,
"P.Track.Poor.U" as P4, "P.Track.Poor.Finishing.U" as P4F, "P.Track.VeryPoor.U" as P5, "P.Track.VeryPoor.Finishing.U" as P5F, "P.Track.SuperRed.U" as P6
from generate_series(0, 3000, 365) S
inner join Places_1 P ON TimeV = ( select max(value) from generate_series(0,3000,365) where value <= TimeS )
where P.Simulation <= 2 and TimeS <= 3000
I expected to have only 9 rows per simulation, as I only need the state of the system at the reference times. But I'm getting repeated values for the reference time table...
Simulation TimeV TimeS P1 P2 P2F P3 P3F P4 P4F P5 P5F P6
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
1 0 0.0 1 0 0 0 0 0 0 0 0 0
1 0 0.0 0 1 0 0 0 0 0 0 0 0
1 0 28.0 0 1 0 0 0 0 0 0 0 0
1 0 28.0 0 1 0 0 0 0 0 0 0 0
1 2190 2190.0 0 1 0 0 0 0 0 0 0 0
1 2190 2190.33333 0 1 0 0 0 0 0 0 0 0
...
One solution (not the prettiest) is to use unions. This will take a row (or multiple rows) and attach them below one another. Here's how you would do it:
(SELECT [COLUMNS HERE] FROM [TABLE] WHERE TimeS <= [TimeV #1] AND ROWNUM = 1 ORDER BY TimeS DESC)
UNION
(SELECT [SAME COLUMNS] FROM [TABLE] WHERE TimeS <= [TimeV #2] AND ROWNUM = 1 ORDER BY TimeS DESC)
UNION
...
Repeat this for each of the values of TimeV you need.
I got the solution!
select P.Simulation, max(P.Time) as Time, value as RefDay,
"P.Track.Initial" as P1,
"P.Track.Good.U" as P2, "P.Track.Good.Finishing.U" as P2F ,"P.Track.Satisfactory.U" as P3, "P.Track.Satisfactory.Finishing.U" as P3F,
"P.Track.Poor.U" as P4, "P.Track.Poor.Finishing.U" as P4F, "P.Track.VeryPoor.U" as P5, "P.Track.VeryPoor.Finishing.U" as P5F, "P.Track.SuperRed.U" as P6
from Places_1 P, generate_series(0,10950,365) where P.Time <= value group by Simulation,value
With this query I get the data I need. The key is grouping by the reference time.

T-SQL poor CTE join performance

Long story short. I have a two SQL queries that are very similar and outputs value pairs of short and long names. Input parameter is for first query: short name and for second query is long name. The queries are constructed that outputs all rows that contained input parameters and this is not exact match (for example if I set tagname as ST2 this query outputs all object that contains ST2 and all other object that has ST2 at the beginning of its name.
All the queries are executed in same database. In below queries input parameters are set to "" this means that query outputs key value pairs of short and long names for all objects
declare #tagName as varchar(50) = ''
set #tagName = #tagName + '.'
-- this one query outputs ~700 rows
;with AnalogTag as
(
Select *
from [Runtime].[dbo].[AnalogTag]
where (substring(TagName, 0, charindex('.',#tagName))) in (substring(#tagName,0, len(#tagName)))
and (substring(TagName, charindex('.',TagName), 2)) not in ('.#')
),
-- this one query outputs ~7000 rows
HierarchicalName as
(
Select *
from [proba7].[dbo].[internal_list_objects_view]
where substring(tag_name, 0,len(#tagName)) = substring(#tagName,0, len(#tagName))
)
select HierarchicalName.tag_name as TagName
,HierarchicalName.hierarchical_name ilo_view_HierarchicalName
from AnalogTag
inner join HierarchicalName
on substring(AnalogTag.TagName, 0, CHARINDEX('.',AnalogTag.TagName)) = HierarchicalName.tag_name
Whole query above runs at approx 3 seconds. And outputs about 450 rows
I created a similar one query on same database:
declare #hierarchicalName as varchar(200) = ''
declare #Length as int
set #Length = LEN(#hierarchicalName)+1
-- this query outputs approx 700 rows and if runs separately it runs
--almost instantly
;with AnalogTag as
(
Select TagName
from [Runtime].[dbo].[AnalogTag]
where (substring(TagName, 0, CHARINDEX('.',TagName))) in
(
Select tag_name from [proba7].[dbo].[internal_list_objects_view]
where substring(hierarchical_name, 0, #Length) = #hierarchicalName
)
and (substring(TagName, CHARINDEX('.',TagName), 2)) not in ('.#')
),
-- this query outputs approx 7000 rows and if runs separately it runs
--almost instantly
HierarchicalName as
(
Select hierarchical_name, tag_name from [proba7].[dbo].[internal_list_objects_view]
where substring(hierarchical_name, 0, #Length) = #hierarchicalName
)
select HierarchicalName.tag_name as ilo_view_TagName
,HierarchicalName.hierarchical_name ilo_view_HierarchicalName
from AnalogTag
inner join HierarchicalName
on substring(AnalogTag.TagName, 0, CHARINDEX('.',AnalogTag.TagName)) = HierarchicalName.tag_name
And this time query runs in 28 seconds. Outputs similar amount of row as first query (because ouptut must be similar on these two queries). I noticed that if i change "inner join" to for example "full join", query runs instantly.
Analog tag example output:
TagName a b c d e f g h j j k l m
PomFPTemp.PV 1062 0 10 0 10 0 4 0 0 0 0 0 0
PomFPWilgWzgl.PV 1 0 10 0 10 0 4 0 0 0 0 0 0
SNST3P1BrakFWHMocD3f.PV 1063 0 10 0 10 0 4 0 0 0 0 0 0
SNST3P1BrakFWHMocP3f.PV 46 0 10 0 10 0 4 0 0 0 0 0 0
SNST3P1BrakFWHMocQ3f.PV 1063 0 10 0 10 0 4 0 0 0 0 0 0
SNST3P1BrakFWHMocQ3fIntExp.PV 1063 0 10 0 10 0 4 0 0 0 0 0 0
SNST3P1BrakFWHMocQ3fIntImp.PV 1063 0 10 0 10 0 4 0 0 0 0 0 0
SNST3P1BrakFWHMocQn3f.PV 1063 0 10 0 10 0 4 0 0 0 0 0 0
SNST3P1EnkvarhExp3f.PV 1060 0 10 0 10 0 4 0 0 0 0 0 0
SNST3P1EnkvarhImp3f.PV 1060 0 10 0 10 0 4 0 0 0 0 0 0
hierarchical name example output:
ID tag_name contained_name hierarchical_name a b c d e f g h i j k l m n o p q r s t u v w x y z aa bb cc dd ee ff gg hh
1 $Galaxy $Galaxy 1 0 0 0 0 1 NULL NULL 0 0 1 1 1 0 0 0 0 0 1 0 NULL 23 0 0 0 0 0 0 0 0 0 133123 50026 1 NULL
2 proba7 Galaxy_001 0 0 0 0 1 1 NULL NULL 0 0 848 1 0 1 0 0 0 0 1 0 NULL 23 0 0 0 0 0 0 0 0 0 4098 878020 1 NULL
3 $_AutoImport $_AutoImport 1 0 0 0 0 3 NULL NULL 0 0 4 2 0 0 0 0 0 0 1 0 NULL 10 0 0 0 0 0 0 0 0 0 131075 3699 1 NULL
4 $_DiCommon $_DiCommon 1 0 0 0 0 4 NULL NULL 0 0 5 3 0 0 0 0 0 0 1 0 NULL 10 0 0 0 0 0 0 0 0 0 131075 50023 1 NULL
5 $WinPlatform $WinPlatform 1 0 0 0 0 5 NULL 1 0 0 6 4 1 0 0 0 0 0 0 0 NULL 1 0 0 0 0 0 0 0 0 0 133121 419340 1 1
6 $AppEngine $AppEngine 1 0 0 0 0 6 NULL 1 0 0 7 5 1 0 0 0 0 0 0 0 NULL 3 0 0 0 0 0 0 0 0 0 133121 419341 1 1
7 $Area $Area 1 0 0 0 0 7 NULL 1 0 0 8 6 1 0 0 0 0 0 0 0 NULL 13 0 0 0 0 0 0 0 0 0 133121 3452998 1 1
8 $AnalogDevice $AnalogDevice 1 0 0 0 0 8 NULL 2 0 0 9 7 0 0 0 0 0 0 0 0 NULL 10 0 0 0 0 0 0 0 0 0 131073 419343 1 2
9 $DDESuiteLinkClient $DDESuiteLinkClient 1 0 0 0 0 9 NULL 3 0 0 10 8 1 0 0 0 0 0 0 0 NULL 11 0 0 0 0 0 0 0 0 0 133121 419344 1 3
10 $DiscreteDevice $DiscreteDevice 1 0 0 0 0 10 NULL 2 0 0 11 9 0 0 0 0 0 0 0 0 NULL 10 0 0 0 0 0 0 0 0 0 131073 419345 1 2
11 $InTouchProxy $InTouchProxy 1 0 0 0 0 11 NULL 3 0 0 12 10 0 0 0 0 0 0 0 0 NULL 11 0 0 0 0 0 0 0 0 0 131073 419346 1 3
Output table (example):
ilo_view_TagName ilo_view_HierarchicalName
ST4FP12Rozl ST4_FP1.Galaz_2.Rozladowywanie
ST4FP21Rozl ST4_FP2.Galaz_1.Rozladowywanie
ST4FP22Rozl ST4_FP2.Galaz_2.Rozladowywanie
ST4FP31Rozl ST4_FP3.Galaz_1.Rozladowywanie
ST4RS41AnWspKFL2 ST4_S1_RS4_1.Wsp.K_Factor.L2
ST4FP32Rozl ST4_FP3.Galaz_2.Rozladowywanie
ST4RS31AnWspKFL2 ST4_S2_RS3_1.Wsp.K_Factor.L2
ST4RS51AnWspKFL2 ST4_S3_RS5_1.Wsp.K_Factor.L2
ST4FP11U ST4_FP1.Galaz_1.Napiecie
Best regards and thanks in advance for any advices. I tried at my best to make this exapmple tables readable.

Truth table with 5 inputs and 3 outputs

I have to make a truth table with 5 inputs and 3 outputs, something like this:
A B C D E red green blue
0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 1
0 0 0 1 0 0 0 1
.
.
.
.
1 1 0 1 0 0 1 1
.
.
.
1 1 1 1 1 1 0 1
etc. (in total 32 rows, the numbers in the rgb table represents the number of 1's in each row in binary i.e in row 1 1 0 1 0 there are three 1's, so three in binary is 0 1 1).
I would like to present the result of it in the Atanua (http://sol.gfxile.net/atanua/index.html) tool (so fore example when I press button E, the blue light will shine, when pressing A B D the green and blue light will shine and so on). But there is a requirement that I can only use AND, OR, NOT operands, and each operand can only have two inputs. Although I'm using Karnaugh map to minimize it, still for so many records the results for each output are very long (especially for the last one).
I tried to simplify it more by adding all of the three output boolean functions into one, and the minimization process ended pretty well:
A + B + C + D
It seems to work fine (but as there is only one output light, it works only in red green blue column separately). My concern is the fact that I would like to have three outputs (three lights, not one), and is that even possible after this kind of minimization? Is there a good solution to do it in Atanua? Or do I have to make 3 separate boolean functions, no matter how long they will be (and there is a lot of them even after minimization)?
EDIT: the whole truth table :)
A B C D E R G B
0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 1
0 0 0 1 0 0 0 1
0 0 0 1 1 0 1 0
0 0 1 0 0 0 0 1
0 0 1 0 1 0 1 0
0 0 1 1 0 0 1 0
0 0 1 1 1 0 1 1
0 1 0 0 0 0 0 1
0 1 0 0 1 0 1 0
0 1 0 1 0 0 1 0
0 1 0 1 1 0 1 1
0 1 1 0 0 0 1 0
0 1 1 0 1 0 1 1
0 1 1 1 0 0 1 1
0 1 1 1 1 1 0 0
1 0 0 0 0 0 0 1
1 0 0 0 1 0 1 0
1 0 0 1 0 0 1 0
1 0 0 1 1 0 1 1
1 0 1 0 0 0 1 0
1 0 1 0 1 0 1 1
1 0 1 1 0 0 1 1
1 0 1 1 1 1 0 0
1 1 0 0 0 0 1 0
1 1 0 0 1 0 1 1
1 1 0 1 0 0 1 1
1 1 0 1 1 1 0 0
1 1 1 0 0 0 1 1
1 1 1 0 1 1 0 0
1 1 1 1 0 1 0 0
1 1 1 1 1 1 0 1
And the karnaugh map for each color (~is the gate NOT, * is AND, + OR):
RED:
BCDE+ACDE+ABDE+ABCE+ABCD
GREEN:
~A~BDE+~AC~DE+~ACD~E+~BCD~E+~AB~CE+B~CD~E+BC~D~E+A~B~CE+A~B~CD+A~BC~D+AB~C~D
BLUE:
~A~B~C~DE+~A~B~CD~E+~A~BC~D~E+~A~BCDE+~AB~C~D~E+~AB~CDE+~ABC~DE+~ABCD~E+A~B~C~D~E+A~B~CDE+A~BC~DE+A~BCD~E+AB~C~DE+AB~CD~E+ABC~D~E+ABCDE
Have to admit that the formulas are somewhat ugly, but it's not too complicated to implement with logic gatters, because you can reuse parts.
A -----+------+------------- - - -
NOT |
+------|--AND- ~AB
| | |
AND-----|---|-- ~A~B
+--AND-+ |
| +--|---|-- A~B
NOT AND--|-- AB
B -----+------+---+---------- - - -
Here as an example I created all combinations of [not]A and [not]B. You can do the same for C and D. So you can get any combination of [not]A and [not]B and [not]C and [not]D by combining a wire from each "box" with an and gatter (e.g. for ABCD we would take the AB wire AND the CD wire).

How to combine rows or data into one row

I am working on a project to see how many units of each category that customers order and this is my Select clause:
SELECT
d2.customer_id
, ( CASE WHEN d2.category = 100 THEN d2.units ELSE 0 END ) AS produce_units
, ( CASE WHEN d2.category = 200 THEN d2.units ELSE 0 END ) AS meat_units
, ( CASE WHEN d2.category = 300 THEN d2.units ELSE 0 END ) AS seafood_units
, SUM (d2.units) AS total_units
And my result looks like this while 62779 is customer id and the last column is total units.
62779 0 0 0 0 20 0 0 0 0 0 0 20
62779 0 0 0 0 0 0 0 0 52 0 0 52
62779 0 6 0 0 0 0 0 0 0 0 0 6
62779 0 0 0 0 0 0 0 0 0 22 0 22
62779 0 0 0 0 0 14 0 0 0 0 0 14
62779 0 0 0 0 0 0 0 20 0 0 0 20
62779 0 0 0 8 0 0 0 0 0 0 0 8
62779 64 0 0 0 0 0 0 0 0 0 0 64
However, I want my result to look like this:
62779 64 6 0 8 20 14 0 20 52 22 0 206
Please advice. Thanks :)