שאלה

BravoMan

Active member
ברור שהקוד קורס לך, כי יש ערך SCREEN וזה שם של פקודה,, המטרה הייתה רק להמחיש שמדובר במסך ואפשר לקרוא לזה SCR
זו לא הסיבה שהקוד קורס.
תאמין לי, אם זו היית כל הבעיה הייתי מתקן אותה בעצמי וממשיך לבדוק.

אתה כמובן מוזמן להמשיך ולשאול פה, ואם יהיו שאלות שאדע לענות אשמח לעזור לך, אבל לגבי הקוד ששלחת אני פשוט לא מצליח להוציא ממנו שום הגיון, ולמרות שבמבט מלמעלה נראה כאילו אתה אכן מנסה לעשות את מה שאתה מדבר עליו, בפועל ברגע שיורדים לפרטים של הקוד זה מתחיל להראות כמו בליל שטויות, או אולי אובפוסקציה שנועה במכוון לבלב את הקורא.

אני לא חושב שהתכוונת למשהו רע פה, אבל כמו שאמרתי קודם - כדי שאנשים אחרים יוכלו לעזור לך, אתה קודם כל צריך לעזור להם להבין מה עשית.
 
אני שולך לך שוב את שתי התכנות כשהן מעוצבות לפי כללי הנוחות שלימדת אותי, וגם את המילון. אשמח אם תבדוק אותן.
 

קבצים מצורפים

  • תוכנות מעוצבות.docx
    KB 38.5 · צפיות: 1
אני לא חושב ש הקוד שלי שטויות, אולי אתה לא מבין אותו כי הוא מיוחד ומסובך וצריך יותר לדעת את הפרטים של מה שניסיתי לעשות. לכן אני מנסה יותר לתאר לך את הרעיונות.
 

BravoMan

Active member
אני עובד עם הרבה מתכנתים מקצועיים שנמצאים במקצוע הרבה שנים, וכתבו מוצרים שאלפי אנשים משתמשים בהם.
גם הם אף פעם לא חושבים שהקוד שלהם שטויות, אבל לא פעם יצא לי למצוא אצלם באגים שהם באמת מטומטמים.

אתה צריך להבין: כולנו בני אדם וכולנו עושים טעויות.
כתיבת קוד היא דבר לא פשוט, ולרוב באגים בקוד נובעים מזה שהמתכנת חושב שהוא הורה למחשב לעשות משהו, כאשר בפועל הוא התבלבל או שגה בפקודות, ובעצם הורה למחשב לעשות משהו שונה לחלוטין.

מחשבים תמיד עושים בדיוק את מה שאמורים להם.
אין להם יכולת לחשוב בהגיון ולזהות טעויות של בני אדם.

הם יכולים להבדיל בין "פקודה חוקית" שהם מכירים ויכולים לבצע, לבין פקודה לא חוקית שהם לא מכירים או לא יכולים לבצע, אבל שום מחשב לא יוכל להגיד לך שנתת לו פקודה חוקית אך לא נכונה.

העובדה כרגע היא שהקוד שלך לא עושה את מה שאתה רוצה ממנו.
אחרת, במקום לבוא לכאן ולשאול למה, היית לך כבר בינה מלאכותית עובדת.

תרם סיימתי לעבור על הקוד שלך.
אני כבר יכול להגיד לך שעשית עבודה די טובה בהפיכתו לקריא יותר, גם אם עדיין פה ושם יש דברים שמקשים על ההבנה (למשל, לא כל השמות הגיוניים או מסבירים את עצמם).

דבר אחד מוזר ששמתי לב אליו:
בחלק קוד שאמור לעשות ציור צורות, אין באמת פקודות ציור.

האם הכוונה היא רק לייצר צורות בזיכרון, ולפי מיקומים, או שאתה מצפה שהצורות גם יופיע על המסך?
 
הקוד ששלחתי לך בהודעה הפתוחה הוא רק המחשה של מה שאני מנסה לעשות בתוכנה. אחר כך שלחתי לך שוב את התוכנות, ובתוכנה עצמה יש הפקודה PSET שזו פקודת ציור. השתדלתי לכתוב את התוכנות באופן יותר ברור לפי הכללים שלימדת אותי, הוספתי הערות וקראתי למשתנים בשמות ברורים. הקוד שלי מבוסס על מגמה מאד ברורה שניסיתי לתאר לך בהתחלה. מקווה שתצליח להבין ולעבוד על זה.
 

