Experto en enfermedades (versión en V)

Descripción del contenido de la página

Sistema experto sobre enfermedades, escrito en V.

Etiquetas:

Código fuente

// main.v
//
// This file is part of Experto en enfermedades (Expert on diseases)

// Last modified 20250812T1907+0200.

/*

Copyright (C) 1985, Chris Naylor: Sinclair BASIC code included in his book
"Build Your Own Expert System" (Sigma Press, 1985).

Copyright (C) 1988, 1989, Marcos Cruz (programandala.net): SuperBASIC version
(http:///programandala.net/es.programa.sistema_experto_sobre_enfermedades.html).

Copyright (C) 2023, 2024, Marcos Cruz (programandala.net): Odin version.

Copyright (C) 2024, 2025, Marcos Cruz (programandala.net): SBASIC version.

Copyright (C) 2025, Marcos Cruz (programandala.net): V version.

This program is licensed under a BSD 2-Clause License
(https://opensource.org/license/bsd-2-clause/). See the <LICENSE.txt> file.

*/

// ==========================================================================
import math
import strconv
import term

const title = 'Experto en enfermedades'

// XXX TMP
// debug level
// 0: do not include debug code (this is the default)
// 1: add the test options to the main menu
// 2: also print debugging messages during the main loop
const debug_level = $d('debug_level', 1)

const diseases = 91
const symptoms = 68

const max_answer = 5
const min_answer = -max_answer

enum Mode {
    normal_mode
    random_demo_mode
    value_demo_mode
}

__global mode = Mode.normal_mode
__global demo_value = 0

fn init() {
    // Anodino's type package is used by Anodino's par package. When type's
    // `max_lines_printed_before_a_pause` is set to zero, no pause is issued
    // during the printing of the paragrahps:
    // type.max_lines_printed_before_a_pause = 0 // XXX TODO
}

fn consult() {
    mut max_prob := [diseases]f64{}
    mut min_prob := [diseases]f64{}
    mut prob := [diseases]f64{}
    mut asked := [symptoms]bool{}
    mut symptoms_count := [diseases]int{}
    mut symptoms_left := [diseases]int{}
    mut value := [symptoms]f64{}

    mut answer_value := 0
    mut disease_name := ''
    mut disease_prob := 0.0
    mut hypothesis := 0
    mut symptom := 0

    mut current_prob := 0.0
    mut con_prob := 0.0
    mut pro_prob := 0.0

    // Find the a priori probability and the rule values
    if debug_level > 1 {
        println('Find the a priori probability and the rule values')
    }

    for disease in 0 .. diseases {
        disease_name, prob[disease] = disease_data(disease)
        current_prob = prob[disease]
        if debug_level > 1 {
            print("Disease #${disease}: \"${disease_name}\" (current prob: ${current_prob})\n")
        }
        for disease_symptom := 0; true; disease_symptom += 1 {
            symptom, pro_prob, con_prob = symptom_data(disease, disease_symptom) or { break }
            symptoms_left[disease] += 1
            value[symptom] += math.abs(current_prob * pro_prob / (current_prob * pro_prob +
                (1 - current_prob) * con_prob) - current_prob * (1 - pro_prob) / (
                current_prob * (1 - pro_prob) + (1 - current_prob) * (1 - con_prob)))
            if debug_level > 1 {
                print('Symptom #${symptom} (value: ${value[symptom]})\n')
            }
        }
        symptoms_count[disease] = symptoms_left[disease]
    }

    for {
        // Find the most important symptom and ask about it
        if debug_level > 1 {
            println('Find the most important symptom and ask about it')
        }

        mut min_value := 0.0
        no_symptom := -1
        mut symptom_to_ask_for := no_symptom
        for s in 0 .. symptoms {
            if value[s] > min_value {
                symptom_to_ask_for = s
                min_value = value[s]
                if debug_level > 1 {
                    print("Symptom to ask for: #${symptom_to_ask_for}, \"${question(symptom_to_ask_for)}\" (value: ${min_value})\n")
                }
            }
            value[s] = 0
        }
        if symptom_to_ask_for == no_symptom {
            println('No hay más preguntas.') // XXX TODO par.whole
            return
        }
        if debug_level == 0 {
            if mode == .normal_mode {
                term.clear()
            }
        }
        println(question(symptom_to_ask_for)) // XXX TODO par.whole
        match mode {
            .random_demo_mode {
                answer_value = random_answer()
                println(answer_value) // XXX TODO par.whole
            }
            .value_demo_mode {
                answer_value = demo_value
                println(answer_value) // XXX TODO par.whole
            }
            .normal_mode {
                answer_value = user_answer()
            }
        }
        asked[symptom_to_ask_for] = true

        // Update the a priori probabilities
        if debug_level > 1 {
            println('Update the a priori probabilities')
        }

        for disease in 0 .. diseases {
            disease_name, _ = disease_data(disease)
            if debug_level > 1 {
                print("Disease #${disease}: \"${disease_name}\"\n")
            }
            for s in 0 .. symptoms_count[disease] {
                symptom, pro_prob, con_prob = symptom_data(disease, s) or { 0, 0.0, 0.0 } // `or` should never happen
                if symptom == symptom_to_ask_for && symptoms_left[disease] > 0 {
                    symptoms_left[disease] = symptoms_left[disease] - 1
                    current_prob = prob[disease]
                    mut pe := current_prob * pro_prob + (1 - current_prob) * con_prob
                    if answer_value > 0 {
                        prob[disease] = current_prob * (1 +
                            (pro_prob / pe - 1) * f64(answer_value) / max_answer)
                    } else {
                        prob[disease] = current_prob * (1 +
                            (pro_prob - (1 - pro_prob) * pe / (1 - pe)) * f64(answer_value) / max_answer)
                    }
                    if prob[disease] == math.trunc(prob[disease]) {
                        symptoms_left[disease] = 0
                    }
                }
            }
        }

        // Find new min and max rule values

        mut current_min_prob := 0.0
        for disease in 0 .. diseases {
            current_prob = prob[disease]
            mut a1 := 1.0
            mut a2 := 1.0
            mut a3 := 1.0
            mut a4 := 1.0
            disease_name, disease_prob = disease_data(disease)
            for s in 0 .. symptoms_count[disease] {
                symptom, pro_prob, con_prob = symptom_data(disease, s) or { 0, 0.0, 0.0 } // `or` should never happen
                if !asked[symptom] && symptoms_left[disease] > 0 {
                    if con_prob > pro_prob {
                        pro_prob = 1 - pro_prob
                        con_prob = 1 - con_prob
                    }
                    value[symptom] = value[symptom] +
                        current_prob * pro_prob / (current_prob * pro_prob +
                        (1 - current_prob) * con_prob) - current_prob * (1 - pro_prob) / (
                        current_prob * (1 - pro_prob) + (1 - current_prob) * (1 - con_prob))
                    a1 = a1 * pro_prob
                    a2 = a2 * con_prob
                    a3 = a3 * (1 - pro_prob)
                    a4 = a4 * (1 - con_prob)
                }
            }
            max_prob[disease] = current_prob * a1 / (current_prob * a1 + (1 - current_prob) * a2)
            min_prob[disease] = current_prob * a3 / (current_prob * a3 + (1 - current_prob) * a4)
            if max_prob[disease] < disease_prob {
                symptoms_left[disease] = 0
            }
            if min_prob[disease] > current_min_prob {
                hypothesis = disease
                current_min_prob = min_prob[disease]
                if debug_level > 1 {
                    disease_name_, _ := disease_data(hypothesis)
                    print('Hipótesis: ${disease_name_} (#${hypothesis}), probabilidad mínima: ${current_min_prob}\n')
                }
            }
        }

        // Search for a clearly possible hypothesis

        for disease in 0 .. diseases {
            if min_prob[hypothesis] <= max_prob[disease] && disease != hypothesis {
                current_min_prob = 0
            }
        }
        if current_min_prob != 0 {
            break
        }
    }

    disease_name, _ = disease_data(hypothesis)
    unsafe {
        println(strconv.v_sprintf('El resultado más probable es ${disease_name} con probabilidad ${prob[hypothesis]}.')) // XXX TODO par.whole
    }
}

