MagneticSensorChessBoard1987

From BITPlan Wiki
Jump to navigation Jump to search

Click here to comment see PlayChessWithAWebCam UniChess87-0044.JPG

History

During my study at RWTH Aachen from 1982 to 1989 I (Wolfgang Fahl) used to play chess every once in a while against my fellow students. One of them was much better and therefore told me when i made a wrong move (mostly a few moves later). He would then allow me to take back the bad move. For that we had to remember what the moves where. Sometimes this what not so easy so we came up with the idea to create a chess board that would help us track the moves.

Requirements

  1. The board should be as "non-invasive" as possible - it should not modify the game of chess more than necessary
  2. The solution should track moves of peaces and record them in a text file
  3. The solution should only allow valid moves
  4. The solution should be able to work from a predefined chess position
  5. The board should connect to a regular IBM PC

Design

  1. a 335 x 335 mm chess plan with 35 mm squares was used as a basis
  2. 32 wooden chess pieces with a height of 33 mm each were fitted with magnets from a Brio-Bahn
  3. The Centronics Printer port would be used for connecting
  4. There would be control leds for each row/column of the board with which to indicate a move detected or to be done by the human player
  5. Since the centronics port has only a few available input lines and max 8 output lines TTL multiplexer/demultipler chips would be used

Hardware

Front

UniChess87-0035.JPG

Back

UniChess87-0036.JPG

Connectors

UniChess87-0037.JPG UniChess87-0038.JPG UniChess87-0039.JPG

Schematics

Parts:

  1. TTL 74151 8 to 1 Multiplexer TTL74151 Pins.jpeg
  2. TTL 74154 4 to 16 Demultiplexer TTL74154 pins.png
  3. 300 Ohm Pull up Resistor

Unichess87-Schematics.JPG

Partlist

  1. chess plan 35 mm fields
  2. 64 Reed Contacts
  3. 16 Black Chess Pieces
  4. 16 White Chess Pieces
  5. 32 magnets
  6. 17 red LEDs
  7. On/Off switch
  8. Male Sub-D Connector 15
  9. Adapter cable Centronics - SUB-D 15 Female
  10. Copper Tape
  11. Aluminum Frame
  12. 1 TTL 74151
  13. 1 TTL 74154
  14. 330 Ohm Resistor
  15. Batteryholder for 3 x AA

Software

The Software was written with Borland Turbo Pascal

SCHFELD.PAS

PROGRAM Schachbrett_Ansteuerung(INPUT,OUTPUT);
TYPE
  KBrettTyp= ARRAY [0..7,0..7] OF BOOLEAN;

CONST
  BlinkTime     =   100;
  MaxBlinkTime  =  1400;
  MaxTime       =  1700;

VAR
  Pw,
  Count,LED1,LED2,
  LED3,LED4,MovCount,
  FigMovCnt: INTEGER;
  MovList                 : ARRAY[0..500] OF LSTRING(5);
  KBrett,SBrett           : KBrettTyp;
  ZugDatei                : TEXT;

(*$include: 'screen.def'*)
(*$include: 'string.def'*)

PROCEDURE ClrLED;
BEGIN
  LED1:=#80;
  LED2:=LED1;
  LED3:=LED1;
  LED4:=LED1;
END;

FUNCTION CheckBrett(D,L: INTEGER): BOOLEAN; EXTERN;
PROCEDURE Sound(Freq,Time: INTEGER); EXTERN;

FUNCTION Check(x,y: INTEGER):BOOLEAN;
VAR
  Pw,Dw,P1,P2:INTEGER;
BEGIN
  CASE  (Count MOD 2) OF
    0: BEGIN P1:=LED1; P2:=LED3; END;
    1: BEGIN P1:=LED2; P2:=LED4; END;
  END;
  IF Count<MaxBlinkTime THEN
    BEGIN
      CASE (Count DIV BlinkTime) MOD 4 OF
        0,1,2: Pw:=P1;
        3: Pw:=P2;
      END;
    END
  ELSE
    Pw:=P2;
  IF Count<MaxBlinkTime THEN
     Count:=SUCC(Count)
  ELSE
    IF Count<MaxTime THEN
      BEGIN
        IF FigMovCnt>=1 THEN
          Count:=0
        ELSE
          Count:=SUCC(Count);
      END
    ELSE
      ClrLED;
  Dw:=(x * 8) +y;
  Check:=CheckBrett(Dw,Pw);
