Cevaplara bakmadan önce görevi kendiniz çözmeyi deneyin. Aynı sonucu veren farklı çözümler de doğrudur.

1 Başlangıç

Bağlanma, çıkışları açıp kapatma ve bekleme.
01

Simülasyona bağlan

Garaj simülasyonunu başlatın. Simülasyona bağlanan, bağlantı başarılıysa ekrana Connected to the garage! yazan ve bağlantıyı kapatan bir program yazın.
Sonra simülasyonu kapatıp programı bir kez daha çalıştırın ve ne olduğunu gözlemleyin.

sim_connect() simülasyonun açtığı paylaşımlı belleğe bağlanır. Simülasyon çalışmıyorsa 1 döndürür ve kütüphane bir hata mesajı yazar; program bu durumda hemen biter (C'de return 1, Python'da exit(1)). Python kütüphanesi bağlanınca ve bağlantıyı kapatınca kendisi de birer satır yazar. Her programın sonunda sim_disconnect() çağırmak iyi bir alışkanlıktır.

sim_connect()sim_disconnect()printf / print
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;   // simulation is not running

    printf("Connected to the garage!\n");

    sim_disconnect();
    return 0;
}
from garage import *

if sim_connect() != 0:   # simulation is not running
    exit(1)

print("Connected to the garage!")

sim_disconnect()
02

Garaj lambasını yak

Garajın iç lambasını yakan bir program yazın. Program bittikten sonra lambanın yanık kaldığını gözlemleyin.
Lambayı söndürmek için elle kontrol panelindeki Işık Kapat düğmesine basın.

garage_lamp(LAMP_ON) lambanın adresine 1 yazar. Simülasyon bu değeri program bittikten sonra da tutar; bu yüzden lamba siz söndürene kadar yanar. Lamba kapalıyken garaj karanlık (gölgeli) çizilir.

garage_lamp()LAMP_ON
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    garage_lamp(LAMP_ON);   // stays on after the program ends

    sim_disconnect();
    return 0;
}
from garage import *

if sim_connect() != 0:
    exit(1)

garage_lamp(LAMP_ON)   # stays on after the program ends

sim_disconnect()
03

Üç saniye yanan lamba

Lambayı yakın, 3 saniye bekleyin, sonra söndürün. Program bittiğinde lamba kapalı olmalı.

Komutlar yukarıdan aşağıya sırayla çalışır. Bekleme olmasaydı lamba o kadar kısa yanardı ki görülmezdi. C'deki Sleep milisaniye, Python'daki time.sleep saniye cinsinden süre alır.

garage_lamp()LAMP_OFFSleep / time.sleep
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    garage_lamp(LAMP_ON);
    Sleep(3000);            // 3000 ms = 3 s
    garage_lamp(LAMP_OFF);

    sim_disconnect();
    return 0;
}
from garage import *
import time

if sim_connect() != 0:
    exit(1)

garage_lamp(LAMP_ON)
time.sleep(3)          # 3 seconds
garage_lamp(LAMP_OFF)

sim_disconnect()
04

Uyarı ışığıyla trafik lambası

Uyarı ışığını sırasıyla 2 saniye kırmızı (255, 0, 0), 2 saniye sarı (255, 255, 0) ve 2 saniye yeşil (0, 255, 0) yakın; en sonunda söndürün. Uyarı ışığı tuş takımının hemen üstündeki renkli şerittir.

Renk, kırmızı-yeşil-mavi (RGB) bileşenlerinin 0–255 arası değerleriyle verilir. Son parametre WARN_ON ışığı açar. Rengi değiştirmek için warning_light() fonksiyonunu yeni değerlerle tekrar çağırmak yeterlidir. warning_light_off() ışığı söndürür ama son rengi unutmaz.

warning_light()RGBwarning_light_off()
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    warning_light(255, 0, 0, WARN_ON);     // red
    Sleep(2000);
    warning_light(255, 255, 0, WARN_ON);   // yellow
    Sleep(2000);
    warning_light(0, 255, 0, WARN_ON);     // green
    Sleep(2000);
    warning_light_off();

    sim_disconnect();
    return 0;
}
from garage import *
import time

if sim_connect() != 0:
    exit(1)

warning_light(255, 0, 0, WARN_ON)     # red
time.sleep(2)
warning_light(255, 255, 0, WARN_ON)   # yellow
time.sleep(2)
warning_light(0, 255, 0, WARN_ON)     # green
time.sleep(2)
warning_light_off()

sim_disconnect()
05

Kapıyı 2 saniye aç

Kapı kapalıyken başlayın. Kapı motorunu yukarı yönde çalıştırın, 2 saniye bekleyin ve motoru durdurun. Kapı yaklaşık üçte bir açılmış olmalı.
Kapıyı yeniden kapatmak için elle kontrol panelinde Kapı Aşağı düğmesine, kapı kapanınca Kapı Durdur düğmesine basın.

Motor bir kez çalıştırılınca kendiliğinden durmaz; iki komut arasındaki bekleme süresi kapının ne kadar hareket edeceğini belirler. Tam açılma yaklaşık 7 saniye sürdüğünden 2 saniyede kapı yaklaşık %30 açılır.

door_motor()DOOR_UPDOOR_STOP
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    door_motor(DOOR_UP);     // start opening
    Sleep(2000);
    door_motor(DOOR_STOP);   // stop the motor

    sim_disconnect();
    return 0;
}
from garage import *
import time

if sim_connect() != 0:
    exit(1)

door_motor(DOOR_UP)     # start opening
time.sleep(2)
door_motor(DOOR_STOP)   # stop the motor

sim_disconnect()
06

Aç, bekle, kapat

Kapı kapalıyken tam bir kapı döngüsü yapın:
1. Uyarı ışığını turuncu (255, 165, 0) yakın ve kapıyı 7 saniye yukarı çalıştırın (kapı tam açılır).
2. Motoru durdurun, uyarı ışığını söndürün ve 3 saniye bekleyin.
3. Uyarı ışığını kırmızı (255, 0, 0) yakın ve kapıyı 7 saniye aşağı çalıştırın.
4. Motoru durdurun ve uyarı ışığını söndürün.

Kapının tam yolu yaklaşık 7 saniye sürdüğü için 7 saniyelik bekleme kapıyı uca kadar götürür. Kapı uca vardıktan sonra motor çalışmaya devam etse de kapı yerinde kalır; ama gerçek bir motor için bu zararlıdır. Ayrıca kapı başta yarı açıksa süre yanlış olur. Süreye güvenmek yerine sensörü okumak daha doğrudur; bunu Görev 15'te yapacaksınız.

door_motor()DOOR_DOWNwarning_light()Sleep / time.sleep
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    warning_light(255, 165, 0, WARN_ON);   // orange: door is moving
    door_motor(DOOR_UP);
    Sleep(7000);                           // full travel takes about 7 s
    door_motor(DOOR_STOP);
    warning_light_off();

    Sleep(3000);                           // door stays open

    warning_light(255, 0, 0, WARN_ON);     // red: door is closing
    door_motor(DOOR_DOWN);
    Sleep(7000);
    door_motor(DOOR_STOP);
    warning_light_off();

    sim_disconnect();
    return 0;
}
from garage import *
import time

if sim_connect() != 0:
    exit(1)

warning_light(255, 165, 0, WARN_ON)   # orange: door is moving
door_motor(DOOR_UP)
time.sleep(7)                         # full travel takes about 7 s
door_motor(DOOR_STOP)
warning_light_off()

time.sleep(3)                         # door stays open

warning_light(255, 0, 0, WARN_ON)     # red: door is closing
door_motor(DOOR_DOWN)
time.sleep(7)
door_motor(DOOR_STOP)
warning_light_off()

sim_disconnect()

2 Temel

Sensör okuma, ekrana yazdırma ve if/else ile karar verme.
07

Kapının konumunu oku