fn print_credits() {
    println(title) // XXX TODO par.whole
    unsafe {
        println(strconv.v_sprintf('Versión ${version}')) // XXX TODO par.whole
    }
    println('')
    println('(C) 1985, Chris Naylor: en Sinclair BASIC.') // XXX TODO par.whole
    println('(C) 1988, 1989, Marcos Cruz (programandala.net): en SuperBASIC.') // XXX TODO par.whole
    println('(C) 2023, 2024, Marcos Cruz (programandala.net): en Odin.') // XXX TODO par.whole
    println('(C) 2025, Marcos Cruz (programandala.net): en V.') // XXX TODO par.whole
    println('')
}

fn main() {
    init()
    for {
        term.clear()
        print_credits()
        if ready() {
            consult()
            press_enter()
        } else {
            break
        }
    }
}

// data.v
//
// This file is part of Experto en enfermedades (Expert on diseases)

// Last modified 20250812T1907+0200.

/*

Copyright (C) 1985, Chris Naylor: Sinclair BASIC code included in his book
"Build Your Own Expert System" (Sigma Press, 1985).

Copyright (C) 1988, 1989, Marcos Cruz (programandala.net): SuperBASIC version
(http:///programandala.net/es.programa.sistema_experto_sobre_enfermedades.html).

Copyright (C) 2023, 2024, Marcos Cruz (programandala.net): Odin version.

Copyright (C) 2024, 2025, Marcos Cruz (programandala.net): SBASIC version.

Copyright (C) 2025, Marcos Cruz (programandala.net): V version.

This program is licensed under a BSD 2-Clause License
(https://opensource.org/license/bsd-2-clause/). See the <LICENSE.txt> file.

*/

// ==========================================================================

// Return name and probability of the given disease.
fn disease_data(disease int) (string, f64) {
    match disease {
        0 { return 'resfriado común', 0.02 }
        1 { return 'rinitis alérgica', 0.01 }
        2 { return 'sinusitis', 0.01 }
        3 { return 'faringitis', 0.02 }
        4 { return 'amigdalitis', 0.001 }
        5 { return 'gripe', 0.01 }
        6 { return 'laringitis', 0.01 }
        7 { return 'tumor de laringe', 0.00004 }
        8 { return 'bronquitis aguda', 0.005 }
        9 { return 'bronquitis crónica', 0.005 }
        10 { return 'asma', 0.02 }
        11 { return 'enfisema pulmonar', 0.01 }
        12 { return 'neumonía', 0.003 }
        13 { return 'pleuresia', 0.001 }
        14 { return 'neumotórax', 0.0002 }
        15 { return 'bronquiectasia', 0.00001 }
        16 { return 'abceso pulmonar', 0.00001 }
        17 { return 'neumoconiosis', 0.001 }
        18 { return 'cáncer de pulmón', 0.001 }
        19 { return 'fibrosis intersticial', 0.00001 }
        20 { return 'edema pulmonar', 0.001 }
        21 { return 'gastritis', 0.01 }
        22 { return 'hernia de hiato', 0.001 }
        23 { return 'úlcera duodenal', 0.01 }
        24 { return 'úlcera gástrica', 0.01 }
        25 { return 'diverticulitis intestinal', 0.001 }
        26 { return 'enterocolitis', 0.0001 }
        27 { return 'enfermedad de Crohn', 0.0001 }
        28 { return 'oclusión intestinal', 0.00001 }
        29 { return 'apendicitis', 0.001 }
        30 { return 'intoxicación alimentaria', 0.001 }
        31 { return 'gastroenteritis', 0.01 }
        32 { return 'litiasis renal', 0.001 }
        33 { return 'pielonefritis aguda', 0.001 }
        34 { return 'litiasis biliar', 0.01 }
        35 { return 'colecistitis', 0.001 }
        36 { return 'herpes', 0.001 }
        37 { return 'trombloflebitis', 0.0005 }
        38 { return 'artritis reumatoide', 0.001 }
        39 { return 'insuficiencia cardiaca', 0.001 }
        40 { return 'ansiedad', 0.01 }
        41 { return 'depresión', 0.01 }
        42 { return 'trombosis coronaria', 0.01 }
        43 { return 'angina de pecho', 0.01 }
        44 { return 'embolia pulmonar', 0.0001 }
        45 { return 'apoplegía', 0.001 }
        46 { return 'ataque isquémico transitorio', 0.001 }
        47 { return 'tuberculosis', 0.0001 }
        48 { return 'hemorroides', 0.01 }
        49 { return 'hipotiroidismo', 0.001 }
        50 { return 'colon irritable', 0.0007 }
        51 { return 'cáncer intestinal', 0.001 }
        52 { return 'colitis ulcerosa', 0.0004 }
        53 { return 'enfermedad de Meniere', 0.0005 }
        54 { return 'espondilosis cervical', 0.006 }
        55 { return 'hemorragia subdural', 0.000001 }
        56 { return 'tumor cerebral', 0.000001 }
        57 { return 'meningitis', 0.000001 }
        58 { return 'hemorragia subaracnoidea', 0.00001 }
        59 { return 'glaucoma agudo', 0.01 }
        60 { return 'arteritis de la temporal', 0.001 }
        61 { return 'dispepsia', .1 }
        62 { return 'bloqueo cardiaco', 0.0003 }
        63 { return 'anemia perniciosa', 0.0004 }
        64 { return 'jaqueca', .1 }
        65 { return 'hipertensión esencial', .15 }
        66 { return 'eccema', 0.03 }
        67 { return 'urticaria', 0.03 }
        68 { return 'sarna', 0.001 }
        69 { return 'sarampión', 0.02 }
        70 { return 'rubeola', 0.01 }
        71 { return 'varicela', 0.001 }
        72 { return 'psoriasis', 0.02 }
        73 { return 'pitiriasis rubra', 0.01 }
        74 { return 'acné rosáceo', 0.01 }
        75 { return 'tirotoxicosis', 0.001 }
        76 { return 'diabetes mellitus', 0.01 }
        77 { return 'cáncer de estómago', 0.0003 }
        78 { return 'fibrilación auricular', 0.001 }
        79 { return 'enfermedad de Hodgkin', 0.0001 }
        80 { return 'fiebre glandular', 0.001 }
        81 { return 'linfoma', 0.0001 }
        82 { return 'paperas', 0.01 }
        83 { return 'parálisis facial', 0.0003 }
        84 { return 'enfermedad de Parkinson', 0.001 }
        85 { return 'artritis reumatoide', 0.01 }
        86 { return 'cistitis', 0.01 }
        87 { return 'tumor renal', 0.001 }
        88 { return 'tumor en la vejiga', 0.0004 }
        89 { return 'iritis', 0.0005 }
        90 { return 'hepatitis aguda', 0.001 }
        else { return '', 0.0 }
    }
    return '', 0.0
}

