# Lights Out (Merlin)

Earlier today I was watching a video from The Great Courses series. The lecturer was Arthur T. Benjamin of Harvey Mudd College. He was discussing strategies to solve a 3 x 3 lights out puzzle. It inspired me to write a T-SQL version of the game.

USE Experiment

/** Thanks to Professor Arthur T. Benjamin of Harvey Mudd Univserity for the inspiration. */

IF OBJECT_ID(‘lightsout’) IS NOT NULL DROP TABLE lightsout;–Technically Merlin.

CREATE TABLE lightsout

(

column1 BIT,

column2 BIT,

column3 BIT,

rownumber INT IDENTITY(1,1)

)

GO

We’ll use a trigger to enforce the one button push rule as well as to update the adjacent cell with their bitwise negation.

CREATE TRIGGER onebutton ON lightsout

AS

BEGIN

–Trigger to assure a single button push

IF @@ROWCOUNT > 1 OR

(SELECT TOP 1

ABS(

CAST(d.column1 AS INT)-CAST(i.column1 AS INT)

+ CAST(d.column2 AS INT)-CAST(i.column1 AS INT)

+ CAST(d.column3 AS INT)-CAST(i.column1 AS INT)

)

FROM deleted d

INNER JOIN

inserted i

ON d.rownumber = i.rownumber

) > 1

BEGIN

PRINT ‘Rule Break.’

ROLLBACK

END

ELSE

–Triggers to update on update

IF (SELECT TOP 1 rownumber FROM deleted) = 1

BEGIN

IF (SELECT TOP 1 deleted.column1 ^ inserted.column1

FROM deleted

INNER JOIN

inserted

ON deleted.rownumber = inserted.rownumber) <> 0

BEGIN

UPDATE l SET column1 = ~(l.column1) FROM lightsout l WHERE rownumber = 1;

UPDATE l SET column1 = ~(l.column1) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 1;

END

IF (SELECT TOP 1 deleted.column2 ^ inserted.column2

FROM deleted

INNER JOIN

inserted

ON deleted.rownumber = inserted.rownumber)<>0

BEGIN

UPDATE l SET column1 = ~(l.column1) FROM lightsout l WHERE rownumber = 1;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 1;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column3 = ~(l.column3) FROM lightsout l WHERE rownumber = 1;

END

IF (SELECT TOP 1 deleted.column3 ^ inserted.column3

FROM deleted

INNER JOIN

inserted

ON deleted.rownumber = inserted.rownumber)<>0

BEGIN

UPDATE l SET column3 = ~(l.column3) FROM lightsout l WHERE rownumber = 1;

UPDATE l SET column3 = ~(l.column3) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 1;

END

END

IF (SELECT TOP 1 rownumber FROM deleted) = 2

BEGIN

IF (SELECT TOP 1 deleted.column1 ^ inserted.column1

FROM deleted

INNER JOIN

inserted

ON deleted.rownumber = inserted.rownumber)<>0

BEGIN

UPDATE l SET column1 = ~(l.column1) FROM lightsout l WHERE rownumber = 1;

UPDATE l SET column1 = ~(l.column1) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column1 = ~(l.column1) FROM lightsout l WHERE rownumber = 3;

END

IF (SELECT TOP 1 deleted.column2 ^ inserted.column2

FROM deleted

INNER JOIN

inserted

ON deleted.rownumber = inserted.rownumber)<>0

BEGIN

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 1;

UPDATE l SET column1 = ~(l.column1) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column3 = ~(l.column3) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 3;

END

IF (SELECT TOP 1 deleted.column3 ^ inserted.column3

FROM deleted

INNER JOIN

inserted

ON deleted.rownumber = inserted.rownumber)<>0

BEGIN

UPDATE l SET column3 = ~(l.column3) FROM lightsout l WHERE rownumber = 1;

UPDATE l SET column3 = ~(l.column3) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column3 = ~(l.column3) FROM lightsout l WHERE rownumber = 3;

END

END

IF (SELECT TOP 1 rownumber FROM deleted) = 3

BEGIN

IF (SELECT TOP 1 deleted.column1 ^ inserted.column1

FROM deleted

INNER JOIN

inserted

ON deleted.rownumber = inserted.rownumber)<>0

BEGIN

UPDATE l SET column1 = ~(l.column1) FROM lightsout l WHERE rownumber = 3;

UPDATE l SET column1 = ~(l.column1) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 3;

END

IF (SELECT TOP 1 deleted.column2 ^ inserted.column2

FROM deleted

INNER JOIN

inserted

ON deleted.rownumber = inserted.rownumber)<>0

BEGIN

UPDATE l SET column1 = ~(l.column1) FROM lightsout l WHERE rownumber = 3;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 3;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column3 = ~(l.column3) FROM lightsout l WHERE rownumber = 3;

END

IF (SELECT TOP 1 deleted.column3 ^ inserted.column3

FROM deleted

INNER JOIN

inserted

ON deleted.rownumber = inserted.rownumber)<>0

BEGIN

UPDATE l SET column3 = ~(l.column3) FROM lightsout l WHERE rownumber = 3;

UPDATE l SET column3 = ~(l.column3) FROM lightsout l WHERE rownumber = 2;

UPDATE l SET column2 = ~(l.column2) FROM lightsout l WHERE rownumber = 3;

END

END

END

GO

Let’s insert some random bits.

–Random bits

INSERT INTO lightsout

SELECT CAST(ROUND(RAND(),0) AS BIT) column1

,CAST(ROUND(RAND(),0) AS BIT) column2

,CAST(ROUND(RAND(),0) AS BIT) column3

UNION ALL

SELECT CAST(ROUND(RAND(),0) AS BIT) column1

,CAST(ROUND(RAND(),0) AS BIT) column2

,CAST(ROUND(RAND(),0) AS BIT) column3

UNION ALL

SELECT CAST(ROUND(RAND(),0) AS BIT) column1

,CAST(ROUND(RAND(),0) AS BIT) column2

,CAST(ROUND(RAND(),0) AS BIT) column3