Kapının kapalılık yüzdesini okuyup ekrana Door closed: 100% biçiminde yazdırın.
Sonra elle kontrol panelinde Kapı Yukarı düğmesine basın, kapı yarıya gelince Kapı Durdur düğmesine basın ve programı tekrar çalıştırın. Bu kez farklı bir sayı görmelisiniz.

Değişken, bir değeri saklamaya yarayan isimli bir kutudur. door_pos_read() simülasyonun o anki kapı konumunu döndürür; bu değer pos değişkenine konur ve yazdırılır. C'de printf içinde %% ekrana tek bir % işareti yazar.

door_pos_read()variableprintf / print
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    int pos = door_pos_read();          // 100 = closed, 0 = open
    printf("Door closed: %d%%\n", pos);

    sim_disconnect();
    return 0;
}
from garage import *

if sim_connect() != 0:
    exit(1)

pos = door_pos_read()          # 100 = closed, 0 = open
print(f"Door closed: {pos}%")

sim_disconnect()
08

Kapı kapalı mı?

Kapının konumunu okuyun. Kapı tam kapalıysa (100) ekrana Door is closed yazıp uyarı ışığını yeşil yakın; değilse Door is NOT closed yazıp kırmızı yakın.
Programı bir kez kapı kapalıyken, bir kez de kapıyı elle biraz açtıktan sonra çalıştırın.

if koşul doğruysa ilk bloğu, yanlışsa else bloğunu çalıştırır; ikisi birden asla çalışmaz. Karşılaştırma == ile yapılır; tek = atama demektir. Python'da bloklar girintiyle, C'de süslü parantezle belirlenir.

if / else==
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    int pos = door_pos_read();

    if (pos == 100)
    {
        printf("Door is closed\n");
        warning_light(0, 255, 0, WARN_ON);   // green
    }
    else
    {
        printf("Door is NOT closed\n");
        warning_light(255, 0, 0, WARN_ON);   // red
    }

    sim_disconnect();
    return 0;
}
from garage import *

if sim_connect() != 0:
    exit(1)

pos = door_pos_read()

if pos == 100:
    print("Door is closed")
    warning_light(0, 255, 0, WARN_ON)   # green
else:
    print("Door is NOT closed")
    warning_light(255, 0, 0, WARN_ON)   # red

sim_disconnect()
09

Kapının üç durumu

Görev 8'i üç duruma genişletin:
• 100 ise Closed yazın, uyarı ışığı yeşil (0, 255, 0).
• 0 ise Fully open yazın, uyarı ışığı kırmızı (255, 0, 0).
• Arada bir değerse Partly open: 40% gibi yüzdeyle birlikte yazın, uyarı ışığı sarı (255, 255, 0).

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.
10

Durum raporu

Lambanın, uyarı ışığının ve kapı motorunun o anki durumunu okuyup yazdırın, örneğin:
Lamp: ON
Warning light: OFF
Motor: UP
Motor için 0 → STOPPED, 1 → UP, 2 → DOWN yazın. Önce programı çalıştırın; sonra elle kontrol panelinde Işık Aç ve Kapı Yukarı düğmelerine basıp tekrar çalıştırın. En sonunda Kapı Durdur'a basmayı unutmayın.

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.
11

Bir tuşu oku

Program ekrana Press and hold key 5 (3 s)... yazsın ve 3 saniye beklesin. Bu sürede simülasyondaki tuş takımında 5 tuşunu fareyle basılı tutun.
Süre dolunca tuşu okuyun: basılıysa lambayı yakıp Key 5 is pressed yazın, değilse lambayı söndürüp Key 5 is not pressed yazın. Programı bir kez tuşa basarak, bir kez basmadan deneyin.

key_read() yalnızca okuma anındaki durumu verir. Tuşa basıp 3 saniye dolmadan bırakırsanız program basışı göremez. Bu sorunu Seviye 3'te tuşu bir döngü içinde sürekli okuyarak çözeceksiniz.

key_read()if / else
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    printf("Press and hold key 5 (3 s)...\n");
    Sleep(3000);

    if (key_read(5) == 1)
    {
        garage_lamp(LAMP_ON);
        printf("Key 5 is pressed\n");
    }
    else
    {
        garage_lamp(LAMP_OFF);
        printf("Key 5 is not pressed\n");
    }

    sim_disconnect();
    return 0;
}
from garage import *
import time

if sim_connect() != 0:
    exit(1)

print("Press and hold key 5 (3 s)...")
time.sleep(3)

if key_read(5) == 1:
    garage_lamp(LAMP_ON)
    print("Key 5 is pressed")
else:
    garage_lamp(LAMP_OFF)
    print("Key 5 is not pressed")

sim_disconnect()
12

İki koşul birden

Program Press and hold key 1 (3 s)... yazıp 3 saniye beklesin. Kapıyı yalnızca iki koşul birlikte sağlanırsa açın: kapı tam kapalı (100) VE 1 tuşu basılı.
Bu durumda Opening yazıp kapıyı 3 saniye yukarı çalıştırın ve durdurun. Aksi halde Cannot open yazıp uyarı ışığını 2 saniye kırmızı yakın ve söndürün. Programı kapı kapalıyken ve kapı biraz açıkken deneyin.

&& (Python'da and) ile birleştirilen koşulun doğru olması için iki parçanın da doğru olması gerekir. Böylece zaten açık olan kapı tekrar açılmaya çalışılmaz.

&& / andkey_read()door_pos_read()
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    printf("Press and hold key 1 (3 s)...\n");
    Sleep(3000);

    if (door_pos_read() == 100 && key_read(1) == 1)
    {
        printf("Opening\n");
        door_motor(DOOR_UP);
        Sleep(3000);
        door_motor(DOOR_STOP);
    }
    else
    {
        printf("Cannot open\n");
        warning_light(255, 0, 0, WARN_ON);
        Sleep(2000);
        warning_light_off();
    }

    sim_disconnect();
    return 0;
}
from garage import *
import time

if sim_connect() != 0:
    exit(1)

print("Press and hold key 1 (3 s)...")
time.sleep(3)

if door_pos_read() == 100 and key_read(1) == 1:
    print("Opening")
    door_motor(DOOR_UP)
    time.sleep(3)
    door_motor(DOOR_STOP)
else:
    print("Cannot open")
    warning_light(255, 0, 0, WARN_ON)
    time.sleep(2)
    warning_light_off()

sim_disconnect()
13

Konuma göre renk

Uyarı ışığının rengini kapının konumundan hesaplayın:
kırmızı = (100 − konum) × 255 / 100
yeşil = konum × 255 / 100
mavi = 0
Böylece kapalı kapı yeşil, tam açık kapı kırmızı, yarı açık kapı ara bir renk olur. Konumu ve hesaplanan değerleri Door closed: 50% R=127 G=127 gibi yazdırın. Kapıyı elle farklı konumlara getirip programı birkaç kez çalıştırın.

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.

3 Orta

Döngüler, sürekli kontrol ve durum takibi.
14

Kapıyı sürekli izle

Görev 13'ü sonsuz bir döngüye alın: her 300 ms'de bir konumu okuyup yazdırın ve uyarı ışığının rengini güncelleyin.
Program çalışırken kapıyı elle kontrol panelinden açıp kapatın (uçta Kapı Durdur'a basın) ve rengin yavaş yavaş değiştiğini izleyin. Programı Ctrl+C ile durdurun.

Sonsuz döngü içindeki komutları durmadan tekrarlar; böylece program sensördeki her değişikliği görür. Döngüdeki 300 ms'lik bekleme hem ekranı okunur tutar hem de işlemciyi boşuna yormaz. Döngüden sonraki satırlara hiç ulaşılmaz; program Ctrl+C ile kesilir.

while (1) / while TrueCtrl+C
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    while (1)                                // Ctrl+C to quit
    {
        int pos = door_pos_read();
        int red   = (100 - pos) * 255 / 100;
        int green = pos * 255 / 100;

        printf("Door closed: %d%%  R=%d G=%d\n", pos, red, green);
        warning_light(red, green, 0, WARN_ON);

        Sleep(300);
    }
}
from garage import *
import time