// XXX TODO include details of the return values in the documentation:

// Given a disease and an ordinal symptom associated to it, return the global
// identifier of the symptom, and the pro and con probabilities of the given
// disease and symptom; if the list of symptoms of the given disease is
// exhausted, return `none` instead.
//
fn symptom_data(disease int, disease_symptom int) ?(int, f64, f64) {
    match disease {
        0 {
            match disease_symptom {
                0 { return 0, 0.9, 0.05 }
                1 { return 1, 0.8, 0.02 }
                2 { return 2, 0.8, 0.02 }
                3 { return 4, 0.6, 0.01 }
                4 { return 5, 1.0, 0.01 }
                5 { return 6, 0.2, 0.01 }
                6 { return 7, 0.5, 0.01 }
                7 { return 14, 0.8, 0.01 }
                8 { return 33, 0.0, 0.01 }
                else {}
            }
        }
        1 {
            match disease_symptom {
                0 { return 0, 1.0, 0.01 }
                1 { return 1, 1.0, 0.01 }
                2 { return 5, 0.9, 0.01 }
                3 { return 9, 0.7, 0.01 }
                4 { return 10, 0.7, 0.01 }
                5 { return 11, 0.6, 0.01 }
                6 { return 19, 0.9, 0.01 }
                else {}
            }
        }
        2 {
            match disease_symptom {
                0 { return 1, 0.5, 0.01 }
                1 { return 5, 0.5, 0.01 }
                2 { return 6, 0.8, 0.01 }
                3 { return 12, 0.9, 0.01 }
                4 { return 13, 0.8, 0.01 }
                5 { return 14, 0.8, 0.01 }
                6 { return 21, 0.5, 0.01 }
                7 { return 62, 0.9, 0.01 }
                else {}
            }
        }
        3 {
            match disease_symptom {
                0 { return 2, 1.0, 0.01 }
                1 { return 7, 0.5, 0.01 }
                2 { return 10, 0.9, 0.01 }
                3 { return 15, 0.9, 0.01 }
                4 { return 36, 0.8, 0.3 }
                5 { return 63, 0.4, 0.01 }
                else {}
            }
        }
        4 {
            match disease_symptom {
                0 { return 2, 1.0, 0.01 }
                1 { return 6, 0.9, 0.01 }
                2 { return 7, 0.9, 0.01 }
                3 { return 14, 1.0, 0.01 }
                4 { return 15, 0.7, 0.01 }
                5 { return 18, 0.0, 0.5 }
                6 { return 33, 0.0, 0.01 }
                7 { return 63, 0.8, 0.01 }
                else {}
            }
        }
        5 {
            match disease_symptom {
                0 { return 0, 0.9, 0.01 }
                1 { return 2, 0.9, 0.01 }
                2 { return 5, 0.5, 0.01 }
                3 { return 6, 0.7, 0.01 }
                4 { return 7, 1.0, 0.01 }
                5 { return 14, 1.0, 0.01 }
                6 { return 16, 0.8, 0.01 }
                7 { return 17, 0.6, 0.01 }
                8 { return 33, 0.0, 0.01 }
                else {}
            }
        }
        6 {
            match disease_symptom {
                0 { return 3, 1.0, 0.01 }
                1 { return 4, 0.9, 0.01 }
                2 { return 7, 0.6, 0.01 }
                3 { return 14, 0.05, 0.01 }
                4 { return 15, 0.7, 0.01 }
                5 { return 36, 0.8, 0.3 }
                6 { return 20, 0.1, 0.01 }
                else {}
            }
        }
        7 {
            match disease_symptom {
                0 { return 3, 1.0, 0.01 }
                1 { return 33, 0.99, 0.01 }
                2 { return 36, 0.8, 0.3 }
                else {}
            }
        }
        8 {
            match disease_symptom {
                0 { return 4, 1.0, 0.01 }
                1 { return 7, 1.0, 0.01 }
                2 { return 11, 1.0, 0.01 }
                3 { return 14, 1.0, 0.01 }
                4 { return 17, 0.5, 0.01 }
                5 { return 20, 1.0, 0.01 }
                6 { return 21, 0.9, 0.01 }
                7 { return 30, 0.9, 0.01 }
                8 { return 33, 0.0, 0.01 }
                else {}
            }
        }
        9 {
            match disease_symptom {
                0 { return 4, 1.0, 0.01 }
                1 { return 11, 0.9, 0.01 }
                2 { return 13, 0.5, 0.01 }
                3 { return 20, 1.0, 0.01 }
                4 { return 21, 0.8, 0.01 }
                5 { return 33, 1.0, 0.01 }
                6 { return 35, 0.9, 0.01 }
                7 { return 36, 0.8, 0.3 }
                else {}
            }
        }
        10 {
            match disease_symptom {
                0 { return 11, 0.8, 0.01 }
                1 { return 21, 1.0, 0.01 }
                2 { return 22, 0.5, 0.01 }
                3 { return 23, 0.5, 0.01 }
                4 { return 24, 0.5, 0.01 }
                5 { return 25, 0.5, 0.01 }
                6 { return 30, 0.8, 0.01 }
                else {}
            }
        }
        11 {
            match disease_symptom {
                0 { return 4, 0.6, 0.01 }
                1 { return 11, 0.6, 0.01 }
                2 { return 20, 0.6, 0.01 }
                3 { return 21, 1.0, 0.01 }
                4 { return 25, 0.8, 0.01 }
                5 { return 36, 0.8, 0.3 }
                else {}
            }
        }
        12 {
            match disease_symptom {
                0 { return 7, 1.0, 0.01 }
                1 { return 14, 1.0, 0.01 }
                2 { return 16, 0.9, 0.01 }
                3 { return 17, 0.8, 0.01 }
                4 { return 21, 1.0, 0.01 }
                5 { return 22, 0.5, 0.01 }
                6 { return 25, 0.5, 0.01 }
                7 { return 26, 0.2, 0.01 }
                8 { return 27, 0.1, 0.01 }
                9 { return 28, 0.02, 0.01 }
                10 { return 30, 0.9, 0.01 }
                11 { return 31, 0.5, 0.005 }
                12 { return 35, 0.1, 0.9 }
                else {}
            }
        }
        13 {
            match disease_symptom {
                0 { return 4, 0.8, 0.01 }
                1 { return 7, 0.9, 0.01 }
                2 { return 14, 1.0, 0.01 }
                3 { return 21, 0.5, 0.01 }
                4 { return 30, 0.8, 0.01 }
                5 { return 31, 0.8, 0.01 }
                6 { return 33, 0.0, 0.01 }
                else {}
            }
        }
        14 {
            match disease_symptom {
                0 { return 17, 0.8, 0.01 }
                1 { return 21, 0.8, 0.01 }
                2 { return 31, 0.8, 0.005 }
                else {}
            }
        }
        15 {
            match disease_symptom {
                0 { return 4, 1.0, 0.01 }
                1 { return 13, 0.5, 0.01 }
                2 { return 20, 1.0, 0.01 }
                3 { return 26, 0.5, 0.01 }
                else {}
            }
        }
        16 {
            match disease_symptom {
                0 { return 17, 0.5, 0.01 }
                1 { return 20, 0.5, 0.01 }
                2 { return 26, 0.5, 0.01 }
                3 { return 32, 0.9, 0.01 }
                else {}
            }
        }
        17 {
            match disease_symptom {
                0 { return 8, 1.0, 0.01 }
                1 { return 20, 0.8, 0.01 }
                2 { return 21, 1.0, 0.01 }
                3 { return 35, 1.0, 0.01 }
                else {}
            }
        }
        18 {
            match disease_symptom {
                0 { return 4, 1.0, 0.01 }
                1 { return 11, 0.5, 0.01 }
                2 { return 17, 0.8, 0.01 }
                3 { return 20, 0.8, 0.01 }
                4 { return 21, 0.5, 0.01 }
                5 { return 26, 0.5, 0.01 }
                6 { return 36, 0.99, 0.3 }
                else {}
            }
        }
        19 {
            match disease_symptom {
                0 { return 20, 0.6, 0.01 }
                1 { return 21, 0.8, 0.01 }
                2 { return 34, 0.8, 0.01 }
                else {}
            }
        }
        20 {
            match disease_symptom {
                0 { return 11, 0.8, 0.01 }
                1 { return 21, 0.9, 0.01 }
                2 { return 24, 0.9, 0.01 }
                3 { return 25, 0.5, 0.01 }
                4 { return 26, 0.5, 0.01 }
                5 { return 29, 0.5, 0.01 }
                else {}
            }
        }
        21 {
            match disease_symptom {
                0 { return 7, 0.4, 0.01 }
                1 { return 36, 0.9, 0.5 }
                2 { return 40, 0.01, 0.8 }
                3 { return 42, 0.8, 0.01 }
                4 { return 41, 0.5, 0.01 }
                else {}
            }
        }
        22 {
            match disease_symptom {
                0 { return 15, 0.9, 0.01 }
                1 { return 17, 0.9, 0.01 }
                2 { return 31, 0.5, 0.005 }
                3 { return 40, 0.8, 0.01 }
                4 { return 41, 0.8, 0.005 }
                5 { return 56, 0.9, 0.01 }
                else {}
            }
        }
        23 {
            match disease_symptom {
                0 { return 36, 0.8, 0.2 }
                1 { return 40, 0.8, 0.01 }
                2 { return 41, 0.99, 0.005 }
                3 { return 56, 0.7, 0.01 }
                else {}
            }
        }
        24 {
            match disease_symptom {
                0 { return 19, 0.8, 0.01 }
                1 { return 40, 0.7, 0.01 }
                2 { return 41, 0.9, 0.005 }
                3 { return 45, 0.5, 0.01 }
                4 { return 55, 0.9, 0.01 }
                5 { return 61, 0.0001, 0.01 }
                else {}
            }
        }
        25 {
            match disease_symptom {
                0 { return 7, 0.5, 0.01 }
                1 { return 40, 0.5, 0.01 }
                2 { return 41, 0.6, 0.005 }
                3 { return 42, 0.5, 0.01 }
                4 { return 55, 0.8, 0.01 }
                else {}
            }
        }
        26 {
            match disease_symptom {
                0 { return 7, 0.3, 0.01 }
                1 { return 22, 0.3, 0.01 }
                2 { return 40, 0.3, 0.01 }
                3 { return 41, 0.9, 0.005 }
                4 { return 42, 0.7, 0.01 }
                else {}
            }
        }
        27 {
            match disease_symptom {
                0 { return 7, 0.7, 0.01 }
                1 { return 14, 0.9, 0.01 }
                2 { return 41, 0.9, 0.005 }
                3 { return 42, 0.9, 0.01 }
                4 { return 61, 0.00001, 0.01 }
                else {}
            }
        }
        28 {
            match disease_symptom {
                0 { return 40, 0.5, 0.01 }
                1 { return 41, 0.9, 0.005 }
                2 { return 42, 0.8, 0.01 }
                else {}
            }
        }
        29 {
            match disease_symptom {
                0 { return 7, 0.8, 0.01 }
                1 { return 33, 0.1, 0.9 }
                2 { return 40, 0.8, 0.01 }
                3 { return 41, 0.9, 0.005 }
                4 { return 43, 0.0, 0.5 }
                else {}
            }
        }
        30 {
            match disease_symptom {
                0 { return 6, 0.8, 0.01 }
                1 { return 40, 0.9, 0.01 }
                2 { return 41, 0.5, 0.005 }
                3 { return 42, 0.9, 0.01 }
                else {}
            }
        }
        31 {
            match disease_symptom {
                0 { return 7, 0.5, 0.01 }
                1 { return 40, 0.8, 0.01 }
                2 { return 41, 0.7, 0.005 }
                3 { return 42, 0.9, 0.01 }
                else {}
            }
        }
        32 {
            match disease_symptom {
                0 { return 41, 0.7, 0.005 }
                else {}
            }
        }
        33 {
            match disease_symptom {
                0 { return 7, 0.8, 0.01 }
                1 { return 40, 0.7, 0.01 }
                2 { return 41, 0.9, 0.005 }
                3 { return 66, 0.9, 0.01 }
                else {}
            }
        }
        34 {
            match disease_symptom {
                0 { return 40, 0.5, 0.01 }
                1 { return 41, 0.5, 0.005 }
                2 { return 56, 0.9, 0.01 }
                else {}
            }
        }
        35 {
            match disease_symptom {
                0 { return 7, 0.9, 0.01 }
                1 { return 40, 0.8, 0.01 }
                2 { return 41, 0.8, 0.005 }
                3 { return 44, 0.8, 0.001 }
                else {}
            }
        }
        36 {
            match disease_symptom {
                0 { return 1, 0.6, 0.01 }
                1 { return 7, 0.5, 0.01 }
                2 { return 13, 0.8, 0.01 }
                3 { return 17, 0.5, 0.01 }
                4 { return 58, 0.9, 0.01 }
                5 { return 59, 0.9, 0.01 }
                else {}
            }
        }
        37 {
            match disease_symptom {
                0 { return 39, 0.8, 0.01 }
                else {}
            }
        }
        38 {
            match disease_symptom {
                0 { return 14, 0.8, 0.01 }
                1 { return 16, 0.8, 0.01 }
                2 { return 39, 0.5, 0.001 }
                else {}
            }
        }
        39 {
            match disease_symptom {
                0 { return 11, 0.6, 0.01 }
                1 { return 17, 0.5, 0.01 }
                2 { return 21, 0.9, 0.01 }
                3 { return 24, 0.5, 0.001 }
                4 { return 25, 0.3, 0.001 }
                5 { return 31, 0.3, 0.001 }
                6 { return 35, 0.5, 0.01 }
                7 { return 38, 0.5, 0.01 }
                8 { return 41, 0.5, 0.01 }
                9 { return 46, 0.9, 0.01 }
                else {}
            }
        }
        40 {
            match disease_symptom {
                0 { return 6, 0.5, 0.01 }
                1 { return 14, 0.5, 0.01 }
                2 { return 15, 0.3, 0.01 }
                3 { return 21, 0.5, 0.01 }
                4 { return 22, 0.6, 0.01 }
                5 { return 27, 0.3, 0.01 }
                6 { return 37, 0.5, 0.01 }
                7 { return 38, 0.8, 0.01 }
                8 { return 42, 0.2, 0.01 }
                9 { return 45, 0.9, 0.01 }
                10 { return 46, 0.6, 0.01 }
                11 { return 47, 0.6, 0.01 }
                12 { return 49, 0.5, 0.01 }
                13 { return 56, 0.5, 0.01 }
                14 { return 57, 0.5, 0.01 }
                else {}
            }
        }
        41 {
            match disease_symptom {
                0 { return 6, 0.5, 0.01 }
                1 { return 14, 0.5, 0.01 }
                2 { return 46, 0.5, 0.01 }
                3 { return 48, 0.5, 0.01 }
                4 { return 49, 0.5, 0.01 }
                5 { return 61, 0.8, 0.01 }
                else {}
            }
        }
        42 {
            match disease_symptom {
                0 { return 14, 0.9, 0.01 }
                1 { return 17, 0.5, 0.01 }
                2 { return 19, 0.5, 0.01 }
                3 { return 21, 0.5, 0.01 }
                4 { return 22, 0.5, 0.01 }
                5 { return 31, 0.9, 0.001 }
                6 { return 35, 0.0, 0.2 }
                7 { return 37, 0.5, 0.01 }
                8 { return 40, 0.5, 0.01 }
                else {}
            }
        }
        43 {
            match disease_symptom {
                0 { return 17, 0.9, 0.01 }
                1 { return 19, 0.9, 0.01 }
                2 { return 21, 0.5, 0.01 }
                3 { return 22, 0.5, 0.01 }
                4 { return 31, 1.0, 0.001 }
                5 { return 35, 0.9, 0.01 }
                6 { return 36, 0.8, 0.3 }
                7 { return 37, 0.5, 0.01 }
                else {}
            }
        }
        44 {
            match disease_symptom {
                0 { return 17, 0.7, 0.01 }
                1 { return 20, 0.6, 0.01 }
                2 { return 21, 1.0, 0.01 }
                3 { return 24, 0.5, 0.001 }
                4 { return 25, 0.4, 0.001 }
                5 { return 26, 0.5, 0.001 }
                else {}
            }
        }
        45 {
            match disease_symptom {
                0 { return 27, 0.8, 0.01 }
                1 { return 37, 0.7, 0.01 }
                2 { return 50, 0.8, 0.001 }
                3 { return 57, 0.9, 0.01 }
                4 { return 60, 0.9, 0.01 }
                else {}
            }
        }
        46 {
            match disease_symptom {
                0 { return 19, 0.5, 0.01 }
                1 { return 27, 0.8, 0.01 }
                2 { return 33, 0.0, 0.01 }
                3 { return 37, 0.7, 0.01 }
                4 { return 50, 0.8, 0.001 }
                5 { return 57, 0.9, 0.01 }
                6 { return 60, 0.9, 0.01 }
                else {}
            }
        }
        47 {
            match disease_symptom {
                0 { return 4, 0.5, 0.01 }
                1 { return 6, 0.5, 0.01 }
                2 { return 7, 0.5, 0.01 }
                3 { return 11, 0.5, 0.01 }
                4 { return 14, 0.5, 0.01 }
                5 { return 17, 0.5, 0.01 }
                6 { return 21, 0.5, 0.01 }
                7 { return 22, 0.5, 0.01 }
                8 { return 26, 0.5, 0.001 }
                9 { return 29, 0.5, 0.01 }
                10 { return 61, 0.0001, 0.01 }
                else {}
            }
        }
        48 {
            match disease_symptom {
                0 { return 48, 0.8, 0.01 }
                1 { return 51, 0.9, 0.001 }
                2 { return 55, 0.9, 0.01 }
                3 { return 58, 0.5, 0.01 }
                else {}
            }
        }
        49 {
            match disease_symptom {
                0 { return 3, 0.5, 0.01 }
                1 { return 16, 0.5, 0.01 }
                2 { return 22, 0.001, 0.01 }
                3 { return 23, 0.0, 0.01 }
                4 { return 38, 0.001, 0.01 }
                5 { return 42, 0.0, 0.01 }
                6 { return 45, 0.001, 0.01 }
                7 { return 47, 0.001, 0.01 }
                8 { return 48, 0.8, 0.01 }
                9 { return 61, 0.9, 0.05 }
                else {}
            }
        }
        50 {
            match disease_symptom {
                0 { return 40, 0.3, 0.01 }
                1 { return 41, 0.8, 0.001 }
                2 { return 42, 0.5, 0.01 }
                3 { return 48, 0.5, 0.01 }
                4 { return 55, 0.5, 0.01 }
                5 { return 56, 0.9, 0.01 }
                else {}
            }
        }
        51 {
            match disease_symptom {
                0 { return 41, 0.5, 0.005 }
                1 { return 42, 0.9, 0.01 }
                2 { return 48, 0.9, 0.01 }
                3 { return 51, 0.5, 0.001 }
                4 { return 55, 0.9, 0.01 }
                5 { return 61, 0.0001, 0.01 }
                else {}
            }
        }
        52 {
            match disease_symptom {
                0 { return 7, 0.5, 0.01 }
                1 { return 22, 0.5, 0.01 }
                2 { return 33, 0.4, 0.01 }
                3 { return 40, 0.5, 0.01 }
                4 { return 41, 0.8, 0.005 }
                5 { return 42, 0.8, 0.01 }
                6 { return 51, 0.6, 0.001 }
                7 { return 55, 0.9, 0.01 }
                else {}
            }
        }
        53 {
            match disease_symptom {
                0 { return 19, 0.9, 0.01 }
                1 { return 33, 0.5, 0.01 }
                2 { return 37, 0.9, 0.001 }
                3 { return 40, 0.8, 0.01 }
                else {}
            }
        }
        54 {
            match disease_symptom {
                0 { return 6, 0.5, 0.01 }
                1 { return 37, 0.5, 0.01 }
                2 { return 53, 0.9, 0.01 }
                3 { return 57, 0.9, 0.01 }
                4 { return 60, 0.5, 0.01 }
                else {}
            }
        }
        55 {
            match disease_symptom {
                0 { return 6, 0.9, 0.01 }
                1 { return 19, 0.5, 0.01 }
                2 { return 27, 0.9, 0.001 }
                3 { return 33, 0.5, 0.01 }
                4 { return 37, 0.9, 0.01 }
                5 { return 40, 0.9, 0.01 }
                6 { return 54, 0.99, 0.001 }
                else {}
            }
        }
        56 {
            match disease_symptom {
                0 { return 6, 0.9, 0.01 }
                1 { return 33, 0.5, 0.01 }
                2 { return 37, 0.8, 0.01 }
                3 { return 40, 0.9, 0.01 }
                4 { return 49, 0.8, 0.01 }
                else {}
            }
        }
        57 {
            match disease_symptom {
                0 { return 1, 0.9, 0.01 }
                1 { return 6, 0.9, 0.01 }
                2 { return 7, 0.9, 0.01 }
                3 { return 27, 0.7, 0.01 }
                4 { return 40, 0.9, 0.01 }
                5 { return 53, 0.9, 0.01 }
                6 { return 59, 0.5, 0.01 }
                else {}
            }
        }
        58 {
            match disease_symptom {
                0 { return 1, 0.8, 0.01 }
                1 { return 6, 0.99, 0.01 }
                2 { return 27, 0.7, 0.01 }
                3 { return 37, 0.7, 0.01 }
                4 { return 40, 0.8, 0.01 }
                5 { return 53, 0.9, 0.01 }
                else {}
            }
        }
        59 {
            match disease_symptom {
                0 { return 1, 0.9, 0.01 }
                1 { return 6, 0.9, 0.01 }
                2 { return 19, 0.8, 0.01 }
                3 { return 33, 0.8, 0.01 }
                4 { return 40, 0.7, 0.01 }
                5 { return 62, 0.9, 0.01 }
                6 { return 67, 0.9, 0.01 }
                else {}
            }
        }
        60 {
            match disease_symptom {
                0 { return 6, 0.9, 0.01 }
                1 { return 7, 0.7, 0.01 }
                2 { return 16, 0.7, 0.01 }
                3 { return 22, 0.8, 0.01 }
                4 { return 62, 0.99, 0.01 }
                else {}
            }
        }
        61 {
            match disease_symptom {
                0 { return 6, 0.7, 0.01 }
                1 { return 19, 0.9, 0.01 }
                2 { return 40, 0.7, 0.01 }
                3 { return 41, 0.7, 0.01 }
                4 { return 56, 0.7, 0.01 }
                5 { return 61, 0.001, 0.01 }
                else {}
            }
        }
        62 {
            match disease_symptom {
                0 { return 17, 0.6, 0.01 }
                1 { return 21, 0.5, 0.01 }
                2 { return 38, 0.6, 0.01 }
                3 { return 57, 0.8, 0.01 }
                else {}
            }
        }
        63 {
            match disease_symptom {
                0 { return 21, 0.9, 0.01 }
                1 { return 27, 0.4, 0.01 }
                2 { return 35, 0.9, 0.01 }
                3 { return 38, 0.9, 0.01 }
                4 { return 41, 0.5, 0.01 }
                5 { return 44, 0.5, 0.01 }
                6 { return 49, 0.5, 0.01 }
                7 { return 57, 0.9, 0.01 }
                else {}
            }
        }
        64 {
            match disease_symptom {
                0 { return 1, 0.9, 0.01 }
                1 { return 6, 1.0, 0.01 }
                2 { return 14, 0.9, 0.01 }
                3 { return 19, 0.9, 0.01 }
                4 { return 33, 0.9, 0.01 }
                5 { return 40, 0.9, 0.01 }
                6 { return 42, 0.5, 0.01 }
                7 { return 62, 0.99, 0.01 }
                else {}
            }
        }
        65 {
            match disease_symptom {
                0 { return 6, 0.5, 0.01 }
                1 { return 14, 0.9, 0.01 }
                2 { return 33, 0.9, 0.01 }
                3 { return 38, 0.5, 0.01 }
                else {}
            }
        }
        66 {
            match disease_symptom {
                0 { return 58, 0.9, 0.01 }
                1 { return 59, 0.1, 0.01 }
                else {}
            }
        }
        67 {
            match disease_symptom {
                0 { return 45, 0.5, 0.01 }
                1 { return 58, 0.9, 0.01 }
                2 { return 59, 1.0, 0.01 }
                else {}
            }
        }
        68 {
            match disease_symptom {
                0 { return 58, 1.0, 0.01 }
                1 { return 59, 1.0, 0.01 }
                else {}
            }
        }
        69 {
            match disease_symptom {
                0 { return 1, 0.9, 0.01 }
                1 { return 4, 0.9, 0.01 }
                2 { return 5, 0.9, 0.01 }
                3 { return 6, 0.5, 0.01 }
                4 { return 7, 1.0, 0.01 }
                5 { return 10, 0.9, 0.01 }
                6 { return 14, 1.0, 0.01 }
                7 { return 33, 0.0, 0.01 }
                8 { return 42, 0.5, 0.01 }
                9 { return 59, 1.0, 0.01 }
                else {}
            }
        }
        70 {
            match disease_symptom {
                0 { return 7, 0.5, 0.01 }
                1 { return 33, 0.0, 0.01 }
                2 { return 53, 0.2, 0.01 }
                3 { return 59, 0.9, 0.01 }
                4 { return 63, 0.5, 0.01 }
                else {}
            }
        }
        71 {
            match disease_symptom {
                0 { return 6, 0.5, 0.01 }
                1 { return 7, 0.8, 0.01 }
                2 { return 14, 0.5, 0.01 }
                3 { return 33, 0.0, 0.01 }
                4 { return 58, 1.0, 0.01 }
                5 { return 59, 1.0, 0.01 }
                else {}
            }
        }
        72 {
            match disease_symptom {
                0 { return 2, 0.5, 0.01 }
                1 { return 45, 0.6, 0.01 }
                2 { return 58, 0.5, 0.01 }
                3 { return 59, 0.99, 0.01 }
                else {}
            }
        }
        73 {
            match disease_symptom {
                0 { return 33, 0.5, 0.01 }
                1 { return 58, 0.9, 0.01 }
                2 { return 59, 1.0, 0.01 }
                else {}
            }
        }
        74 {
            match disease_symptom {
                0 { return 1, 0.5, 0.01 }
                1 { return 33, 0.8, 0.01 }
                2 { return 59, 0.9, 0.01 }
                else {}
            }
        }
        75 {
            match disease_symptom {
                0 { return 1, 0.5, 0.01 }
                1 { return 21, 0.8, 0.01 }
                2 { return 22, 0.9, 0.01 }
                3 { return 23, 0.9, 0.01 }
                4 { return 38, 0.9, 0.01 }
                5 { return 42, 0.8, 0.01 }
                6 { return 45, 0.9, 0.01 }
                7 { return 46, 0.8, 0.01 }
                8 { return 47, 0.9, 0.01 }
                9 { return 61, 0.00001, 0.01 }
                10 { return 63, 0.3, 0.01 }
                11 { return 67, 0.3, 0.01 }
                else {}
            }
        }
        76 {
            match disease_symptom {
                0 { return 1, 0.5, 0.01 }
                1 { return 60, 0.5, 0.01 }
                2 { return 61, 0.0001, 0.01 }
                3 { return 65, 0.99, 0.01 }
                4 { return 67, 1.0, 0.01 }
                else {}
            }
        }
        77 {
            match disease_symptom {
                0 { return 40, 0.5, 0.01 }
                1 { return 41, 0.7, 0.005 }
                2 { return 51, 0.6, 0.001 }
                3 { return 55, 0.5, 0.01 }
                4 { return 61, 0.0001, 0.01 }
                else {}
            }
        }
        78 {
            match disease_symptom {
                0 { return 19, 0.4, 0.01 }
                1 { return 37, 0.5, 0.01 }
                2 { return 38, 0.8, 0.01 }
                3 { return 57, 0.5, 0.01 }
                else {}
            }
        }
        79 {
            match disease_symptom {
                0 { return 22, 0.5, 0.01 }
                1 { return 53, 0.8, 0.01 }
                2 { return 58, 0.7, 0.01 }
                3 { return 62, 0.6, 0.01 }
                4 { return 63, 0.99, 0.01 }
                else {}
            }
        }
        80 {
            match disease_symptom {
                0 { return 2, 0.9, 0.01 }
                1 { return 6, 0.9, 0.01 }
                2 { return 7, 0.9, 0.01 }
                3 { return 14, 0.9, 0.01 }
                4 { return 44, 0.5, 0.001 }
                5 { return 53, 0.8, 0.01 }
                6 { return 59, 0.5, 0.01 }
                7 { return 63, 0.8, 0.01 }
                else {}
            }
        }
        81 {
            match disease_symptom {
                0 { return 7, 0.8, 0.01 }
                1 { return 14, 0.8, 0.01 }
                2 { return 22, 0.5, 0.01 }
                3 { return 53, 0.8, 0.01 }
                4 { return 58, 0.8, 0.01 }
                5 { return 61, 0.001, 0.01 }
                6 { return 63, 0.9, 0.01 }
                else {}
            }
        }
        82 {
            match disease_symptom {
                0 { return 2, 0.8, 0.01 }
                1 { return 7, 0.8, 0.01 }
                2 { return 14, 0.9, 0.01 }
                3 { return 15, 0.7, 0.01 }
                4 { return 53, 0.6, 0.01 }
                5 { return 63, 0.99, 0.01 }
                else {}
            }
        }
        83 {
            match disease_symptom {
                0 { return 1, 0.9, 0.01 }
                1 { return 50, 0.9, 0.01 }
                2 { return 62, 0.5, 0.01 }
                else {}
            }
        }
        84 {
            match disease_symptom {
                0 { return 27, 0.2, 0.01 }
                1 { return 33, 1.0, 0.01 }
                2 { return 47, 0.9, 0.01 }
                3 { return 49, 0.2, 0.01 }
                4 { return 50, 0.8, 0.01 }
                5 { return 52, 0.8, 0.5 }
                else {}
            }
        }
        85 {
            match disease_symptom {
                0 { return 6, 0.8, 0.01 }
                1 { return 7, 0.8, 0.01 }
                2 { return 14, 0.8, 0.01 }
                3 { return 47, 0.1, 0.01 }
                4 { return 58, 0.001, 0.01 }
                5 { return 59, 0.5, 0.01 }
                6 { return 63, 0.8, 0.01 }
                else {}
            }
        }
        86 {
            match disease_symptom {
                0 { return 7, 0.5, 0.01 }
                1 { return 64, 0.9, 0.01 }
                2 { return 65, 0.9, 0.01 }
                3 { return 66, 0.9, 0.01 }
                else {}
            }
        }
        87 {
            match disease_symptom {
                0 { return 7, 0.6, 0.01 }
                1 { return 40, 0.5, 0.01 }
                2 { return 41, 0.5, 0.01 }
                3 { return 61, 0.0001, 0.01 }
                4 { return 64, 0.7, 0.01 }
                else {}
            }
        }
        88 {
            match disease_symptom {
                0 { return 7, 0.3, 0.01 }
                1 { return 41, 0.5, 0.01 }
                2 { return 64, 0.9, 0.01 }
                3 { return 65, 0.5, 0.01 }
                4 { return 66, 0.5, 0.01 }
                else {}
            }
        }
        89 {
            match disease_symptom {
                0 { return 1, 0.9, 0.01 }
                1 { return 67, 0.9, 0.01 }
                else {}
            }
        }
        90 {
            match disease_symptom {
                0 { return 7, 0.8, 0.01 }
                1 { return 14, 0.8, 0.01 }
                2 { return 16, 0.5, 0.01 }
                3 { return 40, 0.5, 0.01 }
                4 { return 41, 0.5, 0.01 }
                5 { return 44, 0.5, 0.01 }
                else {}
            }
        }
        else {}
    }
    return none
}