BravoMan

Active member
תגיד לי בבקשה, מה עושה השורה הזו:
קוד:
FOR F = 1 TO NN: x0$ = "x(" + STR$(F) + ")"
 
ככל שאני זוכר זה מהחלק של המילון. קובץ הבסיס שמצורף אחר כך להגדרות המלים, מכיל בין השאר לימוד ליישם פעולות מפעלים באנגלית שהם יוצרים רק תנאים ריקים, לפקודות בביסיק שמוכרות למחשב ומפעילות אותו. המשתנה X מקבל תוצאה שעוברת בלולאת ניחוש מספרי כדי למצוא את הפעולה שעונה על התנאי הארוך שבהגדרה. יש גם שיטה בתוכנה שכדי שלא יהיה רק משתנה אחד, X מוגדר כמשתנה בתוך מערך וכל פעם הוא מוצג כחלק מתקדם יותר במערך עד שחוזר להתחלת המערך וכן הלאה. בלי קשר לכל פעולה נלמדת יש מספר סידורי משלה, וכדי ללמד את המחשב לבצע אותה מציבים בה משתנה קצת אחר לפי הסדר. את התוצאות של קובץ הבסיס WW מבחינת X, גם מתוך לימוד פעולות וגם מתוך הגדרת תכונות של עצם בעזרת המלה CHARACTER, שומר המחשב בתוך קובץ יישום שהגדרת קובץ הבסיס יוצרת מתוך עצמה כשמפעילים אותה בתור חלק מתוכנה שהתוכנה שלי יצרה בעזרת ההגדרות.
 

BravoMan

Active member
לא... הרמתי ידיים.
אני לא יכול לפענח את הקוד שלך.

או שהוא מתוחכם מדי בשבילי (וגם בשביל QBASIC עצמו), או שהוא בליל שטויות שאין לו סיכוי לעבוד.
היה מעניין לראות קוד QBASIC אחרי כל השנים, האלה, וזה אף עודד אותי לכתוב תוכנה קטנה ב-QB שמאפשרת למשתמש לצייר קווים וצורות על המסך במצב גרפי.

אם תרצה, אשתף פה את הקוד.
 
אזכיר לך שהקוד שפרסמתי בשרשור רק דוגמא מופשטת בעוד הקוד האמתי נמצא בתוכנות. הוא מבוסס על המילון האנגלי שהכתבתי למחשב, ואולי הוא קצת ארוך מלפרסם במחשב. יש שתי תוכנות, תוכל לשתף את הקוד כדי שאנסה להסביר לך אותו.
 
נערך לאחרונה ב:
אגב, ניסיתי את שיטת הפרוצודורות ולא עבדה. המחשב כותב פרוצדורות אבל לא מזהה אותן כדי לעבור אליהן אוטומטית אלא כותב שגיאה. השיטה לכתוב משתנים בשמות אנושיים נחמדה מאד ועוזרת לזכור מה המשמעות, אבל היא מאד מאריכה את שמות המשתנים ואת השורות, מסרבלת וקשה לראות את כל השורה ולזכור מה היא עושה.
 

BravoMan

Active member
אם "שיטת הפרוצדורות" לא עובדת לך, סימן שאתה לא משתמש בה נכון!
קוד:
REM Putting global constants here, because can't find a better place... 
CONST CURLEN% = 2 'Cursor line length, cursor has 4 lines forming a crosshair 
CONST SCRWIDTH% = 319  'maximum X coordinate on screen 
CONST SCRHEIGHT% = 199 'maximum Y coordinate on screen 
CONST COLORON% = 15 
CONST COLOROFF% = 0 
CONST TRUE = 1 
CONST FALSE = 0 
CONST DOTSINSHAPE = 15 
CONST MAXSHAPES = 5 
 
REM Custom data types to describe our objects 
TYPE Dot 
  x AS INTEGER 
  y AS INTEGER 
END TYPE 
 
TYPE Shape 
  dotCount AS INTEGER 
  isClosed AS INTEGER 