END;

PROCEDURE State(VAR B:KBrettTyp);
VAR
  Spalte,Zeile: INTEGER;
BEGIN
  FOR Spalte:=0 TO 7 DO
    FOR Zeile:=0 TO 7 DO
      B[Spalte,Zeile]:=Check(Spalte,Zeile);
END;

PROCEDURE Kontakte;
VAR
  Spalte,Zeile: INTEGER;
BEGIN
  CLRSCR;
  ClrLED;
  REPEAT
    GOTOXY(1,1);
    FOR Spalte:=0 TO 7 DO
    BEGIN
      FOR Zeile:=0 TO 7 DO
      BEGIN
        IF KeyPressed THEN RETURN;
        IF Check(Spalte,Zeile) THEN WRITE('*') ELSE WRITE('.');
      END;
      WRITELN;
    END;
  UNTIL FALSE;
END;

PROCEDURE Scribe(VAR D:TEXT;P:INTEGER);
BEGIN
  WRITE(D,MovList[P]);
    CASE (P MOD 4) OF
      0: BEGIN WRITELN(D);WRITE(D,P DIV 4+1:3,': '); END;
      2: WRITE(D,'   ');
    OTHERWISE
    ;
    END;
END;

PROCEDURE Zuege;
  PROCEDURE Accept(X1,Y1,X2,Y2: INTEGER);
    PROCEDURE StatePos(Zeile,Spalte: INTEGER);
    BEGIN
      MovCount:=SUCC(MovCount);
      CONCAT(MovList[MovCount],CHR(ORD('A')+Zeile));
      CONCAT(MovList[MovCount],CHR(ORD('8')-Spalte));
      CASE (MovCount MOD 4) OF
       1,3: BEGIN
              IF FigMovCnt>=2 THEN
                CONCAT(MovList[MovCount],' X ')
              ELSE
                CONCAT(MovList[MovCount],' - ');
            END;
      OTHERWISE
      ;
      END;
      Scribe(OutPut,MovCount);
    END;
  BEGIN
    StatePos(X1,Y1);
    StatePos(X2,Y2);
    Count:=0;
    State(SBrett);
    Sound(800,20);
  END;

PROCEDURE ZugVerfolgen;
VAR
  AktCheck: BOOLEAN;
  P1,P2,P3,P4,Spalte,Zeile: INTEGER;

  PROCEDURE GetPos(VAR X,Y,L1,L2: INTEGER);
  BEGIN
    X:=Zeile;
    Y:=Spalte;
    L1:=(X+8) * 8;
    L2:=Y     * 8;
    Count:=0;
    State(SBrett);
  END;

BEGIN
  WRITELN('Zug-Anzeige: ');
  Scribe(OutPut,0);
  MovCount:=0;
  State(SBrett);
  FigMovCnt:=0;
  ClrLED;
  REPEAT
    FOR Zeile:=0 TO 7 DO
      FOR Spalte:=0 TO 7 DO
      BEGIN
        IF KeyPressed THEN RETURN;
        AktCheck:=Check(Spalte,Zeile);
        IF (NOT AktCheck) AND Sbrett[Spalte,Zeile] THEN
          BEGIN                { Figur Entfernt }
            IF FigMovCnt=1 THEN
              BEGIN
                GetPos(P3,P4,LED3,LED4);
                FigMovCnt:=FigMovCnt+1;
              END
            ELSE
              BEGIN
                GetPos(P1,P2,LED1,LED2);
                LED3:=LED1;
                LED4:=LED2;
                FigMovCnt:=FigMovCnt+1;
              END;
          END;
        IF AktCheck AND (NOT Sbrett[Spalte,Zeile]) THEN
          BEGIN  { Figur gesetzt }
            CASE FigMovCnt OF
              0: BEGIN
                   GetPos(P1,P2,LED1,LED2);
                 END;
              1: BEGIN
                   IF NOT ((P1=Zeile) AND (P2=Spalte)) THEN { Figur bewegt? }
                   BEGIN
                     Accept(P1,P2,Zeile,Spalte);
                     GetPos(P1,P2,LED3,LED4);
                     LED1:=LED3;LED2:=LED4;
                     FigMovCnt:=0;
                   END
                 ELSE
                   BEGIN
                     ClrLED;
                     State(SBrett);
                     FigMovCnt:=0;
                  END;
                END
            OTHERWISE
              IF (P1=Zeile) AND (P2=Spalte) THEN
                BEGIN
                  Accept(P3,P4,Zeile,Spalte);
                  GetPos(P1,P2,LED3,LED4);
                  FigMovCnt:=0;
                END
              ELSE
                BEGIN
                   Accept(P1,P2,Zeile,Spalte);
                  GetPos(P1,P2,LED3,LED4);
                  FigMovCnt:=0;
                END;
            END; { Case }
          END;
      END;
  UNTIL FALSE;