// Return the question about the given symptom.
fn question(symptom int) string {
    match symptom {
        0 { return '¿Estornudas mucho?' }
        1 { return '¿Te duelen los ojos, o lagrimeas mucho?' }
        2 { return '¿Te duele la garganta?' }
        3 { return '¿Tienes ronquera o afonía?' }
        4 { return '¿Toses mucho?' }
        5 { return '¿Tienes mucosidad nasal muy fluida?' }
        6 { return '¿Te duele la cabeza, o sufres, en general, de dolores de cabeza?' }
        7 { return '¿Tienes alta temperatura (superior a 37 grados centígrados)?' }
        8 { return '¿Te ves obligado, por tu trabajo, a pasar muchas horas respirando aire viciado o polvoriento?' }
        9 { return '¿Te pica la nariz?' }
        10 { return '¿Tienes la garganta reseca?' }
        11 { return '¿Respiras con dificultad y fatiga?' }
        12 { return '¿Tienes la nariz muy taponada?' }
        13 { return '¿Has tenido recientemente un resfriado u otra infección similar?' }
        14 { return '¿Tienes malestar general?' }
        15 { return '¿Tienes dificultad para tragar?' }
        16 { return '¿Tienes dolores musculares?' }
        17 { return '¿Sientes cualquier tipo de dolor en el pecho?' }
        18 { return '¿Te han extirpado las amigdalas?' }
        19 { return '¿Tus síntomas tienden a aparecer en ataques, y no a estar presentes continuamente?' }
        20 { return '¿Tienes una tos productiva, o sea una tos en la que expulsas algo?' }
        21 { return '¿Respiras entrecortadamente?' }
        22 { return '¿Sudas mucho? (No ya cuando haces un esfuerzo, sino cuando estás físicamente relajado).' }
        23 { return '¿Tienes la frecuencia cardiaca elevada? (Normalmente debe estar entre 60 y 80 pulsaciones por minuto, y algo más rápida para personas de edad superior a 70 o inferior a 20).' }
        24 { return '¿Sufres ataques de dificultades respiratorias tan fuertes que llegan a preocuparte?' }
        25 { return '¿Tienes cianosis, es decir, se te ha puesto la piel de un color ligeramente azulado?' }
        26 { return '¿Cuando toses, presentan sangre los esputos?' }
        27 { return '¿Estás aturdido o perplejo sobre cuanto acontece a tu alrededor?' }
        28 { return '¿Estás (o está el paciente) en estado delirante, hablando incoherentemente y con mala coordinación muscular?' }
        29 { return '¿Tienes una tos seca (no productiva)?' }
        30 { return '¿Sientes dolor al respirar o al toser?' }
        31 { return '¿Has sentido en estos días un dolor muy fuerte en el pecho?' }
        32 { return '¿Tienes sensaciones alternantes de frío y calor?' }
        33 { return '¿Hace ya tiempo (seis semanas o más) que presentas alguno de estos síntomas?' }
        34 { return '¿Tienes los dedos hipocráticos, o en «palillos de tambor»? (Se llaman así cuando las cutículas casi han desaparecido, y las uñas se abomban excesivamente hacia la punta).' }
        35 { return '¿Tienes síntomas que aparecen fundamentalmente al realizar algún esfuerzo?' }
        36 { return '¿Fumas? responde con el número que resulta de dividir por cinco el número de cigarrillos diarios. El número máximo para la respuesta es 5. Si no fumas, responde -5.' }
        37 { return '¿Tienes sensaciones de vértigo?' }
        38 { return '¿Tienes palpitaciones (sensación de que el corazón late más fuerte, o más rápido, o menos regularmente de lo que debiera)?' }
        39 { return '¿Tienes algún tobillo excesivamente hinchado?' }
        40 { return '¿Tienes vómitos, o fuertes náuseas?' }
        41 { return '¿Sufres de algún tipo de dolor abdominal, o dolor localizado entre las costillas inferiores y las ingles?' }
        42 { return '¿Padeces diarrea, o sueles tener crisis de diarrea?' }
        43 { return '¿Te han extirpado el apéndice?' }
        44 { return '¿Tienes ictericia? (La ictericia no es una enfermedad, sino un síntoma. Con frecuencia es más patente en los ojos: la parte blanca se torna amarillenta).' }
        45 { return '¿Te sientes tenso o inquieto?' }
        46 { return '¿Te cuesta conciliar el sueño, o te desvelas frecuentemente por la noche?' }
        47 { return '¿Tienes contracciones involuntarias o temblores?' }
        48 { return '¿Sufres de estreñimiento, o sueles tener crisis de estreñimiento?' }
        49 { return '¿Te falla la memoria, tienes dificultad para recordar hechos aislados, ya sea ocasional o regularmente?' }
        50 { return '¿Sufres afasia, es decir, has perdido capacidad para expresarte con palabras?' }
        51 { return '¿Has tenido alguna hemorragia por el recto?' }
        52 { return '¿Eres hombre o mujer? Responde con 5 para hombre y -5 para mujer. Una respuesta 0 hace que el diagnóstico sea independiente del sexo.' }
        53 { return '¿Tienes rigidez o dolor en el cuello?' }
        54 { return '¿Has sufrido algún golpe o herida de cualquier tipo en la cabeza durante las últimas semanas? (Un golpe incluso leve puede ser importante).' }
        55 { return '¿Has expulsado recientemente heces de aspecto anormal?' }
        56 { return '¿Expulsas muchos gases, por cualquier vía?' }
        57 { return '¿Tienes sensaciones repentinas de desmayo, es decir, de sentirte desfallecido y mareado, incluso, quizás con pérdida de consciencia?' }
        58 { return '¿Te pica alguna parte del cuerpo, tengas o no erupción en ella?' }
        59 { return '¿Tienes alguna erupción o lesión de cualquier tipo en la piel?' }
        60 { return '¿Tienes alguna parte del cuerpo entumecida, o con sensación de comezón u hormigueo, como de «agujas y alfileres»?' }
        61 { return '¿Es tu peso anormal? Responde con 5 para un peso excesivamente elevado, con -5 si es excesivamente bajo y con 0 si es normal.' }
        62 { return '¿Sufres de algún dolor en la cara o en la frente?' }
        63 { return '¿Tienes algún bulto, hinchazón o abultamiento, en cualquier parte del cuerpo?' }
        64 { return '¿Es anormal el color de tu orina?' }
        65 { return '¿Orinas con una frecuencia anormal?' }
        66 { return '¿Tienes dolores al orinar?' }
        67 { return '¿Tienes alguna anormalidad en la visión, como ver borroso o doble, o luces destelleantes? (No cuentan los defectos que pueden corregirse con gafas).' }
        else {}
    }
    return ''
}