if sim_connect() != 0:
    exit(1)

while True:                              # Ctrl+C to quit
    pos = door_pos_read()
    red = (100 - pos) * 255 // 100
    green = pos * 255 // 100

    print(f"Door closed: {pos}%  R={red} G={green}")
    warning_light(red, green, 0, WARN_ON)

    time.sleep(0.3)
15

Sensörle tam aç, tam kapat

Görev 6'yı süre yerine sensörle yapın:
1. Uyarı ışığını turuncu (255, 165, 0) yakın, motoru yukarı çalıştırın ve door_pos_read() 0 olana kadar her 50 ms'de bir kontrol ederek bekleyin. Sonra motoru durdurun, ışığı söndürün ve Door is fully open yazın.
2. 1 saniye bekleyin.
3. Aynı şekilde kapıyı konum 100 olana kadar kapatın ve Door is fully closed yazın.
Programı kapı yarı açıkken de deneyin: yine doğru yerde durmalı.

Döngü, kapı hedefe ulaşana kadar konumu tekrar tekrar okur; koşul yanlış olunca döngüden çıkılır ve motor durdurulur. Bu yöntem süreye değil ölçüme dayandığı için kapı nereden başlarsa başlasın doğru yerde durur. == 0 yerine > 0 ile beklemek, değer bir adımda hedefi geçse bile programın takılmasını önler.

while (condition)door_pos_read()sensor
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    warning_light(255, 165, 0, WARN_ON);
    door_motor(DOOR_UP);
    while (door_pos_read() > 0)      // wait until fully open
        Sleep(50);
    door_motor(DOOR_STOP);
    warning_light_off();
    printf("Door is fully open\n");

    Sleep(1000);

    warning_light(255, 165, 0, WARN_ON);
    door_motor(DOOR_DOWN);
    while (door_pos_read() < 100)    // wait until fully closed
        Sleep(50);
    door_motor(DOOR_STOP);
    warning_light_off();
    printf("Door is fully closed\n");

    sim_disconnect();
    return 0;
}
from garage import *
import time

if sim_connect() != 0:
    exit(1)

warning_light(255, 165, 0, WARN_ON)
door_motor(DOOR_UP)
while door_pos_read() > 0:       # wait until fully open
    time.sleep(0.05)
door_motor(DOOR_STOP)
warning_light_off()
print("Door is fully open")

time.sleep(1)

warning_light(255, 165, 0, WARN_ON)
door_motor(DOOR_DOWN)
while door_pos_read() < 100:     # wait until fully closed
    time.sleep(0.05)
door_motor(DOOR_STOP)
warning_light_off()
print("Door is fully closed")

sim_disconnect()
16

Uç noktada motoru durduran bekçi

Sürekli çalışan bir bekçi program yazın: motor yukarı çalışıyorken kapı tam açıksa (0) ya da motor aşağı çalışıyorken kapı tam kapalıysa (100) motoru durdursun ve Limit reached, motor stopped yazsın. Döngü her 50 ms'de bir dönsün.
Programı çalışır halde bırakın ve kapıyı yalnızca elle kontrol panelindeki Kapı Yukarı / Kapı Aşağı düğmeleriyle hareket ettirin: kapı her uca geldiğinde kendiliğinden durmalı.

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.
17

Tuş takımıyla kumanda

Tuş takımını kumanda olarak kullanın: 1 → kapı yukarı, 2 → kapı aşağı, 0 → dur. Kapı uca ulaşınca motor kendiliğinden dursun (Görev 16). Motor çalışırken uyarı ışığı turuncu (255, 165, 0) yansın, motor durunca sönsün. Döngü her 50 ms'de bir dönsün.
Deneyin: 1'e basın, kapı yarıdayken 0'a basın, sonra 2'ye basın.

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.
18

Hangi tuş basılı?

Tuş takımının 12 tuşunu (0–11) bir for döngüsüyle tarayın ve basılı olan tuşu yazdırın: rakamlar için Key 7, 10 için Key #, 11 için Key X. Dış döngü her 200 ms'de bir dönsün.
Bir tuşu basılı tuttuğunuzda yazının tekrar tekrar geldiğine dikkat edin; bunu bir sonraki görevde düzelteceksiniz.

for döngüsü bir sayacı belirli bir aralıkta otomatik artırır; 12 ayrı if yazmak yerine aynı kontrol 12 kez tekrarlanır. Tuş takımında # 10, X 11 numaralı tuştur; bu yüzden bu iki değer ayrı yazdırılır.

forkey_read()ADR_KEY_HASHADR_KEY_X
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    while (1)
    {
        for (int k = 0; k <= 11; k++)          // check every key
        {
            if (key_read(k) == 1)
            {
                if (k == ADR_KEY_HASH)   printf("Key #\n");
                else if (k == ADR_KEY_X) printf("Key X\n");
                else                     printf("Key %d\n", k);
            }
        }
        Sleep(200);
    }
}
from garage import *
import time

if sim_connect() != 0:
    exit(1)

while True:
    for k in range(12):                    # check every key
        if key_read(k) == 1:
            if k == ADR_KEY_HASH:
                print("Key #")
            elif k == ADR_KEY_X:
                print("Key X")
            else:
                print(f"Key {k}")
    time.sleep(0.2)
19

Basışları say

# tuşuna kaç kez basıldığını sayın. Tuşu ne kadar uzun basılı tutarsanız tutun her basış yalnızca bir kez sayılsın; sayı her arttığında # pressed 3 times gibi yazdırın.
X tuşu sayacı sıfırlasın ve Counter reset yazsın (sayaç zaten 0 ise bir şey yapmasın). Döngü her 20 ms'de bir dönsün.

Basışı yakalamak için tuşun 0'dan 1'e geçtiği anı (yükselen kenar) aramak gerekir. previous değişkeni bir önceki okumayı saklar; yalnızca previous == 0 ve now == 1 olduğunda sayaç artar. Tuş basılı kaldıkça ikisi de 1 olduğundan tekrar sayılmaz.

edge detectioncounterprevious state
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    int count = 0;
    int previous = 0;                      // # state in the last round

    while (1)
    {
        int now = key_read(ADR_KEY_HASH);
        if (now == 1 && previous == 0)     // 0 -> 1: a new press
        {
            count++;
            printf("# pressed %d times\n", count);
        }
        previous = now;

        if (key_read(ADR_KEY_X) == 1 && count != 0)
        {
            count = 0;
            printf("Counter reset\n");
        }
        Sleep(20);
    }
}
from garage import *
import time

if sim_connect() != 0:
    exit(1)

count = 0
previous = 0                           # # state in the last round

while True:
    now = key_read(ADR_KEY_HASH)
    if now == 1 and previous == 0:     # 0 -> 1: a new press
        count += 1
        print(f"# pressed {count} times")
    previous = now

    if key_read(ADR_KEY_X) == 1 and count != 0:
        count = 0
        print("Counter reset")
    time.sleep(0.02)
20

Rakam kadar yanıp sön

Bir rakam tuşuna (1–9) basılmasını bekleyin, tuş bırakılınca da devam edin. Sonra Blinking 4 times gibi yazdırın ve garaj lambasını o rakam kadar yakıp söndürün (0,5 s yanık, 0,5 s sönük). Ardından yeni bir rakam bekleyin. 0, # ve X tuşları yok sayılsın.

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.
21

Dört haneli kodu oku