END;

VAR
   Taste: CHAR;
       z: INTEGER;
BEGIN
  CLRSCR;
  ZugVerfolgen;
  ASSIGN(ZugDatei,'SCHParti.txt');
  REWRITE(ZugDatei);
  FOR z:=0 TO MovCount DO
    Scribe(ZugDatei,z);
  CLOSE(ZugDatei);
END;

VAR
  Taste: CHAR;

BEGIN
  Window(1,1,80,25);
  REPEAT
    CLRSCR;
    WRITELN('(K)ontakt Matrix');
    WRITELN('(Z)ug-Anzeige');
    GetKey(Taste);
    MovList[0]:=NULL;
    Taste:=UpCase(Taste);
    CASE Taste OF
      'K': Kontakte;
      'Z': Zuege;
    OTHERWISE
     ;
    END;
  UNTIL Taste='E';
END.

Centronics Port Check

DATA SEGMENT PUBLIC 'DATA'

DATA ENDS
DGROUP GROUP DATA
       ASSUME CS:ADDS,DS:DGROUP,SS:DGROUP

ADDS SEGMENT 'CODE'
PUBLIC CheckBrett,Sound

Sound PROC FAR ; Freq,Time: INTEGER;
  PUSH BP
  MOV BP,SP
  PUSH DI
  MOV DI,8[BP] ; Freq;
  MOV BX,6[BP] ; Time;

  MOV AL,0B6H ; Zeitgeber Modus-Register schreiben
  OUT 43H,AL
  MOV DX,14H   ; Zeitgeber Divisor =
  MOV AX,4F38H ; 1331000/Frequenz
  DIV DI
  OUT 42H,AL   ; Zaehler in niederw. Byte Timer 2
  MOV AL,AH
  OUT 42H,AL  ; Zaehler in hoeherw. Byte Timer 2
  IN AL,61H   ; Aktuelle Einstellung Port B
  MOV AH,AL   ; In AH Sichern
  OR AL,3     ; Lautsprecher einschalten
  OUT 61H,AL

Warte:
  MOV CX,2801  ; 10 Millisekunden warten

LS_Ein:
  LOOP LS_Ein
  DEC BX       ; Einschaltzaehler auf 0?
  JNZ Warte    ; wenn nicht Lautsprecher anlassen

  MOV AL,AH    ; Port wiederherstellen
  OUT 61H,AL


  POP DI
  POP BP
  RET 4
Sound ENDP

CheckBrett PROC FAR  ;d,l: INTEGER: BOOLEAN
  PUSH BP
  MOV BP,SP
  CLI
  MOV AX,8[BP]   ; d
  MOV CX,6[BP]   ; l
  MOV DX,0278h
  OUT DX,AL      ; Port[Data]:=D
  INC DX
  IN AL,DX
  XCHG AL,CL
  DEC DX
  OUT DX,AL     ; Port[Data]:=l
  STI
  MOV AX,0
  AND CL,080h
  JNZ FALSE

  INC AX

FALSE:

  POP BP
  RET 4

CheckBrett ENDP


ADDS  ENDS
      END