// user_input.v
//
// This file is part of Experto en enfermedades (Expert on diseases)

// Last modified 20250812T1907+0200.

/*

Copyright (C) 1985, Chris Naylor: Sinclair BASIC code included in his book
"Build Your Own Expert System" (Sigma Press, 1985).

Copyright (C) 1988, 1989, Marcos Cruz (programandala.net): SuperBASIC version
(http:///programandala.net/es.programa.sistema_experto_sobre_enfermedades.html).

Copyright (C) 2023, 2024, Marcos Cruz (programandala.net): Odin version.

Copyright (C) 2024, 2025, Marcos Cruz (programandala.net): SBASIC version.

Copyright (C) 2025, Marcos Cruz (programandala.net): V version.

This program is licensed under a BSD 2-Clause License
(https://opensource.org/license/bsd-2-clause/). See the <LICENSE.txt> file.

*/

// ==========================================================================
import os
import rand
import strconv

const prompt = '> '

fn user_input_string() string {
    print(prompt)
    return os.input('')
}

fn print_menu() {
    if debug_level == 0 {
        println('Comandos:') // XXX TODO par.whole
    } else {
        println('Comandos principales:') // XXX TODO par.whole
    }
    println('- Consultar') // XXX TODO par.whole
    println('- Finalizar') // XXX TODO par.whole
    if debug_level > 0 {
        println('Comandos para depuración:') // XXX TODO par.whole
        println('- Probar (modo automático con respuestas aleatorias)') // XXX TODO par.whole
        unsafe {
            println(strconv.v_sprintf('- Número de ${min_answer} a ${max_answer} (modo automático con respuesta única)')) // XXX TODO par.whole
        }
    }
}