END TYPE 
 
REM Autogenerated declarations 
DECLARE FUNCTION ADDDOT% (curPos AS ANY, curShape AS INTEGER, shapes() AS Shape, dots() AS Dot) 
DECLARE SUB DRAWSHAPE (shapes() AS Shape, dots() AS Dot, curPos AS Dot, i%) 
DECLARE SUB PAINTCURSOR (d AS Dot, CURCOLOR%) 
DECLARE FUNCTION MAX% (A%, B%) 
DECLARE FUNCTION MIN% (A%, B%) 
DECLARE FUNCTION MOVECURSOR% (k$, d AS ANY) 
 
REM This is main (though basic does not have main) 
SCREEN 7 
 
DIM shapes(MAXSHAPES) AS Shape 
DIM dots(MAXSHAPES, DOTSINSHAPE) AS Dot 'We have to do this because QB dosn't support arrays in user types 
curShape% = 0 
 
DIM curPos AS Dot 
DIM oldPos AS Dot 
 
curPos.x = SCRWIDTH% / 2 
curPos.y = SCRHEIGHT% / 2 
CALL PAINTCURSOR(curPos, COLORON%) 
 
REM Event loop 
 
DO 
  oldPos = curPos 
 
  CURKEY$ = INKEY$ 
 
  IF CURKEY$ = CHR$(32) THEN 
    changed = ADDDOT(curPos, curShape%, shapes(), dots()) 
  ELSE 
    changed = MOVECURSOR(CURKEY$, curPos) 
  END IF 
 
  IF changed = TRUE THEN 
    CALL PAINTCURSOR(oldPos, COLOROFF%) 
    REM Delete line to cursor 
    DIM cs AS Shape 
    cs = shapes(curShape%) 
    IF cs.isClosed = FALSE AND cs.dotCount > 0 THEN 
      LINE (dots(curShape%, cs.dotCount - 1).x, dots(curShape%, cs.dotCount - 1).y)-(oldPos.x, oldPos.y), 0 
    END IF 
    FOR i% = 0 TO curShape% 
      CALL DRAWSHAPE(shapes(), dots(), curPos, i%) 
    NEXT i% 
    CALL PAINTCURSOR(curPos, COLORON%) 
  END IF 
LOOP UNTIL CURKEY$ = CHR$(27) 
 
 
FUNCTION ADDDOT% (curPos AS Dot, curShape%, shapes() AS Shape, dots() AS Dot) 
 
REM If we are out of shapes, do nothing 
IF shapes(curShape%).isClosed = TRUE THEN 
  ADDDOT = FALSE 
  EXIT FUNCTION 
END IF 
 
needClose = FALSE 
ADDDOT = TRUE 
 
REM If this is first dot in shape, just add it 
IF shapes(curShape%).dotCount = 0 THEN 
  dots(curShape%, 0) = curPos 
  shapes(curShape%).dotCount = 1 
ELSE 
  REM Check if same position as first dot 
  IF curPos.x = dots(curShape%, 0).x AND curPos.y = dots(curShape%, 0).y THEN 
    needClose = TRUE 
  ELSE 
    dots(curShape%, shapes(curShape%).dotCount) = curPos 
    shapes(curShape%).dotCount = shapes(curShape%).dotCount + 1 
    IF shapes(curShape%).dotCount = DOTSINSHAPE THEN needClose = TRUE 
  END IF 
END IF 
 
IF needClose = TRUE THEN 
  shapes(curShape%).isClosed = TRUE 
  IF curShape% < MAXSHAPES - 1 THEN 
    curShape% = curShape% + 1 
  END IF 
END IF 
 
END FUNCTION 
 
SUB DRAWSHAPE (shapes() AS Shape, dots() AS Dot, curPos AS Dot, i%) 
DIM s AS Shape 
s = shapes(i%) 
 
REM Make sure we don't try to draw line to non-existant dot! 
IF s.dotCount > 1 THEN 
  FOR d% = 0 TO s.dotCount - 2 
    LINE (dots(i%, d%).x, dots(i%, d%).y)-(dots(i%, d% + 1).x, dots(i%, d% + 1).y) 
  NEXT d% 
END IF 
 