Tuş takımından 4 rakam okuyun (bu kez 0 da geçerli; # ve X yok sayılsın). Her rakam basılıp bırakıldığında uyarı ışığı 150 ms mavi (0, 0, 255) yansın (tuş sesi gibi) ve ekrana bir * yazılsın.
4 rakam tamamlanınca rakamları tek sayıda birleştirin (1, 2, 3, 4 → 1234) ve Code: 1234 yazın. Kod 1234 ise uyarı ışığı 3 saniye yeşil, değilse 3 saniye kırmızı yansın; sonra program bitsin.

code * 10 sayıyı bir basamak sola kaydırır, yeni rakam da en sağa eklenir: 0 → 1 → 12 → 123 → 1234. Rakamlar 0 ile 9 arasında olduğundan 'henüz tuş yok' bilgisi için -1 kullanılır. C'de * hemen görünsün diye fflush(stdout), Python'da flush=True kullanılır. %04d / :04d kod 0 ile başlasa bile 4 hane yazdırır.

code = code * 10 + digitfor-1 as no key
#include "garage.h"

int main(void)
{
    if (sim_connect() != 0) return 1;

    printf("Enter a 4-digit code: ");
    int code = 0;

    for (int n = 0; n < 4; n++)
    {
        int digit = -1;                        // -1 = no key yet
        while (digit == -1)
        {
            for (int k = 0; k <= 9; k++)
                if (key_read(k) == 1) digit = k;
            Sleep(20);
        }
        while (key_read(digit) == 1) Sleep(20);   // wait for release

        warning_light(0, 0, 255, WARN_ON);     // blue key beep
        Sleep(150);
        warning_light_off();
        printf("*");
        fflush(stdout);

        code = code * 10 + digit;
    }

    printf("\nCode: %04d\n", code);
    if (code == 1234) warning_light(0, 255, 0, WARN_ON);
    else              warning_light(255, 0, 0, WARN_ON);
    Sleep(3000);
    warning_light_off();

    sim_disconnect();
    return 0;
}
from garage import *
import time

if sim_connect() != 0:
    exit(1)

print("Enter a 4-digit code: ", end="", flush=True)
code = 0

for n in range(4):
    digit = -1                             # -1 = no key yet
    while digit == -1:
        for k in range(10):
            if key_read(k) == 1:
                digit = k
        time.sleep(0.02)
    while key_read(digit) == 1:            # wait for release
        time.sleep(0.02)

    warning_light(0, 0, 255, WARN_ON)      # blue key beep
    time.sleep(0.15)
    warning_light_off()
    print("*", end="", flush=True)

    code = code * 10 + digit

print(f"\nCode: {code:04d}")
if code == 1234:
    warning_light(0, 255, 0, WARN_ON)
else:
    warning_light(255, 0, 0, WARN_ON)
time.sleep(3)
warning_light_off()

sim_disconnect()

4 İleri

Fonksiyonlar, zamanlama, durum makineleri ve hataya dayanıklılık.
22

Fonksiyonlarla şifreli kapı

Görev 21'i fonksiyonlara bölün ve sürekli çalışan bir şifreli kapı yapın:
• wait_key(): herhangi bir tuşun (0–11) basılıp bırakılmasını bekler, 150 ms mavi tuş ışığı yakar ve tuşun numarasını döndürür.
• open_door() ve close_door(): kapıyı sensöre bakarak tam açar / tam kapatır; hareket sırasında uyarı ışığı turuncu yanar (Görev 15).
Ana döngü 4 rakam okusun (# ve X yok sayılsın) ve her rakam için * yazsın. Kod 1234 ise Access granted yazıp lambayı yaksın, kapıyı açsın, 5 saniye beklesin, kapıyı kapatıp lambayı söndürsün. Yanlışsa Wrong code yazıp uyarı ışığını 2 saniye kırmızı yaksın.

Fonksiyon, bir işi bir kez yazıp istediğiniz yerde adıyla çağırmanızı sağlar. Ana döngü artık 'ne yapılacağını' anlatır, ayrıntılar fonksiyonların içindedir; bu kodu okumayı ve hatayı bulmayı kolaylaştırır. wait_key() tuş numarasını return ile geri verir; k <= 9 kontrolü # (10) ve X (11) tuşlarını atlar.

functionreturnvoid
#include "garage.h"

// Waits for a key press + release, returns the key number (0..11)
int wait_key(void)
{
    int key = -1;
    while (key == -1)
    {
        for (int k = 0; k <= 11; k++)
            if (key_read(k) == 1) key = k;
        Sleep(20);
    }
    while (key_read(key) == 1) Sleep(20);   // wait for release

    warning_light(0, 0, 255, WARN_ON);       // blue key beep
    Sleep(150);
    warning_light_off();
    return key;
}

void open_door(void)
{
    warning_light(255, 165, 0, WARN_ON);
    door_motor(DOOR_UP);
    while (door_pos_read() > 0) Sleep(50);
    door_motor(DOOR_STOP);
    warning_light_off();
}

void close_door(void)
{
    warning_light(255, 165, 0, WARN_ON);
    door_motor(DOOR_DOWN);
    while (door_pos_read() < 100) Sleep(50);
    door_motor(DOOR_STOP);
    warning_light_off();
}

int main(void)
{
    if (sim_connect() != 0) return 1;

    while (1)
    {
        printf("Enter code: ");
        int code = 0;
        int n = 0;
        while (n < 4)
        {
            int k = wait_key();
            if (k <= 9)                    // ignore # and X
            {
                code = code * 10 + k;
                n++;
                printf("*");
                fflush(stdout);
            }
        }
        printf("\n");

        if (code == 1234)
        {
            printf("Access granted\n");
            garage_lamp(LAMP_ON);
            open_door();
            Sleep(5000);
            close_door();
            garage_lamp(LAMP_OFF);
        }
        else
        {
            printf("Wrong code\n");
            warning_light(255, 0, 0, WARN_ON);
            Sleep(2000);
            warning_light_off();
        }
    }
}
from garage import *
import time


def wait_key():
    """Waits for a key press + release, returns the key number (0..11)."""
    key = -1
    while key == -1:
        for k in range(12):
            if key_read(k) == 1:
                key = k
        time.sleep(0.02)
    while key_read(key) == 1:              # wait for release
        time.sleep(0.02)

    warning_light(0, 0, 255, WARN_ON)      # blue key beep
    time.sleep(0.15)
    warning_light_off()
    return key


def open_door():
    warning_light(255, 165, 0, WARN_ON)
    door_motor(DOOR_UP)
    while door_pos_read() > 0:
        time.sleep(0.05)
    door_motor(DOOR_STOP)
    warning_light_off()


def close_door():
    warning_light(255, 165, 0, WARN_ON)
    door_motor(DOOR_DOWN)
    while door_pos_read() < 100:
        time.sleep(0.05)
    door_motor(DOOR_STOP)
    warning_light_off()


if sim_connect() != 0:
    exit(1)

while True:
    print("Enter code: ", end="", flush=True)
    code = 0
    n = 0
    while n < 4:
        k = wait_key()
        if k <= 9:                         # ignore # and X
            code = code * 10 + k
            n += 1
            print("*", end="", flush=True)
    print()

    if code == 1234:
        print("Access granted")
        garage_lamp(LAMP_ON)
        open_door()
        time.sleep(5)
        close_door()
        garage_lamp(LAMP_OFF)
    else:
        print("Wrong code")
        warning_light(255, 0, 0, WARN_ON)
        time.sleep(2)
        warning_light_off()
23

Dizide şifre: X ile sil, # ile onayla

Şifre artık sabit uzunlukta değil. Kullanıcı rakamları yazar ve # ile onaylar:
• Her rakam bir dizide saklansın ve * yazılsın; en fazla 8 rakam saklansın, fazlası yok sayılsın.
• X, o ana kadar yazılanları silsin, Cleared yazsın ve uyarı ışığı 300 ms sarı (255, 255, 0) yansın.
• Doğru şifre 2580'dir ve bir dizide ({2, 5, 8, 0}) saklanır. #'e basılınca girilen rakamları şifreyle karşılaştırın: uzunluk ve tüm rakamlar aynıysa kapıyı Görev 22'deki gibi açıp kapatın (lamba dahil), değilse Wrong code yazıp 2 saniye kırmızı yakın.
Her denemeden sonra giriş sıfırlansın. Görev 22'deki fonksiyonları kullanın.

Dizi, aynı türden birçok değeri numaralı kutularda saklar: entered[0] ilk rakamdır. C'de dizinin boyu sabit olduğundan kaç kutunun dolu olduğunu len tutar. check_code() önce uzunluğa bakar, sonra rakamları tek tek karşılaştırır ve ilk farkta 0 döndürür. Python'da entered == PASSWORD aynı işi yapar: iki listenin uzunluğu ve tüm elemanları aynıysa doğrudur.

array / listcheck_code()# / X keys
#include "garage.h"

#define MAX_DIGITS 8

int password[4] = {2, 5, 8, 0};
int password_len = 4;

int wait_key(void)
{
    int key = -1;
    while (key == -1)
    {
        for (int k = 0; k <= 11; k++)
            if (key_read(k) == 1) key = k;
        Sleep(20);
    }
    while (key_read(key) == 1) Sleep(20);
    warning_light(0, 0, 255, WARN_ON);
    Sleep(150);
    warning_light_off();
    return key;
}

void open_door(void)
{
    warning_light(255, 165, 0, WARN_ON);
    door_motor(DOOR_UP);
    while (door_pos_read() > 0) Sleep(50);
    door_motor(DOOR_STOP);
    warning_light_off();
}

void close_door(void)
{
    warning_light(255, 165, 0, WARN_ON);
    door_motor(DOOR_DOWN);
    while (door_pos_read() < 100) Sleep(50);
    door_motor(DOOR_STOP);
    warning_light_off();
}

// Returns 1 if the typed digits equal the password
int check_code(int entered[], int len)
{
    if (len != password_len) return 0;
    for (int i = 0; i < len; i++)
        if (entered[i] != password[i]) return 0;
    return 1;
}

int main(void)
{
    if (sim_connect() != 0) return 1;

    int entered[MAX_DIGITS];
    int len = 0;
    printf("Type the code and press #. X clears.\n");

    while (1)
    {
        int k = wait_key();
        if (k <= 9)                            // a digit
        {
            if (len < MAX_DIGITS)
            {
                entered[len] = k;
                len++;
                printf("*");
                fflush(stdout);
            }
        }
        else if (k == ADR_KEY_X)               // clear
        {
            len = 0;
            printf("\nCleared\n");
            warning_light(255, 255, 0, WARN_ON);
            Sleep(300);
            warning_light_off();
        }
        else                                   // # = confirm
        {
            printf("\n");
            if (check_code(entered, len))
            {
                printf("Access granted\n");
                garage_lamp(LAMP_ON);
                open_door();
                Sleep(5000);
                close_door();
                garage_lamp(LAMP_OFF);
            }
            else
            {
                printf("Wrong code\n");
                warning_light(255, 0, 0, WARN_ON);
                Sleep(2000);
                warning_light_off();
            }
            len = 0;
        }
    }
}
from garage import *
import time

MAX_DIGITS = 8
PASSWORD = [2, 5, 8, 0]


def wait_key():
    key = -1
    while key == -1:
        for k in range(12):
            if key_read(k) == 1:
                key = k
        time.sleep(0.02)
    while key_read(key) == 1:
        time.sleep(0.02)
    warning_light(0, 0, 255, WARN_ON)
    time.sleep(0.15)
    warning_light_off()
    return key


def open_door():
    warning_light(255, 165, 0, WARN_ON)
    door_motor(DOOR_UP)
    while door_pos_read() > 0:
        time.sleep(0.05)
    door_motor(DOOR_STOP)
    warning_light_off()


def close_door():
    warning_light(255, 165, 0, WARN_ON)
    door_motor(DOOR_DOWN)
    while door_pos_read() < 100:
        time.sleep(0.05)
    door_motor(DOOR_STOP)
    warning_light_off()


if sim_connect() != 0:
    exit(1)

entered = []
print("Type the code and press #. X clears.")

while True:
    k = wait_key()
    if k <= 9:                             # a digit
        if len(entered) < MAX_DIGITS:
            entered.append(k)
            print("*", end="", flush=True)
    elif k == ADR_KEY_X:                   # clear
        entered = []
        print("\nCleared")
        warning_light(255, 255, 0, WARN_ON)
        time.sleep(0.3)
        warning_light_off()
    else:                                  # # = confirm
        print()
        if entered == PASSWORD:            # same length and same digits
            print("Access granted")
            garage_lamp(LAMP_ON)
            open_door()
            time.sleep(5)
            close_door()
            garage_lamp(LAMP_OFF)
        else:
            print("Wrong code")
            warning_light(255, 0, 0, WARN_ON)
            time.sleep(2)
            warning_light_off()
        entered = []
24

Yanlış deneme sayacı ve kilit

Görev 23'e güvenlik ekleyin: yanlış denemeleri sayın ve Wrong code (2/3) gibi yazdırın. Art arda 3 yanlış denemede sistem 15 saniye kilitlensin:
• LOCKED for 15 s yazılsın.
• Kilit süresince uyarı ışığı kırmızı yanıp sönsün (250 ms yanık, 250 ms sönük) ve tuşlar dikkate alınmasın.
• Kilit bitince Unlocked yazılsın ve sayaç sıfırlansın.
Doğru şifre girildiğinde de sayaç sıfırlansın. 1. ve 2. yanlış denemede önceki gibi 2 saniye kırmızı yansın.

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.
25

Kapanırken engel: güvenlik geri dönüşü

Gerçek garaj kapıları kapanırken önüne bir engel çıkarsa durup geri açılır. Simülasyonda engel sensörü olmadığı için X tuşunu 'engel algılandı' düğmesi olarak kullanın.
close_door_safe() adında bir fonksiyon yazın: kapıyı kapatırken her 50 ms'de konumla birlikte X tuşunu da kontrol etsin. X basılırsa motoru hemen durdursun, Obstacle! Reopening yazsın, uyarı ışığını 1 saniye kırmızı yaksın, kapıyı tam açsın ve 0 döndürsün. Kapı engelsiz kapanırsa 1 döndürsün.
Ana program: #'e basılınca kapıyı açsın, 5 saniye beklesin ve close_door_safe() ile kapatsın; kapı engel yüzünden yeniden açıldıysa 5 saniye bekleyip tekrar kapatmayı denesin. Kapı kapanınca Door closed yazsın.

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.
26

Şifre girişinde zaman aşımı

Görev 23'teki şifre girişine zaman aşımı ekleyin: kullanıcı en az bir rakam yazdıktan sonra 5 saniye hiçbir tuşa basmazsa giriş silinsin, Timeout, entry cleared yazılsın ve uyarı ışığı 1 saniye sarı yansın.
Bunun için wait_key_timeout(ms) fonksiyonunu yazın: verilen süre içinde bir tuş basılıp bırakılırsa (mavi tuş ışığıyla birlikte) numarasını, süre dolarsa -1 döndürsün. Bu görevde kapıyı hareket ettirmeyin: doğru şifrede Access granted yazıp 3 saniye yeşil, yanlışta Wrong code yazıp 2 saniye kırmızı yakın.

Zaman aşımı 'şimdiki zaman − başlangıç zamanı ≥ süre' sorusuyla anlaşılır. wait_key_timeout() beklerken saati sürekli kontrol eder ve süre dolunca -1 döndürür. Ana döngü -1 aldığında giriş boşsa hiçbir şey yapmaz, yeniden bekler; doluysa girişi siler. Böylece yarım bırakılan bir şifre bir sonraki kullanıcıya kalmaz.

GetTickCount / time.timetimeoutwait_key_timeout()
#include "garage.h"

#define MAX_DIGITS 8

int password[4] = {2, 5, 8, 0};
int password_len = 4;

// Returns the pressed key (0..11) or -1 if no key came within ms
int wait_key_timeout(DWORD ms)
{
    DWORD start = GetTickCount();
    while (GetTickCount() - start < ms)
    {
        for (int k = 0; k <= 11; k++)
        {
            if (key_read(k) == 1)
            {
                while (key_read(k) == 1) Sleep(20);   // wait for release
                warning_light(0, 0, 255, WARN_ON);
                Sleep(150);
                warning_light_off();
                return k;
            }
        }
        Sleep(20);
    }
    return -1;                                 // time is up
}

int check_code(int entered[], int len)
{
    if (len != password_len) return 0;
    for (int i = 0; i < len; i++)
        if (entered[i] != password[i]) return 0;
    return 1;
}

int main(void)
{
    if (sim_connect() != 0) return 1;

    int entered[MAX_DIGITS];
    int len = 0;
    printf("Type the code and press #. X clears.\n");

    while (1)
    {
        int k = wait_key_timeout(5000);
        if (k == -1)                           // 5 s without a key
        {
            if (len > 0)
            {
                len = 0;
                printf("\nTimeout, entry cleared\n");
                warning_light(255, 255, 0, WARN_ON);
                Sleep(1000);
                warning_light_off();
            }
        }
        else if (k <= 9)
        {
            if (len < MAX_DIGITS)
            {
                entered[len] = k;
                len++;
                printf("*");
                fflush(stdout);
            }
        }
        else if (k == ADR_KEY_X)
        {
            len = 0;
            printf("\nCleared\n");
            warning_light(255, 255, 0, WARN_ON);
            Sleep(300);
            warning_light_off();
        }
        else                                   // #
        {
            printf("\n");
            if (check_code(entered, len))
            {
                printf("Access granted\n");
                warning_light(0, 255, 0, WARN_ON);
                Sleep(3000);
            }
            else
            {
                printf("Wrong code\n");
                warning_light(255, 0, 0, WARN_ON);
                Sleep(2000);
            }
            warning_light_off();
            len = 0;
        }
    }
}
from garage import *
import time

MAX_DIGITS = 8
PASSWORD = [2, 5, 8, 0]


def wait_key_timeout(ms):
    """Returns the pressed key (0..11) or -1 if no key came within ms."""
    start = time.time()
    while (time.time() - start) * 1000 < ms:
        for k in range(12):
            if key_read(k) == 1:
                while key_read(k) == 1:    # wait for release
                    time.sleep(0.02)
                warning_light(0, 0, 255, WARN_ON)
                time.sleep(0.15)
                warning_light_off()
                return k
        time.sleep(0.02)
    return -1                              # time is up


if sim_connect() != 0:
    exit(1)

entered = []
print("Type the code and press #. X clears.")

while True:
    k = wait_key_timeout(5000)
    if k == -1:                            # 5 s without a key
        if len(entered) > 0:
            entered = []
            print("\nTimeout, entry cleared")
            warning_light(255, 255, 0, WARN_ON)
            time.sleep(1)
            warning_light_off()
    elif k <= 9:
        if len(entered) < MAX_DIGITS:
            entered.append(k)
            print("*", end="", flush=True)
    elif k == ADR_KEY_X:
        entered = []
        print("\nCleared")
        warning_light(255, 255, 0, WARN_ON)
        time.sleep(0.3)
        warning_light_off()
    else:                                  # #
        print()
        if entered == PASSWORD:
            print("Access granted")
            warning_light(0, 255, 0, WARN_ON)
            time.sleep(3)
        else:
            print("Wrong code")
            warning_light(255, 0, 0, WARN_ON)
            time.sleep(2)
        warning_light_off()
        entered = []
27

Programı durdurmadan yanıp sönme

Görev 17'deki tuş kumandasını geliştirin: kapı hareket ederken uyarı ışığı turuncu (255, 165, 0) yanıp sönsün (300 ms yanık, 300 ms sönük), ama tuşlar her an hemen tepki versin.
Yani yanıp sönmeyi Sleep(300) / time.sleep(0.3) ile YAPMAYIN: döngü 20 ms'de bir dönsün; her turda saati okuyun, son değişimden bu yana 300 ms geçtiyse ışığı tersine çevirin. Motor durunca ışık sönük kalsın. Kapı yarıdayken 0'a basarak kapının hemen durduğunu kontrol edin.

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.
28

Durum makinesiyle kapı

Kapıyı bir durum makinesiyle yönetin. Dört durum vardır: CLOSED, OPENING, OPEN, CLOSING.
• CLOSED: motor durur, lamba ve uyarı ışığı söner. # basılınca → OPENING.
• OPENING: lamba yanar, uyarı ışığı turuncu, motor yukarı. Konum 0 olunca → OPEN.
• OPEN: motor durur, uyarı ışığı yeşil. 10 saniye geçince veya # basılınca → CLOSING.
• CLOSING: uyarı ışığı turuncu, motor aşağı. Konum 100 olunca → CLOSED; X basılırsa (engel) Obstacle! yazıp → OPENING.
Her durum değişiminde -> OPEN gibi yeni durumu yazdırın. Program başında kapı kapalı değilse CLOSING ile başlayın. Döngü 20 ms'de bir dönsün, hiçbir yerde uzun Sleep olmasın; tuşlar kenar algılamayla (Görev 19) okunsun.

Durum makinesinde program her an tek bir durumdadır ve her durum yalnızca kendi çıkış koşullarını bilir. Çıkışlar enter() içinde, durum değişirken bir kez ayarlanır. Hiçbir yerde uzun bekleme olmadığı için program kapı hareket ederken bile X tuşunu ve 10 saniyelik sayacı aynı anda izleyebilir. Yeni bir davranış eklemek, yeni bir durum ya da geçiş eklemek kadar kolaydır.

state machineenumenter()new_key()
#include "garage.h"

enum { CLOSED, OPENING, OPEN, CLOSING };
const char *names[] = { "CLOSED", "OPENING", "OPEN", "CLOSING" };

int state = CLOSED;
DWORD open_time = 0;           // when the door became OPEN
int last_key = -1;

// Returns a key number only at the moment it is pressed, otherwise -1
int new_key(void)
{
    int key = -1;
    for (int k = 0; k <= 11; k++)
        if (key_read(k) == 1) key = k;
    int result = -1;
    if (key != last_key) result = key;
    last_key = key;
    return result;
}

// Switches to a new state and sets the outputs once
void enter(int s)
{
    state = s;
    printf("-> %s\n", names[s]);
    if (s == CLOSED)
    {
        door_motor(DOOR_STOP);
        warning_light_off();
        garage_lamp(LAMP_OFF);
    }
    else if (s == OPENING)
    {
        garage_lamp(LAMP_ON);
        warning_light(255, 165, 0, WARN_ON);
        door_motor(DOOR_UP);
    }
    else if (s == OPEN)
    {
        door_motor(DOOR_STOP);
        warning_light(0, 255, 0, WARN_ON);
        open_time = GetTickCount();
    }
    else                                       // CLOSING
    {
        garage_lamp(LAMP_ON);
        warning_light(255, 165, 0, WARN_ON);
        door_motor(DOOR_DOWN);
    }
}

int main(void)
{
    if (sim_connect() != 0) return 1;

    if (door_pos_read() >= 100) enter(CLOSED);
    else                        enter(CLOSING);

    while (1)
    {
        int key = new_key();
        int pos = door_pos_read();

        if (state == CLOSED)
        {
            if (key == ADR_KEY_HASH) enter(OPENING);
        }
        else if (state == OPENING)
        {
            if (pos <= 0) enter(OPEN);
        }
        else if (state == OPEN)
        {
            if (key == ADR_KEY_HASH || GetTickCount() - open_time >= 10000)
                enter(CLOSING);
        }
        else                                   // CLOSING
        {
            if (key == ADR_KEY_X)
            {
                printf("Obstacle!\n");
                enter(OPENING);
            }
            else if (pos >= 100) enter(CLOSED);
        }
        Sleep(20);
    }
}
from garage import *
import time

CLOSED, OPENING, OPEN, CLOSING = 0, 1, 2, 3
NAMES = ["CLOSED", "OPENING", "OPEN", "CLOSING"]

state = CLOSED
open_time = 0.0                # when the door became OPEN
last_key = -1


def new_key():
    """Returns a key number only at the moment it is pressed, otherwise -1."""
    global last_key
    key = -1
    for k in range(12):
        if key_read(k) == 1:
            key = k
    result = -1
    if key != last_key:
        result = key
    last_key = key
    return result


def enter(s):
    """Switches to a new state and sets the outputs once."""
    global state, open_time
    state = s
    print(f"-> {NAMES[s]}")
    if s == CLOSED:
        door_motor(DOOR_STOP)
        warning_light_off()
        garage_lamp(LAMP_OFF)
    elif s == OPENING:
        garage_lamp(LAMP_ON)
        warning_light(255, 165, 0, WARN_ON)
        door_motor(DOOR_UP)
    elif s == OPEN:
        door_motor(DOOR_STOP)
        warning_light(0, 255, 0, WARN_ON)
        open_time = time.time()
    else:                                  # CLOSING
        garage_lamp(LAMP_ON)
        warning_light(255, 165, 0, WARN_ON)
        door_motor(DOOR_DOWN)


if sim_connect() != 0:
    exit(1)

if door_pos_read() >= 100:
    enter(CLOSED)
else:
    enter(CLOSING)

while True:
    key = new_key()
    pos = door_pos_read()

    if state == CLOSED:
        if key == ADR_KEY_HASH:
            enter(OPENING)
    elif state == OPENING:
        if pos <= 0:
            enter(OPEN)
    elif state == OPEN:
        if key == ADR_KEY_HASH or time.time() - open_time >= 10:
            enter(CLOSING)
    else:                                  # CLOSING
        if key == ADR_KEY_X:
            print("Obstacle!")
            enter(OPENING)
        elif pos >= 100:
            enter(CLOSED)
    time.sleep(0.02)

5 Proje

Her şeyi birleştiren tam sistemler.
29

Tam garaj kontrolcüsü

Görev 28'deki durum makinesini şifreli girişle birleştirin. Durumlar: CLOSED, OPENING, OPEN, CLOSING, LOCKED.
• CLOSED: tuş takımından şifre alınır (Görev 23–26). Rakam → * ve 100 ms mavi ışık (en fazla 8 rakam); X → girişi sil, 300 ms sarı; # → kontrol. Şifre 2580. Doğruysa Access granted → OPENING. Yanlışsa Wrong code (n/3) ve 1 s kırmızı; 3. yanlışta → LOCKED. Giriş doluyken 5 s tuşa basılmazsa Timeout, entry cleared ve 1 s sarı.
• LOCKED: 15 s boyunca uyarı ışığı kırmızı yanıp söner (250 ms), tuşlar yok sayılır; sonra Unlocked → CLOSED.
• OPENING: lamba yanar, motor yukarı, uyarı ışığı turuncu yanıp söner (300 ms, programı durdurmadan — Görev 27). Konum 0 → OPEN.
• OPEN: motor durur, ışık sabit yeşil. 10 s sonra veya # ile → CLOSING.
• CLOSING: motor aşağı, turuncu yanıp sönme. X → Obstacle! Reopening → OPENING. Konum 100 → CLOSED.
CLOSED ve LOCKED durumlarında motor durur, lamba ve uyarı ışığı söner, giriş silinir. Her durum değişimi -> OPEN gibi yazdırılsın; program başında kapı kapalı değilse CLOSING ile başlansın.

Program, önceki görevlerdeki parçaların birleşimidir: kenar algılamalı tuş okuma, dizide şifre, deneme sayacı, zaman aşımı, programı durdurmadan yanıp sönme ve güvenlik geri dönüşü. Durum makinesi bunları düzenli tutar: her durum yalnızca kendi işini yapar. Yalnızca CLOSED durumundaki kısa tuş ışıkları (100–1000 ms) bekletir; o sırada motor zaten durmaktadır. state_time her yeni durumda sıfırlandığı için aynı değişken hem kilit hem otomatik kapanma süresini ölçer.

state machinenon-blockingarray / listtimeoutsafety stop
#include "garage.h"

enum { CLOSED, OPENING, OPEN, CLOSING, LOCKED };
const char *names[] = { "CLOSED", "OPENING", "OPEN", "CLOSING", "LOCKED" };

#define MAX_DIGITS 8
int password[4] = {2, 5, 8, 0};
int password_len = 4;

int state = CLOSED;
DWORD state_time = 0;          // when the current state started
DWORD blink_time = 0;          // last blink change
int blink_on = 0;
int last_key = -1;

int entered[MAX_DIGITS];
int len = 0;
DWORD last_key_time = 0;       // for the entry timeout
int wrong = 0;

int new_key(void)
{
    int key = -1;
    for (int k = 0; k <= 11; k++)
        if (key_read(k) == 1) key = k;
    int result = -1;
    if (key != last_key) result = key;
    last_key = key;
    return result;
}

int check_code(void)
{
    if (len != password_len) return 0;
    for (int i = 0; i < len; i++)
        if (entered[i] != password[i]) return 0;
    return 1;
}

// Short light signal (only used while the motor is stopped)
void flash(int r, int g, int b, int ms)
{
    warning_light(r, g, b, WARN_ON);
    Sleep(ms);
    warning_light_off();
}

// Blinks the warning light without stopping the program
void blink(int r, int g, int b, DWORD period)
{
    if (GetTickCount() - blink_time >= period)
    {
        blink_on = !blink_on;
        if (blink_on) warning_light(r, g, b, WARN_ON);
        else          warning_light_off();
        blink_time = GetTickCount();
    }
}

void enter(int s)
{
    state = s;
    state_time = GetTickCount();
    blink_time = state_time;
    blink_on = 0;
    warning_light_off();
    printf("-> %s\n", names[s]);

    if (s == CLOSED || s == LOCKED)
    {
        door_motor(DOOR_STOP);
        garage_lamp(LAMP_OFF);
        len = 0;
    }
    else if (s == OPENING)
    {
        garage_lamp(LAMP_ON);
        door_motor(DOOR_UP);
    }
    else if (s == OPEN)
    {
        door_motor(DOOR_STOP);
        warning_light(0, 255, 0, WARN_ON);
    }
    else                                       // CLOSING
    {
        garage_lamp(LAMP_ON);
        door_motor(DOOR_DOWN);
    }
}

// CLOSED state: collects and checks the code
void handle_code(int key)
{
    if (key >= 0 && key <= 9)
    {
        if (len < MAX_DIGITS)
        {
            entered[len] = key;
            len++;
            printf("*");
            fflush(stdout);
        }
        last_key_time = GetTickCount();
        flash(0, 0, 255, 100);
    }
    else if (key == ADR_KEY_X)
    {
        len = 0;
        printf("\nCleared\n");
        flash(255, 255, 0, 300);
    }
    else if (key == ADR_KEY_HASH)
    {
        printf("\n");
        if (check_code())
        {
            wrong = 0;
            printf("Access granted\n");
            enter(OPENING);
        }
        else
        {
            wrong++;
            printf("Wrong code (%d/3)\n", wrong);
            len = 0;
            if (wrong >= 3)
            {
                wrong = 0;
                enter(LOCKED);
            }
            else flash(255, 0, 0, 1000);
        }
    }
    else if (len > 0 && GetTickCount() - last_key_time >= 5000)
    {
        len = 0;
        printf("\nTimeout, entry cleared\n");
        flash(255, 255, 0, 1000);
    }
}

int main(void)
{
    if (sim_connect() != 0) return 1;

    printf("Code 2580 + #. X = clear / obstacle. Ctrl+C to quit.\n");
    if (door_pos_read() >= 100) enter(CLOSED);
    else                        enter(CLOSING);

    while (1)
    {
        int key = new_key();
        int pos = door_pos_read();

        if (state == CLOSED)
        {
            handle_code(key);
        }
        else if (state == LOCKED)
        {
            blink(255, 0, 0, 250);
            if (GetTickCount() - state_time >= 15000)
            {
                printf("Unlocked\n");
                enter(CLOSED);
            }
        }
        else if (state == OPENING)
        {
            blink(255, 165, 0, 300);
            if (pos <= 0) enter(OPEN);
        }
        else if (state == OPEN)
        {
            if (key == ADR_KEY_HASH || GetTickCount() - state_time >= 10000)
                enter(CLOSING);
        }
        else                                   // CLOSING
        {
            blink(255, 165, 0, 300);
            if (key == ADR_KEY_X)
            {
                printf("Obstacle! Reopening\n");
                enter(OPENING);
            }
            else if (pos >= 100) enter(CLOSED);
        }
        Sleep(20);
    }
}
from garage import *
import time

CLOSED, OPENING, OPEN, CLOSING, LOCKED = 0, 1, 2, 3, 4
NAMES = ["CLOSED", "OPENING", "OPEN", "CLOSING", "LOCKED"]

MAX_DIGITS = 8
PASSWORD = [2, 5, 8, 0]

state = CLOSED
state_time = 0.0               # when the current state started
blink_time = 0.0               # last blink change
blink_on = False
last_key = -1

entered = []
last_key_time = 0.0            # for the entry timeout
wrong = 0


def new_key():
    global last_key
    key = -1
    for k in range(12):
        if key_read(k) == 1:
            key = k
    result = -1
    if key != last_key:
        result = key
    last_key = key
    return result


def flash(r, g, b, seconds):
    """Short light signal (only used while the motor is stopped)."""
    warning_light(r, g, b, WARN_ON)
    time.sleep(seconds)
    warning_light_off()


def blink(r, g, b, period):
    """Blinks the warning light without stopping the program."""
    global blink_on, blink_time
    if time.time() - blink_time >= period:
        blink_on = not blink_on
        if blink_on:
            warning_light(r, g, b, WARN_ON)
        else:
            warning_light_off()
        blink_time = time.time()


def enter(s):
    global state, state_time, blink_time, blink_on
    state = s
    state_time = time.time()
    blink_time = state_time
    blink_on = False
    warning_light_off()
    print(f"-> {NAMES[s]}")

    if s == CLOSED or s == LOCKED:
        door_motor(DOOR_STOP)
        garage_lamp(LAMP_OFF)
        entered.clear()
    elif s == OPENING:
        garage_lamp(LAMP_ON)
        door_motor(DOOR_UP)
    elif s == OPEN:
        door_motor(DOOR_STOP)
        warning_light(0, 255, 0, WARN_ON)
    else:                                  # CLOSING
        garage_lamp(LAMP_ON)
        door_motor(DOOR_DOWN)


def handle_code(key):
    """CLOSED state: collects and checks the code."""
    global last_key_time, wrong
    if 0 <= key <= 9:
        if len(entered) < MAX_DIGITS:
            entered.append(key)
            print("*", end="", flush=True)
        last_key_time = time.time()
        flash(0, 0, 255, 0.1)
    elif key == ADR_KEY_X:
        entered.clear()
        print("\nCleared")
        flash(255, 255, 0, 0.3)
    elif key == ADR_KEY_HASH:
        print()
        if entered == PASSWORD:
            wrong = 0
            print("Access granted")
            enter(OPENING)
        else:
            wrong += 1
            print(f"Wrong code ({wrong}/3)")
            entered.clear()
            if wrong >= 3:
                wrong = 0
                enter(LOCKED)
            else:
                flash(255, 0, 0, 1)
    elif len(entered) > 0 and time.time() - last_key_time >= 5:
        entered.clear()
        print("\nTimeout, entry cleared")
        flash(255, 255, 0, 1)


if sim_connect() != 0:
    exit(1)

print("Code 2580 + #. X = clear / obstacle. Ctrl+C to quit.")
if door_pos_read() >= 100:
    enter(CLOSED)
else:
    enter(CLOSING)

while True:
    key = new_key()
    pos = door_pos_read()

    if state == CLOSED:
        handle_code(key)
    elif state == LOCKED:
        blink(255, 0, 0, 0.25)
        if time.time() - state_time >= 15:
            print("Unlocked")
            enter(CLOSED)
    elif state == OPENING:
        blink(255, 165, 0, 0.3)
        if pos <= 0:
            enter(OPEN)
    elif state == OPEN:
        if key == ADR_KEY_HASH or time.time() - state_time >= 10:
            enter(CLOSING)
    else:                                  # CLOSING
        blink(255, 165, 0, 0.3)
        if key == ADR_KEY_X:
            print("Obstacle! Reopening")
            enter(OPENING)
        elif pos >= 100:
            enter(CLOSED)
    time.sleep(0.02)
30

Kapıyı istenen konuma götür

Kapıyı tuş takımıyla istenen konuma götürün. Kullanıcı 0–100 arası bir kapalılık yüzdesi yazar ve # ile onaylar (ör. 5, 0, # → %50). Yazılan rakamlar ekranda görünsün; en fazla 3 rakam alınsın. X yazılan sayıyı silsin (Cleared).
• Hiç rakam yoksa ya da değer 100'den büyükse Invalid yazıp uyarı ışığını 1 saniye kırmızı yakın.
• Kapı zaten o konumdaysa Already there yazın.
• Aksi halde program yönü kendisi seçsin: hedef şu anki değerden küçükse kapı yukarı, büyükse aşağı gitsin; hedefe ulaşınca dursun. Hareket sırasında uyarı ışığı turuncu yansın ve konum her değiştiğinde 45% -> 50% gibi yazdırılsın. Hedefe varınca Arrived yazıp 1 saniye yeşil yakın.
• Hareket sırasında X basılırsa kapı hemen dursun ve Stopped yazılsın.

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.
31

Yönetici modu: şifre değiştirme

Şifre, program değiştirilmeden güncellenebilsin. Kullanıcı şifresi başlangıçta 1234, yönetici şifresi sabit 9999'dur. Tüm girişler # ile onaylanır, X girişi siler (Cleared); her rakam için * yazılır, en fazla 8 rakam alınır.
• Kullanıcı şifresi girilirse: Access granted, kapıyı açın, 5 s bekleyin, kapatın (Görev 22'deki fonksiyonlar).
• Yönetici şifresi girilirse: Admin mode yazılır ve uyarı ışığı sürekli sarı (255, 255, 0) yanar. Enter new code: yazılır, kullanıcı yeni şifreyi yazıp #'e basar; sonra Repeat new code: yazılır ve aynı şifre tekrar girilir. İki giriş aynıysa ve en az 4 rakamlıysa şifre değişir: Code changed yazılır ve uyarı ışığı iki kez yeşil yanıp söner (300 ms yanık, 300 ms sönük). Değilse Code NOT changed yazılır ve 2 s kırmızı yanar.
• Başka bir giriş: Wrong code ve 2 s kırmızı.
Not: Sürekli sarı ışık bozulmasın diye bu görevde tuş ışığı (mavi) kullanmayın.

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.
32

Çok kullanıcılı garaj ve rapor

Garajı üç kişi kullanıyor ve her birinin 4 haneli kodu var: Ali 1111, Ayse 2222, Can 3333. İsimleri bir dizide, kodları iki boyutlu bir dizide (listelerin listesi) saklayın. Girişler Görev 31'deki gibi okunur (*, X siler, # onaylar).
• Bir kullanıcının kodu girilirse Welcome, Ayse yazılsın, o kişinin açma sayısı 1 artsın, lamba yansın, kapı açılsın, 5 s sonra Görev 25'teki close_door_safe() ile kapatılsın (engel yüzünden açıldıysa 5 s sonra tekrar denensin) ve lamba sönsün.
• Bilinmeyen bir kod girilirse Unknown code yazılsın, yanlış deneme sayacı artsın ve 2 s kırmızı yansın.
• Yalnızca 0 girilip #'e basılırsa rapor yazdırılsın:
Ali: 2 openings
Ayse: 0 openings
Can: 1 openings
Wrong attempts: 1
Total openings: 3

Cevap sende

Bu görevin cevabı verilmiyor. Önceki görevlerin cevaplarındaki fikirleri birleştirerek kendiniz çözün; çalışan programınız sizin cevabınızdır.