// Ask the user for permission to start a new consult; return `true` for yes
// and `false` for no.
fn ready() bool {
    for {
        print_menu()
        mut answer := user_input_string().to_lower()
        match true {
            answer.starts_with('consultar') {
                mode = .normal_mode
                return true
            }
            answer.starts_with('finalizar') {
                return false
            }
            answer.starts_with('probar') {
                if debug_level > 0 {
                    mode = .random_demo_mode
                    return true
                }
            }
            else {
                demo_value = valid_answer(answer) or { continue }
                mode = .value_demo_mode
                return true
            }
        }
    }
    return false
}

fn press_enter() {
    println('')
    println('Pulsa la tecla «intro» para empezar.') // XXX TODO par.whole
    user_input_string()
}

// Check the given user answer string; if it is valid, return its numerical
// value; otherwise return an error.
fn valid_answer(answer string) !int {
    match answer.len {
        1 {
            if !'012345'.contains(answer) {
                return error('Formato de número incorrecto o no en el rango permitido.')
            }
        }
        2 {
            if !'+-'.contains(answer.substr(0, 1)) {
                return error('Formato de número incorrecto.')
            }
            if !'012345'.contains(answer.substr(1, 1)) {
                return error('Formato de número incorrecto o no en el rango permitido.')
            }
        }
        else {
            return error('Formato de número incorrecto.')
        }
    }
    return strconv.atoi(answer)
}