REM last line in shape, may go to cursor 
IF s.dotCount > 0 THEN 
  IF s.isClosed THEN 
    LINE (dots(i%, s.dotCount - 1).x, dots(i%, s.dotCount - 1).y)-(dots(i%, 0).x, dots(i%, 0).y) 
  ELSE 
    LINE (dots(i%, s.dotCount - 1).x, dots(i%, s.dotCount - 1).y)-(curPos.x, curPos.y) 
  END IF 
END IF 
 
END SUB 
 
FUNCTION MAX% (A%, B%) 
IF A% >= B% THEN MAX = A% ELSE MAX% = B 
END FUNCTION 
 
FUNCTION MIN% (A%, B%) 
IF A% <= B% THEN MIN = A% ELSE MIN = B% 
END FUNCTION 
 
FUNCTION MOVECURSOR% (k$, d AS Dot) 
IF RIGHT$(k$, 1) = "K" AND d.x > 0 THEN 
  d.x = d.x - 1 
  MOVECURSOR = TRUE 
ELSEIF RIGHT$(k$, 1) = "M" AND d.x < SCRWIDTH% THEN 
  d.x = d.x + 1 
  MOVECURSOR = TRUE 
ELSEIF RIGHT$(k$, 1) = "H" AND d.y > 0 THEN 
  d.y = d.y - 1 
  MOVECURSOR = TRUE 
ELSEIF RIGHT$(k$, 1) = "P" AND d.y < SCRHEIGHT% THEN 
  d.y = d.y + 1 
  MOVECURSOR = TRUE 
ELSE 
  MOVECURSOR = FALSE 
END IF 
END FUNCTION 
 
SUB PAINTCURSOR (d AS Dot, CURCOLOR%) 
IF d.y > 0 THEN LINE (d.x, MAX(d.y - 1, 0))-(d.x, MAX(d.y - (1 + CURLEN%), 0)), CURCOLOR% 
IF d.y < SCRHEIGHT% THEN LINE (d.x, MIN(d.y + 1, SCRHEIGHT%))-(d.x, MIN(d.y + 1 + CURLEN%, SCRHEIGHT%)), CURCOLOR% 
IF d.x > 0 THEN LINE (MAX(d.x - 1, 0), d.y)-(MAX(d.x - (1 + CURLEN%), 0), d.y), CURCOLOR% 
IF d.x < SCRWIDTH% THEN LINE (MIN(d.x + 1, SCRWIDTH%), d.y)-(MIN(d.x + 1 + CURLEN%, SCRWIDTH%), d.y), CURCOLOR% 
END SUB

שחק עם זה, אולי תלמד משהו...
 
את שיטת הסברוטינות לא הכרתי, אתה הכרת לי אותה כדי להקל במקום מספרי שורות. ניסיתי לכתוב את הסברוטינה עם שמה ולהפנות אליה כמו שהראית לי, לא עבד. ארצה לדעת איך מגדירים סברוטינות ומפנים אליהן. יש לי ידע מסוים ואני משתדל לנצל אותו בחוכמה. כל ידע מוסיף. ככל שאני זוכר כתבת לי שצריך לכתוב את המלה סברוטינה ואחריה את שם הסברוטינה ואז נפתח תת מסך וכותבים בו אותה ובסוף פקודה עם END, ואחר כך אפשר במקום מסוים בתוכנה לכתוב "GOTO" ואחריו להפנות לסברוטינה.
 
נערך לאחרונה ב:

BravoMan

Active member
לסברוטינה קוראים עם call.
מציע שתסתכל על הקוד שצירפתי, ותראה אפה השמות מופיעים.
יותר מזה - תעתיק את הקוד לקובץ טקסט פשוט, שנה את הסיומת ל-BAS, ותריץ ב-QBASIC.
תראה מה הקוד עושה.

GOTO יכול לקבל מספר שורה, אבל יכול לקבל גם "תווית" שזה שם שמורכב מאותיות אנגליות, עם נקודתיים בסוף, ומשמש כסימן בקוד.
בדיוק כמו מספר שורה, אבל יותר ידידותי לבני אדם.
בניגוד לסברוטינה, קפיצה של GOTO לא חוזרת למקום ממנו קפצה.

יש גם דרך ביניים להשתמש ב-GOSUB, אבל אלה שאריות פרימיטיביות מיומיו הראשונים של בייסיק ואין באמת סיבה להשתמש בהן.

אגב, מזכיר לך שיש את האתר הזה:

יש פה רשימה של כל הפקודות ואיך להשתמש בכל אחת.
 

BravoMan

Active member
תתחיל מזה שלא תעביר פרמטרים.
תיצור פרוצדורה עם סוגריים ריקים כדי להתנסות.

פרוצדורה יכולה לראות משתנים גלובליים, כאלה שהגדרת מחוץ לפרוצדורה, אז בתור התחלה לא צריכה להיות לך בעיה לעבוד בלי להבין מה הם "פרמטרים".

אחרי שתעבור את השלב הזה בהצלחה, אנסה להסביר לך מה זה "פרמטר".
 
כתוב לי בבקשה את הצורות המדויקות של פקודת יצירת פרוצדורה, ושל פקודת קריאה אליה. כשכתבתי עם GOSUB בלי להגדיר פרמטרים ובלי סוגריים אחרי השם, סרב המחשב לעבור לפרוצידורה וכתב שגיאה אף שיצר את הפרוצידורה. אולי בביסיק שאז היה לי, לא הכיר את הקריאה GOSUB לפרוצידורה אלא רק את CALL. עכשיו יש לי מחשב חדש ובקרוב יתקינו לי שוב ביסיק. בינתיים אני לא יכול להפעיל את התוכנות גם כי אין לי ביסיק וגם כי יש אזהרה שהן ממקור לא ידוע.
 
נערך לאחרונה ב:

BravoMan

Active member
אתה צריך לשים לב למה שכותבים לך!
אמרתי לך שלפרוצדורות קוראים עם CALL לא GOSUB!

הנה דוגמה מאוד פשוטה:
קוד:
DECLARE SUB HELLO () 
 
PRINT "Before sub" 
CALL HELLO 
PRINT "After sub" 
 
SUB HELLO 
    PRINT "Hellow world" 
END SUB

תשים לב לסדר הופעת הטקסט על המסך!

שים לב שאת ה-DECLARE אתה לא חייב לכתוב, QBASIC ייצר את השורה הזו עבורך אוטומטית.
שים לב גם, שבקריאה לא צריך סוגריים אם אין פרמטרים.

ואם תלחץ F2 ב-QBASIC תוכל לראות את כל הפרוצדורות ולעבור בניהן.
 
ככל שאני זוכר בהתחלה אמרת לי לכתוב פרוצידורות עם GOSUB. האם אפשר להגדיר פרוצידורה בלי סוגריים? ומה שאני כותב בוודאי לא שטויות, יש לי שכל. עוד משהו חשוב: בתוכנה המבוססת על המילון יש בעיה שצריך לקרוא מתוך פרוצידורה אחת לפרוצידורה אחרת, האם אפשרי?
 
נערך לאחרונה ב:

BravoMan

Active member
1. נתתי לך דוגמה לפרוצדורה בלי סוגריים (אתה עדיין חייב סוגריים בשורת DECLARE כי ככה השפה עובדת)

2. ניתן לקרוא לפרוצדורה מתוך פרוצדורה, מתוך פרוצדורה, מספר שכבות (אני לא בטוח כמה QB יחזיק, כנראה יותר מ-10 שכבות).
עושים את זה באותה צורה כמו שקוראים לפרוצדורה ישר.

3. ראיתי שבאחת ההודעות אכן עשיתי טעות - GOSUB עובד רק עם תוויות בקוד, לא עם פרוצדורות.

4. העובדה היא שהקוד שאתה כותב לא עובד.
שתי דוגמאות הקוד שצירפתי לך עד כה עובדות.
תריץ אותן, שחק איתן, נסה לשנות דברים ותראה איך זה משפיע.

זה יעזור לך ללמוד איך השפה עובדת.

נ.ב.
ניתן לקרוא לפרוצדורה מתוך עצמה.
זה נקרא רקורסיה, אבל זה רק למתכנתים מתקדמים.

כמובן, אם ה-AI שלך לא יכול ללמוד על רקורסיה, הוא לא יכול ללמוד על העולם האמתי, כי יש הרבה רקורסיה בטבע...
 
למעלה