// Prompt the user for a valid answer, check it and return it.
fn user_answer() int {
    mut answer_value := 0
    for {
        unsafe {
            println(strconv.v_sprintf('Responde con un número de ${min_answer} a ${max_answer}:')) // XXX TODO par.whole
            println(strconv.v_sprintf('${min_answer} (no, nunca) … 0 … ${max_answer} (sí, siempre)')) // XXX TODO par.whole
        }
        answer_value = valid_answer(user_input_string()) or {
            println(err)
            continue
        }
        break
    }
    return answer_value
}

// Return a random number in the range `min_answer ... max_answer`.
fn random_answer() int {
    return rand.intn(max_answer - min_answer + 1) or { 0 } + min_answer
}

// VERSION.v
//
// This file is part of Experto en enfermedades (Expert on diseases)

// Last modified 20250812T1908+0200.

/*

Copyright (C) 1985, Chris Naylor: Sinclair BASIC code included in his book
"Build Your Own Expert System" (Sigma Press, 1985).

Copyright (C) 1988, 1989, Marcos Cruz (programandala.net): SuperBASIC version
(http:///programandala.net/es.programa.sistema_experto_sobre_enfermedades.html).

Copyright (C) 2023, 2024, Marcos Cruz (programandala.net): Odin version.

Copyright (C) 2024, 2025, Marcos Cruz (programandala.net): SBASIC version.

Copyright (C) 2025, Marcos Cruz (programandala.net): V version.

This program is licensed under a BSD 2-Clause License
(https://opensource.org/license/bsd-2-clause/). See the <LICENSE.txt> file.

*/

// ==========================================================================

const version = '0.1.0-dev.0.28.2+20250626T0104CEST'

Descargas

La descarga estará disponible tras la publicación del repositorio.

Páginas relacionadas

Experto en enfermedades (versión en SuperBASIC)
Sistema experto sobre enfermedades, escrito en SuperBASIC para el sistema operativo QDOS y compatibles.
Experto en enfermedades (versión en Odin)
Sistema experto sobre enfermedades, escrito en Odin.
Experto en enfermedades (versión en SBASIC)
Sistema experto sobre enfermedades, escrito en SBASIC para el sistema operativo SMSQ/E.
Experto en enfermedades (versión en D)
Sistema experto sobre enfermedades, escrito en D.