<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Baltasar García Perez-Schofield</title>
    <description>The latest articles on DEV Community by Baltasar García Perez-Schofield (@baltasarq).</description>
    <link>https://dev.to/baltasarq</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F156438%2Fc92243a0-0316-41ba-9445-ba8c9ee76d3b.png</url>
      <title>DEV Community: Baltasar García Perez-Schofield</title>
      <link>https://dev.to/baltasarq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/baltasarq"/>
    <language>en</language>
    <item>
      <title>Street Smart Coding</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Wed, 01 Apr 2026 13:15:38 +0000</pubDate>
      <link>https://dev.to/baltasarq/cesar-aguirres-street-smart-coding-31ec</link>
      <guid>https://dev.to/baltasarq/cesar-aguirres-street-smart-coding-31ec</guid>
      <description>&lt;p&gt;Hace ya algún tiempo que tengo &lt;a href="http://bit.ly/csarag-ssc" rel="noopener noreferrer"&gt;&lt;em&gt;Street Smart Coding&lt;/em&gt;&lt;/a&gt;, un libro de programación escrito en inglés, por &lt;a href="https://dev.to/canro91"&gt;César Aguirre&lt;/a&gt;, uno de los escritores más prolíficos aquí en &lt;a href="http://dev.to"&gt;dev.to&lt;/a&gt;, y me propuse escribir una revisión del mismo.&lt;/p&gt;

&lt;p&gt;Cuando lees este libro, te das cuenta de un detalle importantísimo, y que para mi valida su contenido como para recomendarlo a cualquiera: está escrito desde la experiencia. Es decir, no te dice cómo hay que hacer las cosas, sino cómo aprendió personalmente cómo hay que hacer las cosas.&lt;/p&gt;

&lt;p&gt;Pongamos un ejemplo. He escogido este porque no tiene que ver directamente con programación, sino con lo que hoy en día se denomina &lt;em&gt;soft skills&lt;/em&gt;. A mi me gusta más el término acuñado ya hace unos años: &lt;em&gt;peopleware&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;That day, I learned it's never just five minutes. Next time someone says "just five minutes," remember it could turn into 3:00AM the next day. Say no.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Encontraremos este párrafo en el capítulo &lt;em&gt;Learn to say no&lt;/em&gt;, junto con &lt;em&gt;Saying yes to everything often means saying no to the people who matter most. You need healthy boundaries instead. Sometimes, all it takes is one single word: no&lt;/em&gt;. Efectivamente, aprender a decir &lt;strong&gt;no&lt;/strong&gt; es muy importante, tan importante que si no lo haces, puede implicar decir &lt;em&gt;no&lt;/em&gt; a tus más allegados: los límites son importantes. ¿Pero, cómo puedes explicarle a un desarrollador &lt;em&gt;junior&lt;/em&gt; que es importante saber decir &lt;strong&gt;no&lt;/strong&gt;? La única forma es hacerlo a través de una experiencia personal (experiencia que encontraremos en ese capítulo, junto a las conclusiones ya mencionadas), y ahí es donde está la fortaleza real de este libro.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Never, ever, ever tell anyone they're wrong&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Efectivamente, siempre hay una forma distinta de hablar con alguien, incluso convercerlo de algo, más productiva, en lugar de decirle: "no, eso está mal." Personalmente, esto lo aprendí en mi trabajo como profesor; pronto me di cuenta de que decirle a un alumno que algo que había dicho estaba mal era la mejor forma de conseguir que dejase de participar en clase. Quizás en una relación profesor-alumno podemos asumir que decir "no, eso está mal", debería ser una posibilidad real y por lo tanto constructiva, pero no lo es. Así, una pequeña modificación de esa frase tan simple podría ser: "eso es cierto, pero también hay que tener en cuenta..." Y es que, la confianza de tu interlocutor en ti termina cuando le dices que algo está mal. Es indiferente si tienes razón o no.&lt;/p&gt;

&lt;p&gt;Vamos con algo de código, C# en este caso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;movies&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;"The Matrix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Inception"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Interstellar"&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;César nos explica que podemos sustituir el código de arriba por el siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;movies&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;"The Matrix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Inception"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Interstellar"&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;", "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;movies&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿La diferencia? Que hay código que no escribimos nosotros. Efectivamente, siempre que abordo un proyecto cualquiera, siempre tengo que &lt;em&gt;descender&lt;/em&gt; por debajo del nivel de abstracción en el que yo deseo estar; es decir, siempre que me planteo escribir código como el de arriba, me pregunto. ¿Para algo tan básico y repetitivo, no hay ya una función/clase/biblioteca que lo haga?&lt;/p&gt;

&lt;p&gt;Podemos encontrar este ejemplo en &lt;em&gt;Know your standard library&lt;/em&gt;. ¿Por qué no escribir código es algo importante? Porque podemos apoyarnos en código ya escrito, de manera que nos evitemos una tarea menor y repetitiva, reutilizando código que alguien ya se ha molestado en desarrollar y probar para nosotros, lo que nos permite centrarnos en el código realmente importante. No reinventes la rueda, apóyate en código de calidad, en cambio.&lt;/p&gt;

&lt;p&gt;¿Por qué nos comenta el autor esto? Pues porque él mismo se ha encontrado con código similar, independientemente del lenguaje de programación, en casi todos los trabajos en los que ha estado. Volvemos así al aspecto de la experiencia personal.&lt;/p&gt;

&lt;p&gt;Estos son solo unos pocos ejemplos de lo que puedes encontrar en &lt;em&gt;Street Smart Coding&lt;/em&gt;. ¿Te lo vas a perder?&lt;/p&gt;

</description>
      <category>book</category>
      <category>spanish</category>
      <category>review</category>
      <category>development</category>
    </item>
    <item>
      <title>Un nuevo C: el C++ ligero.</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Mon, 23 Mar 2026 12:09:51 +0000</pubDate>
      <link>https://dev.to/baltasarq/un-nuevo-c-el-c-ligero-467c</link>
      <guid>https://dev.to/baltasarq/un-nuevo-c-el-c-ligero-467c</guid>
      <description>&lt;h2&gt;
  
  
  Buscando el camino
&lt;/h2&gt;

&lt;p&gt;Hay muchas críticas que se le pueden hacer a C++: que si permite comportamiento indefinido sin avisar (incluso lo aplica en el modo de optimización más agresivo), que si ha crecido hasta límites desmesurados, que si el precio a pagar es el de unos ejecutables monstruosos... Últimamente, la crítica se ha centrado en la seguridad  del manejo de la memoria. Por ejemplo, la &lt;a href="https://www.genbeta.com/actualidad/no-c-c-casa-blanca-pide-dejar-usar-lenguajes-programacion-que-base-windows-linux-macos" rel="noopener noreferrer"&gt;Casa Blanca ha pedido &lt;em&gt;pasarse&lt;/em&gt; a lenguajes más seguros&lt;/a&gt;, como por ejemplo C# o Rust. &lt;a href="https://www.reclunautas.com/post/estendencia-dejar-de-usar-c-y-c-y-centrarse-en-rust-y-java" rel="noopener noreferrer"&gt;La NSA ha emitido recomendaciones similares sobre abandonar C y C++&lt;/a&gt;. Incluso &lt;a href="https://en.wikipedia.org/wiki/Criticism_of_C%2B%2B" rel="noopener noreferrer"&gt;la Wikipedia tiene una página dedicada a las críticas a C++&lt;/a&gt;. Esta &lt;a href="https://www.genbeta.com/desarrollo/creador-c-critica-informe-nsa-que-defiende-superioridad-lenguajes-seguros-como-rust" rel="noopener noreferrer"&gt;crítica a C++ no ha sentado nada bien a Bjarne Stroustrup&lt;/a&gt;, el creador original del lenguaje de programación C++.&lt;/p&gt;

&lt;p&gt;En cualquier caso, todo esto lo que ha provocado es que hayan surgido nuevos lenguajes de programación para sustituir a C++, siendo los más conocidos &lt;a href="https://dotnet.microsoft.com/en-us/languages/csharp" rel="noopener noreferrer"&gt;C#&lt;/a&gt; y &lt;a href="https://dev.java/" rel="noopener noreferrer"&gt;Java&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pero esto no quiere decir que no existan muchos más, que han surgido buscando eliminar puntos de fricción de C++, simplificar la experiencia de programación, y aportar sus propias características. Notables menciones son &lt;a href="https://ziglang.org/" rel="noopener noreferrer"&gt;Zig&lt;/a&gt;, &lt;a href="https://vlang.io/" rel="noopener noreferrer"&gt;V&lt;/a&gt;, o &lt;a href="https://rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En 2013, Bas vd Berg creó &lt;a href="http://c2lang.org/" rel="noopener noreferrer"&gt;C2, una evolución del lenguaje de programación C&lt;/a&gt; con el objetivo de eliminar complejidad innecesaria. Por ejemplo, no presenta archivos de cabecera &lt;code&gt;.h&lt;/code&gt;, no hay macros... &lt;/p&gt;

&lt;p&gt;&lt;a href="https://c3-lang.org/" rel="noopener noreferrer"&gt;El lenguaje de programación C3&lt;/a&gt; se basa en C2 para ofrecer un mismo objetivo, pero además con ciertas capacidades que lo acercan a C++. Y este es el objetivo de este artículo.&lt;/p&gt;

&lt;h2&gt;
  
  
  C3
&lt;/h2&gt;

&lt;p&gt;El &lt;code&gt;¡Hola, mundo!&lt;/code&gt; en este lenguaje de programación es como sigue a continuación.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"¡Hola, mundo!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para compilarlo, aunque podríamos haber creado un proyecto completo, podemos simplemente hacer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;c3c compile holamundo.c3
&lt;span class="nv"&gt;$ &lt;/span&gt;./holamundo
¡Hola, mundo!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Las diferencias sintáticas con C son muy pocas: las funciones van ahora precedidas de &lt;code&gt;fn&lt;/code&gt;, de manera que se distingan facilmente de cualquier otra estructura. No hay archivos de cabecera, sino verdaderos módulos que son utilizados mediante &lt;code&gt;import&lt;/code&gt;. El significado, la semántica del programa, es mucho más evidente que en C.&lt;/p&gt;

&lt;p&gt;El siguiente es un programa que trata de generar ternas pitagóricas a partir de números aleatorios.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Terna&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;Terna&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;sqa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;sqb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;sqc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;sqc&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;sqa&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sqb&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;Terna&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;tformat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"(%d, %d, %d)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Lcg128Random&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Terna&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;printn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"Ternas pitagóricas&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Calculando..."&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;_000_000_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Terna&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_long&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_long&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_long&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"%d ternas encontradas tras %d ciclos.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Terna&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;printn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El programa crea una estructura &lt;strong&gt;Terna&lt;/strong&gt;, que consta de tres enteros &lt;code&gt;long&lt;/code&gt; (128 bits) sin signo. La idea es que la suma de los cuadrados de &lt;em&gt;a&lt;/em&gt; y &lt;em&gt;b&lt;/em&gt; debe ser igual a &lt;em&gt;c&lt;/em&gt;. Esta propiedad se verifica mediante el método &lt;code&gt;Terna.chk()&lt;/code&gt;. El método &lt;code&gt;Terna.str()&lt;/code&gt; devuelve los valores de la terna como texto.&lt;/p&gt;

&lt;p&gt;Así que utilizamos &lt;strong&gt;Lcg128Random&lt;/strong&gt; del módulo &lt;code&gt;std::math::random&lt;/code&gt; para generar enteros de 128 bits. Con un bucle, probamos a generar números aleatorios, y si se crea una terna válida, se añade a una lista (esta lista puede crecer dinámicamente).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C3&lt;/strong&gt; se siente bastante directo, fácil de comprender (no existe una nueva sintaxis), con un compilador que genera ejecutables rápidamente, y que son muy rápidos ellos mismos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;c3c compile ternas_pitagoricas.c3
&lt;span class="nv"&gt;$ &lt;/span&gt;./ternas_pitagoricas                                                  Ternas pitagóricas
Calculando...
1 ternas encontradas tras 1000000000 ciclos.
&lt;span class="o"&gt;(&lt;/span&gt;3, 4, 5&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El ejecutable realiza mil millones (1 000 000 000) de ciclos en unos 17 segundos de manera consistente. Esto involucra crear una terna, llamar su método &lt;code&gt;chk()&lt;/code&gt; (que consiste en un cálculo matemático), y añadirlo o no a una lista.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt; ./ternas_pitagoricas
Ternas pitagóricas
Calculando...
1 ternas encontradas tras 1000000000 ciclos.
&lt;span class="o"&gt;(&lt;/span&gt;3, 4, 5&lt;span class="o"&gt;)&lt;/span&gt;
./ternas_pitagoricas  16,38s user 0,00s system 99% cpu 16,438 total

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt; ./ternas_pitagoricas
Ternas pitagóricas
Calculando...
1 ternas encontradas tras 1000000000 ciclos.
&lt;span class="o"&gt;(&lt;/span&gt;3, 4, 5&lt;span class="o"&gt;)&lt;/span&gt;
./ternas_pitagoricas  16,35s user 0,00s system 99% cpu 16,402 total

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt; ./ternas_pitagoricas
Ternas pitagóricas
Calculando...
1 ternas encontradas tras 1000000000 ciclos.
&lt;span class="o"&gt;(&lt;/span&gt;3, 4, 5&lt;span class="o"&gt;)&lt;/span&gt;
./ternas_pitagoricas  16,31s user 0,00s system 99% cpu 16,368 total
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El ejecutable es de unos 700 k, como se muestra a continuación.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; ternas_pitagoricas                                             
&lt;span class="go"&gt;-rwxr-xr-x 1 baltasarq baltasarq 702640 mar 23 12:13 ternas_pitagoricas
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿Podemos compararlo con una versión C++? Pues claro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;list&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Terna&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;Terna&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;chk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;sqa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;sqb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;sqc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;sqc&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;sqa&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sqb&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;", "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;", "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Terna&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"Ternas pitagóricas&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;ulong&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;Terna&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000000000ul&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Terna&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"%lu ternas encontradas tras %lu ciclos.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Terna&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La salida devuelve la solución tras mil millones de ciclos en unos 17 segundos de manera consistente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;g++ ternas_pitagoricas.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; ternas_pitagoricas
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt; ./ternas_pitagoricas
Ternas pitagóricas
1 ternas encontradas tras 1000000000 ciclos.
3, 4, 5
./ternas_pitagoricas  17,20s user 0,00s system 99% cpu 17,270 total
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obtenemos un resultado similar. Esto no es extraño, pues aprovecha el backend de LLVM.&lt;/p&gt;

&lt;p&gt;En este caso, C++ es capaz de generar el ejecutable más pequeño, aunque es cierto que no se emplea la estructura de entrada y salida oficial, &lt;em&gt;IOStreams&lt;/em&gt;. También es importante notar que el ejecutable enlaza con la librería estándar de C++, que no es, precisamente, pequeña (unos 3 MB). C3 genera, por otra parte, un ejecutable que es autocontenido.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;g++ ternas_pitagoricas.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; ternas_pitagoricas    
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; ternas_pitagoricas
&lt;span class="nt"&gt;-rwxr-xr-x&lt;/span&gt; 1 baltasarq baltasarq 44320 mar 23 12:54 ternas_pitagoricas
&lt;span class="nv"&gt;$ &lt;/span&gt;ldd ternas_pitagoricas                                                
        linux-vdso.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007faefdf04000&lt;span class="o"&gt;)&lt;/span&gt;
        libstdc++.so.6 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libstdc++.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007faefdc00000&lt;span class="o"&gt;)&lt;/span&gt;
        libm.so.6 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libm.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007faefdae2000&lt;span class="o"&gt;)&lt;/span&gt;
        libgcc_s.so.1 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libgcc_s.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007faefdab5000&lt;span class="o"&gt;)&lt;/span&gt;
        libc.so.6 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libc.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007faefd8c4000&lt;span class="o"&gt;)&lt;/span&gt;
        /lib64/ld-linux-x86-64.so.2 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib64/ld-linux-x86-64.so.2 &lt;span class="o"&gt;(&lt;/span&gt;0x00007faefdf06000&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;c3c compile ternas_pitagoricas.c3                                    
Program linked to executable &lt;span class="s1"&gt;'./ternas_pitagoricas'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;ldd ternas_pitagoricas
        linux-vdso.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007fad32973000&lt;span class="o"&gt;)&lt;/span&gt;
        libm.so.6 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libm.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007fad32796000&lt;span class="o"&gt;)&lt;/span&gt;
        libc.so.6 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libc.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007fad325a5000&lt;span class="o"&gt;)&lt;/span&gt;
        /lib64/ld-linux-x86-64.so.2 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib64/ld-linux-x86-64.so.2 &lt;span class="o"&gt;(&lt;/span&gt;0x00007fad32975000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿El sucesor oficial, o al menos un lenguaje estable? Es difícil decirlo, solo el tiempo lo dirá.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>programming</category>
      <category>systems</category>
      <category>development</category>
    </item>
    <item>
      <title>Hackeando en 8 bits (y IV)</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Mon, 16 Mar 2026 17:43:35 +0000</pubDate>
      <link>https://dev.to/baltasarq/hackeando-en-8-bits-y-iv-9hi</link>
      <guid>https://dev.to/baltasarq/hackeando-en-8-bits-y-iv-9hi</guid>
      <description>&lt;p&gt;Y vamos a terminar ahora con la serie dedicada a &lt;em&gt;hackear&lt;/em&gt; juegos en el Speccy, lo que se conocía en la época como &lt;em&gt;desprotegerlos&lt;/em&gt;. Vamos a buscar vidas infinitas em &lt;a href="https://worldofspectrum.net/infoseek/?regexp=abu+simbel+profanation" rel="noopener noreferrer"&gt;Abu Simbel Profanation&lt;/a&gt; e &lt;a href="https://worldofspectrum.net/item/0002450/" rel="noopener noreferrer"&gt;Ikari Warriors&lt;/a&gt;. Y como herramienta, utilizaremos em emulador de Spectrum &lt;a href="https://github.com/chernandezba/zesarux" rel="noopener noreferrer"&gt;Zesarux&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En la última entrega de esta serie, vimos a grandes rasgos cómo crear uno de aquellos cargadores que proporcionaban vidas infinitas o bombas infinitas, o cualquier otro &lt;em&gt;cheat&lt;/em&gt;, metiendo &lt;strong&gt;POKE&lt;/strong&gt;s justo antes de la ejecución del programa.&lt;/p&gt;

&lt;p&gt;Pero en esta entrega vamos a centrarnos en otro tipo de &lt;em&gt;hack&lt;/em&gt;: simularemos que tenemos un &lt;a href="https://worldofspectrum.net/item/0022960/" rel="noopener noreferrer"&gt;&lt;strong&gt;Multiface&lt;/strong&gt;&lt;/a&gt;. Este aparato permite, conectado a la parte trasera del Speccy, pulsar un botón rojo que genera una &lt;a href="https://es.wikipedia.org/wiki/Interrupci%C3%B3n_no_enmascarable" rel="noopener noreferrer"&gt;NMI&lt;/a&gt; (&lt;em&gt;Non Maskable Interruption&lt;/em&gt; o interrupción no enmascarable). Al pulsar el botón, al Speccy no le queda más remedio, esté haciendo lo que esté haciendo, que ejecutar el código del vector de interrupción dado, lo que ejecuta su software mientras el software está en memoria. Lo que se podía hacer entonces era guardar el contenido de la memoria (con lo que podías guardar el juego tal cual se estaba ejecutando en ese momento), introducir &lt;strong&gt;POKE&lt;/strong&gt;s, o explorar la memoria.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fba1c0754jke0iy7sibts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fba1c0754jke0iy7sibts.png" alt="Abu Simbel Profanation" width="544" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos a simular, como decía, la forma de utilizar un periférico como &lt;strong&gt;Multiface&lt;/strong&gt;, pero con la comodidad de un emulador de hoy en día. Todo lo que vamos a hacer aquí se puede hacer con dicho aparato enchufado y siguiendo sus instrucciones, pero lógicamente es mucho más tedioso.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6j5gn2ksdozk03uzdhly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6j5gn2ksdozk03uzdhly.png" alt="Abu Simbel Profanation tras NMI" width="645" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abu Simbel Profanation
&lt;/h2&gt;

&lt;p&gt;Este juego fue creado por Víctor Ruiz para su sello familiar (compartido con sus heramanos), &lt;strong&gt;Dinamic&lt;/strong&gt;. Según las entrevistas que se le han hecho con el tiempo, fue creado en una especie de versión más limitada de BASIC, que era posible compilar a código máquina.&lt;/p&gt;

&lt;p&gt;Al arrancar Zesarux, seleccionamos la cinta a cargar en el menú &lt;code&gt;Z&lt;/code&gt; &amp;gt;&amp;gt; &lt;em&gt;smart load&lt;/em&gt;, que en este caso será el .TAP o .TZX descargado desde la web de &lt;em&gt;World of Spectrum&lt;/em&gt;. Este emulador es muy particular, y cargará la cinta él solo, como si hubiéramos tecleado la secuencia de comandos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpyz06cnef3tqnusi5fdg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpyz06cnef3tqnusi5fdg.png" alt="Abu Simbel Profanation en Zesarux" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cuando el juego se ejecute, seleccionamos la opción &lt;code&gt;3. keyboard&lt;/code&gt; (o &lt;code&gt;2. kempston&lt;/code&gt; si tenemos un controlador conectado), y el juego nos sitúa dentro de la pirámide con cierta (infame) gota cayendo desde el techo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0i6x8tix6xq6p4tik108.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0i6x8tix6xq6p4tik108.png" alt="Menu Find de Zesarux" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En la parte superior del escritorio de &lt;strong&gt;Zesarux&lt;/strong&gt;, a la derecha de la pantalla del Speccy, veremos un icono de una cucaracha: se trata de las opciones que nos permitirán depurar un programa. Vamos a utilizarlo para encontrar pokes. Nos metemos en la opción &lt;em&gt;Debug&lt;/em&gt; &amp;gt;&amp;gt; &lt;em&gt;Find&lt;/em&gt; &amp;gt;&amp;gt; &lt;em&gt;Find bytes&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi73m9h8jzxc2ktb0t9br.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi73m9h8jzxc2ktb0t9br.png" alt="Menu Find Bytes de Zesarux" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Menú&lt;/th&gt;
&lt;th&gt;Submenú&lt;/th&gt;
&lt;th&gt;Submenú&lt;/th&gt;
&lt;th&gt;Submenú&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Debug&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Find&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Find bytes&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Find bytes (initial)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Find bytes (next)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;View results&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Clear results&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;En la tabla anterior vemos las posibilidades del menú. Aunque hay opciones automatizadas para buscar &lt;strong&gt;POKE&lt;/strong&gt;s, lo haremos de forma genérica para permitir buscar &lt;em&gt;cheats&lt;/em&gt; sobre municiones, granadas, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxbzmuw6o2q77hwxjgz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxbzmuw6o2q77hwxjgz4.png" alt="Find bytes initial" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Comenzamos. La primera vez seleccionamos (1), &lt;em&gt;Find bytes (initial)&lt;/em&gt;. Ahora que estamos en el juego podemos buscar el valor 10, que introducimos, pues es el número inicial de vidas. Nos dará varios cientos de resultados, como es de esperar, pero lo importante es que Zesarux va a recordar los resultados. Así, la siguiente vez que entremos en el menú, nos encontraremos con (2) &lt;em&gt;Find bytes (next)&lt;/em&gt;, en lugar de la opción (1). ¡Pero espera! Aún es pronto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjur464e52bk1r0lj3pg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjur464e52bk1r0lj3pg.png" alt="Ver resultados" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mueve a &lt;em&gt;Johnny Jones&lt;/em&gt; con las teclas &lt;code&gt;O&lt;/code&gt; (izquierda), &lt;code&gt;P&lt;/code&gt; (derecha), y &lt;code&gt;Q&lt;/code&gt; (salto) hasta... sí, la gota. Ponle debajo y pierde una vida. Confía en mi, merecerá la pena... Es verdad, ahora solo tienes 9 vidas, pero verás lo que pasa.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbs61f4wx3jee4pi1llvf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbs61f4wx3jee4pi1llvf.png" alt="Nueve vidas en Abu Simbel Profanation" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Volvemos al menú de &lt;em&gt;Find&lt;/em&gt; y (2) &lt;em&gt;Find bytes (next)&lt;/em&gt;, y esta vez introducimos 9. ¡Solo hay una coincidencia! Pulsamos ESC y volvemos al mismo submenú para seleccionar (3) &lt;em&gt;View results&lt;/em&gt;.  La dirección de memoria con valor 9 es 38818. ¡Ya sabemos en qué posición de memoria guarda el juego las vidas! &lt;/p&gt;

&lt;p&gt;Nos vamos de nuevo al menú &lt;em&gt;Debug&lt;/em&gt;, y esta vez seleccionamos la opción &lt;strong&gt;POKE&lt;/strong&gt;. Seleccionamos la primera opción, &lt;em&gt;&lt;strong&gt;POKE&lt;/strong&gt;...&lt;/em&gt;. Nos pregunta la dirección, introducimos 38818. A continuación, nos pregunta con qué valor queremos modificar la dirección 38818. En cada posición de memoria, solo podemos escribir un valor entre 0 y 255. Sabemos que va a ser el número de vidas disponible, así que... ¡qué caray! ¡Introduzcamos 255! ¡Mejor que zozobre que no que zofalte!&lt;/p&gt;

&lt;p&gt;A continuación, nos pregunta cuántos bytes queremos modificar. Lo más normal es, como en esta ocasión, que sea solo uno. Pero es posible que, para valores por encima de 255, un juego utilice dos (el mínimo), o más bytes. En este caso, simplemente introducimos 1.&lt;/p&gt;

&lt;p&gt;Tras pulsar ENTER, puede que pensemos que algo ha ido mal. Que no ha cambiado nada. Pero... llevemos a &lt;em&gt;Johnny&lt;/em&gt; hasta la gota, para morir de nuevo. Solo una vez más. Si lo hacemos... ¡habrán aparecido 254 vidas restantes! Tiene sentido que el juego solo actualice el marcador de vidas del jugador cuando este número cambia... es decir, cambia según las reglas &lt;em&gt;normales&lt;/em&gt; del juego.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7dazmufft8fjx7am3mi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7dazmufft8fjx7am3mi.png" alt="199 vidas" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Un detalle curioso es que no aparece solo "254", sino "0254". Está claro que Víctor Ruiz quería que los marcadores estuvieran "equilibrados", ya que hay más de 10 pantallas, y en la primera se muestra como "01", no como "1". Está claro que el número de vidas es tan exagerademente alto, que el algoritmo para mostrar vidas se desborda. Literalmente.&lt;/p&gt;

&lt;p&gt;Un detalle... creo que es en la segunda o en la tercera pantalla que es posible caer en un pozo vertical que termina en unas mortíferas agujas... Es importante que no caigas ahí, o... tendrás que esperar a morir doscientas y pico veces (o, mejor, hacer un &lt;strong&gt;POKE&lt;/strong&gt; de 38818 con 1).&lt;/p&gt;

&lt;p&gt;Si queremos buscar algún otro valor en memoria, tendremos que seleccionar (4) &lt;em&gt;Clear results&lt;/em&gt;, para poder volver a empezar, seleccionando de nuevo la opción (1) &lt;em&gt;Find bytes (initial)&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ikari Warriors
&lt;/h2&gt;

&lt;p&gt;El siguiente juego que &lt;em&gt;desprotegeremos&lt;/em&gt; es &lt;strong&gt;Ikari Warriors&lt;/strong&gt;. Descárgate el .TAP o el .TZX, y cárgalo en &lt;strong&gt;Zesarux&lt;/strong&gt;, de nuevo mediante la opción de menú &lt;code&gt;Z&lt;/code&gt; &amp;gt;&amp;gt; &lt;em&gt;Smart load&lt;/em&gt;. El juego pide seleccionar el controlador del primer jugador, y después del segundo jugador. En mi caso, redefeniré las teclas (opción 1), del juego para el &lt;strong&gt;Jugador 1&lt;/strong&gt;, y cualquier otra cosa pra el &lt;strong&gt;Jugador 2&lt;/strong&gt;, pues no pienso usarlo. Finalmente, seleccionamos (1) (&lt;em&gt;Start one player game&lt;/em&gt;) para comenzar el juego.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2df5e97g4vit05tct1qz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2df5e97g4vit05tct1qz.png" alt="Ikari Warriors en Zesarux" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Las vidas están representadas mediante cabezas del héroe, son 6 en total. Así que seleccionamos (1) &lt;em&gt;Find bytes (initial)&lt;/em&gt;, e introducimos 6 (o las vidas que nos queden en ese momento, el juego no se anda con chiquitas). Nos dirá que hay más de seiscientos resultados. Seguramente ya nos habrán matado una o dos veces, seleccionamos (2) &lt;em&gt;Find bytes (next)&lt;/em&gt; e introducimos el número de vidas que nos quede. Ahora ya solo aparecerá un resultado. Con (3) &lt;em&gt;View results&lt;/em&gt;, comprobaremos que la dirección de memoria de las vidas es 58478. Ahora seleccionamos &lt;em&gt;Debug&lt;/em&gt; &amp;gt;&amp;gt; &lt;em&gt;Poke&lt;/em&gt; &amp;gt;&amp;gt; &lt;em&gt;Poke...&lt;/em&gt;. Introducimos la dirección de memoria, 58478. A continuación, nos pide un valor, sabemos que como máximo puede estar entre 0 y 255. Pero... ¡cuidado! Recuerda que las vidas se representan con figuras en la pantalla. Si introducimos un valor demasiado alto, las figuras se extenderán corrompiendo la pantalla, e impidiendo que nuestro héroe se mueva por ella. Un valor seguro es 40, ya que son las 10 filas por cuatro figuras que se pueden representar en pantalla sin sobrepasar el espacio destinado para ellas. El juego, como decía, no se anda con chiquitas, así que tendrás que introducir el &lt;strong&gt;POKE&lt;/strong&gt; a 58478 con 40 &lt;strong&gt;varias veces&lt;/strong&gt;. En cambio, es bastante improbable que te quedes sin granadas, pudiendo llegar a acumular varias docenas. Así que, personalmente, no creo que merezca la pena buscar el &lt;strong&gt;POKE&lt;/strong&gt; correspondiente. Aún así, lo hice por experimentar, pero... no salió nada, ni con las granadas ni con los disparos. Probablemente, algún tema de ofuscación, curioso.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevfa16ywjbeo40ezywxj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevfa16ywjbeo40ezywxj.png" alt="Ikari Warriors en Zesarux con 40 vidas" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En cualquier caso, ya sabes cómo encontrar vidas en un juego. ¡Enhorabuena, eres un &lt;em&gt;hacker&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;¿Qué?&lt;br&gt;
¿Cómo?&lt;br&gt;
¿Qué con estas técnicas y ciertos programas buscadores de &lt;em&gt;cheats&lt;/em&gt;, también se pueden buscar vidas infinitas en lo juegos de ahora? No tengo ni idea de lo que me estás hablando...&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>sinclair</category>
      <category>games</category>
      <category>hack</category>
    </item>
    <item>
      <title>Hackeando en 8 bits (y III)</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Fri, 13 Mar 2026 12:18:41 +0000</pubDate>
      <link>https://dev.to/baltasarq/hackeando-en-8-bits-y-iii-i07</link>
      <guid>https://dev.to/baltasarq/hackeando-en-8-bits-y-iii-i07</guid>
      <description>&lt;p&gt;Como hemos visto en las dos entregas anteriores, todo se reduce a un concepto: &lt;a href="https://dev.to/baltasarq/hackeando-en-8-bits-2d6e"&gt;cambiar la memoria&lt;/a&gt;. Si lo hacemos cuidadosamente, podemos colocar, o bien nuestras propias instrucciones, &lt;a href="https://dev.to/baltasarq/hackeando-en-8-bits-y-ii-2e8n"&gt;cambiando el comportamiento del programa&lt;/a&gt;, o bien nuestros propios datos, de manera que podamos cambiar el número de vidas, el número de balas, el número de bombas... etc.&lt;/p&gt;

&lt;p&gt;En esta entrega vamos a ver un ejemplo real, centrándonos en &lt;a href="https://worldofspectrum.net/item/0004916/" rel="noopener noreferrer"&gt;Stop the express&lt;/a&gt;. Vamos a seguir el proceso de creación de un cargador que nos proporcione vidas y tiempo infinito. Lo que hoy en día se conoce como &lt;code&gt;cheats&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Encontrar las posiciones de memoria adecuadas y saber modificarlas, implica tener conocimientos de &lt;a href="https://clrhome.org/table/" rel="noopener noreferrer"&gt;ensamblador y código máquina del Z80&lt;/a&gt;, el microprocesador dentro del ZX Spectrum. En este pequeño artículo lo haremos paso a paso, sin asumir conocimientos previos.&lt;/p&gt;

&lt;p&gt;Comencemos el proceso de crear un cargador con &lt;em&gt;Stop the Express&lt;/em&gt;. Tras encender el Spectrum, y colocar la cinta en el reproductor de cassette, tecleamos &lt;code&gt;merge ""&lt;/code&gt; y pulsamos PLAY. Bueno, esto es la idea, a partir de ahora vamos a manejarnos con un &lt;a href="https://www.rastersoft.com/programas/fbzx.html" rel="noopener noreferrer"&gt;emulador de Spectrum, llamado FBZX&lt;/a&gt;. Precisamente, nos permitirá emular insertar una cinta, ponerla en marcha, etc.&lt;/p&gt;

&lt;p&gt;Así, pulsamos F3 y 1 para indicar que queremos cargar una cinta, el .tap o .tzx de &lt;strong&gt;Stop the Express&lt;/strong&gt; que nos hayamos descargado de &lt;strong&gt;World of Spectrum&lt;/strong&gt;. Teclamos &lt;code&gt;merge""&lt;/code&gt; como se ve en la imagen anterior. Es importante que nos fijemos en que hemos desactivado la carga rápida y la carga turbo.&lt;/p&gt;

&lt;p&gt;Ahora, de vuelta en la pantalla de Spectrum, pulsamos ENTER para cargar la cinta, y pulsamos F6 para ponerla en marcha (virtualmente). Una vez que aparece &lt;code&gt;Ok 0:1&lt;/code&gt;, pulsamos F5 para parar la cinta. Volvemos a pulsar ENTER para ver el código en pantalla.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1aporz8c1ahsldyn2ezy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1aporz8c1ahsldyn2ezy.png" alt="MERGE "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Introducimos 20 y ENTER y en la línea 50 eliminamos los colores, de manera que solo nos quede la línea 20, que es la que carga la pantalla de presentación (&lt;code&gt;load "" screen$&lt;/code&gt;), el código máquina del juego (&lt;code&gt;load "" code&lt;/code&gt;), y la ejecución del mismo &lt;code&gt;randomize usr 48096&lt;/code&gt;. Este último lo vamos a modificar poniendo &lt;code&gt;REM&lt;/code&gt; delante, lo que lo transforma en un comentario.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fuflu759stg4p21n3ex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fuflu759stg4p21n3ex.png" alt="El cargador de Stop the Express"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;50 load "StopExpr2" screen$: load "StopExpr3" code: rem randomize usr 48096
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf1vlj6zzrcgl6cb0zz7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf1vlj6zzrcgl6cb0zz7.png" alt="El cargador de Stop the Express modificado"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esta última instrucción es interesante. Ahora le hemos puesto &lt;code&gt;rem&lt;/code&gt; delante, con lo que la hemos transformado en un comentario y no se va a ejecutar. La pregunta ahora es: ¿cómo es que esta instrucción ejecuta el juego? La parte importante es &lt;code&gt;USR 48096&lt;/code&gt;. Lo que sucede es que es una función, no una instrucción. Necesita una instrucción a la cual va a ser pasada por parámetro. ¿Cuál instrucción exactamente? Realmente no importa demasiado, solo la necesitamos para que evalúe sus argumentos. Concretamente, se usa &lt;code&gt;RANDOMIZE&lt;/code&gt;, que inicializa la semilla aleatoria que alimenta a la función &lt;code&gt;RND&lt;/code&gt;, que devuelve un valor aleatorio entre 0 y 1. Así, una vez que &lt;code&gt;RANDOMIZE&lt;/code&gt; evalúe su parámetro, podrá inicializar la semilla aleatoria. Lo que pasa es que nunca se producirá un retorno de la función que llama al código máquina del juego, claro...&lt;/p&gt;

&lt;p&gt;La documentación del ZX Spectrum nos dice que cuando ejecutamos un &lt;code&gt;load "" code&lt;/code&gt;, en realidad estamos haciendo un &lt;code&gt;load "" code 32768&lt;/code&gt;. Estamos cargando el código del juego a partir de la dirección de memoria 32768. Si tenemos en cuenta que el código tiene un tamaño de 15394 bytes, entonces sabemos que ocupará desde la dirección en memoria 32768 hasta la dirección 48162, inclusive. El resto de la memoria, desde la dirección en memoria 48163 hasta 64k (65536), queda libre.&lt;/p&gt;

&lt;p&gt;Tener parte de la memoria libre es importante porque necesitamos espacio para poder cargar un desensamblador, sin "pisar" el programa, es decir, sin utilizar la memoria que está siendo ocupada por el programa. El desensamblador nos va a decir las instrucciones que están en memoria, sin necesidad de que interpretemos los números en ella directamente.&lt;/p&gt;

&lt;p&gt;Hasta ahora hemos utilizado emulador el mejor Spectrum posible, el creado por Investrónica en 1986, con características mejoradas como el chip de sonido de tres canales, o la memoria de 128k. Se trata del &lt;a href="https://dev.to/baltasarq/el-zx-spectrum-128k-de-investronica-332k"&gt;&lt;strong&gt;Sinclair Spectrum + 128k&lt;/strong&gt;&lt;/a&gt;. Pero &lt;em&gt;Stop the express&lt;/em&gt; necesita un modelo de 48k, el modelo anterior, así que por si acaso, pasaremos a ese modo con la instrucción &lt;code&gt;SPECTRUM&lt;/code&gt;. Si ahora pulsamos la tecla &lt;code&gt;K&lt;/code&gt;, veremos que aparece la instrucción &lt;code&gt;LIST&lt;/code&gt; en pantalla. Pulsamos ENTER y veremos de nuevo el listado.&lt;/p&gt;

&lt;p&gt;Esta forma de manejarse con el teclado es típica del ZX Spectrum original, el de 48k. Se concibió como una manera de ahorrar memoria, y también de ayudar a los usuarios a teclear programas en BASIC. Hay muchos detractores de esta forma de operación, así como fervientes seguidores de la misma.&lt;/p&gt;

&lt;p&gt;Ahora pulsamos &lt;code&gt;R&lt;/code&gt; (aparece &lt;code&gt;RUN&lt;/code&gt;en pantalla) y pulsamos ENTER. Pulsamos F6 para volver a poner la cinta en marcha. El programa cargará la pantalla de presentación, y después el bloque de código máquina del juego en sí.&lt;/p&gt;

&lt;p&gt;Cuando termine, veremos en la parte inferior de la pantalla &lt;code&gt;Ok 50:2&lt;/code&gt;. Aparentemente, no ha pasado nada, pero tenemos el juego en memoria. Si pulsamos &lt;code&gt;V&lt;/code&gt; (aparece &lt;code&gt;CLS&lt;/code&gt;), y ENTER, y &lt;code&gt;K&lt;/code&gt; (aparece &lt;code&gt;LIST&lt;/code&gt;), y ENTER, veremos que seguimos teniendo el cargador en memoria.&lt;/p&gt;

&lt;p&gt;Ahora es necesario cargar el desensamblador que mencionamos. Vamos a utilizar &lt;a href="https://worldofspectrum.net/item/0008091/" rel="noopener noreferrer"&gt;HiSoft MONS&lt;/a&gt;. El primer archivo, &lt;code&gt;HiSoftDevpacV3M2Mons.tap.zip&lt;/code&gt; ya nos vale. Lo descomprimimos, por ejemplo en el mismo directorio de descargas, con lo que nos quedamos con &lt;code&gt;MONS321.tap&lt;/code&gt;. Esta &lt;em&gt;cinta&lt;/em&gt;, es decir, este archivo &lt;em&gt;.tap&lt;/em&gt;, solo tiene un programa, que es el propio desensamblador, que cargaremos con &lt;code&gt;load "" code 52000&lt;/code&gt;. Volvemos a FBZX, pulsamos F3 y 1 para seleccionar &lt;code&gt;MONS321.tap&lt;/code&gt;, y ESC para volver a la emulación. Pulsamos &lt;code&gt;J&lt;/code&gt; (aparece &lt;code&gt;LOAD&lt;/code&gt;), pulsamos Ctrl + P dos veces para obtener dos dobles comillas, y a continuación pulsamos Ctrl + Shift, y soltamos (el cursor cambia para mostrar una &lt;code&gt;E&lt;/code&gt; parpadeante), y entonces pulsamos la tecla &lt;code&gt;I&lt;/code&gt; (aparece &lt;code&gt;CODE&lt;/code&gt; en pantalla). Finalmente, tecleamos 52000, para obtener &lt;code&gt;load "" code 52000&lt;/code&gt;. Pulsamos ENTER para pasar al modo de carga, y F6 para comenzar la reproducción de la cinta. En pantalla aparecerá &lt;code&gt;BYTES: MONS3M2&lt;/code&gt;, y realizará la carga correspondiente, hasta mostrar &lt;code&gt;Ok 0:1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El proceso de carga del juego para su desensamblado, en realidad suele hacerse desde el mismo MONS, pero para no entrar en excesivas tecnicidades, y explorar también al propio Spectrum 48k, al final he decidido hacerlo así.&lt;/p&gt;

&lt;p&gt;Para ejecutar el desenamblador, tecleamos &lt;code&gt;T&lt;/code&gt;(aparece &lt;code&gt;RANDOMIZE&lt;/code&gt;), Ctrl + Shift (el cursor cambia a una &lt;code&gt;E&lt;/code&gt; parpadeante), y &lt;code&gt;L&lt;/code&gt; (aparece &lt;code&gt;USR&lt;/code&gt;). Tecleamos a continuación 52000, para obtener &lt;code&gt;RANDOMIZE USR 52000&lt;/code&gt;. Pulsamos ENTER.&lt;/p&gt;

&lt;p&gt;Veremos brevemente un mensaje de bienvenida de MONS3, y después una pantalla con el contenido de los registros del Z80, el contenido de una zona de la memoria en &lt;a href="https://es.wikipedia.org/wiki/Sistema_hexadecimal" rel="noopener noreferrer"&gt;hexadecimal&lt;/a&gt;, y un cursor parpadeante en la zona inferior de la pantalla.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7vwcmfx6df8njoizxda.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7vwcmfx6df8njoizxda.png" alt="Mons3 ejecutándose en el Speccy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como yo no soy un experto en ensamblador del Z80, me dirijo a los &lt;em&gt;pokes&lt;/em&gt; disponibles, que son los siguientes para vidas infinitas y tiempo infinito. A continuación aparecen las direcciones en memoria a cambiar, el valor en hexadecimal del nuevo valor a poner en memoria, y su opcode correspondiente en el Z80.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dirección en memoria&lt;/th&gt;
&lt;th&gt;Valor&lt;/th&gt;
&lt;th&gt;Significado&lt;/th&gt;
&lt;th&gt;Hex&lt;/th&gt;
&lt;th&gt;Opcode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;34464&lt;/td&gt;
&lt;td&gt;183&lt;/td&gt;
&lt;td&gt;Vidas infinitas&lt;/td&gt;
&lt;td&gt;B7&lt;/td&gt;
&lt;td&gt;OR A, A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;34926&lt;/td&gt;
&lt;td&gt;183&lt;/td&gt;
&lt;td&gt;Vidas infinitas&lt;/td&gt;
&lt;td&gt;B7&lt;/td&gt;
&lt;td&gt;OR A, A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;35257&lt;/td&gt;
&lt;td&gt;183&lt;/td&gt;
&lt;td&gt;Vidas infinitas&lt;/td&gt;
&lt;td&gt;B7&lt;/td&gt;
&lt;td&gt;OR A, A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;35780&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Tiempo infinito&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;NOP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;39549&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Tiempo infinito&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;NOP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;En &lt;strong&gt;Mons3&lt;/strong&gt;, si pulsamos la combinación de teclas &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;1&lt;/code&gt;, volvemos a BASIC. Para volver a entrar en &lt;strong&gt;Mons3&lt;/strong&gt;, necesitaremos volver a teclear &lt;code&gt;randomize usr 52000&lt;/code&gt;, es decir, &lt;code&gt;T&lt;/code&gt;, &lt;code&gt;Ctrl&lt;/code&gt;+ &lt;code&gt;Shift&lt;/code&gt;, &lt;code&gt;L&lt;/code&gt;, 52000 y ENTER.&lt;/p&gt;

&lt;p&gt;Con &lt;code&gt;Ctrl&lt;/code&gt;+ &lt;code&gt;3&lt;/code&gt;, desensamblamos el programa empezando en la dirección de memoria por defecto, que al principio es 0, es decir, estaríamos desensamblando la &lt;strong&gt;ROM&lt;/strong&gt; del &lt;strong&gt;Speccy&lt;/strong&gt;, la que contiene el intérprete de BASIC, etc.&lt;/p&gt;

&lt;p&gt;Con &lt;code&gt;H&lt;/code&gt;, y un número decimal, obtenemos su valor hexadecimal equivalente. Por ejemplo, &lt;code&gt;H&lt;/code&gt; y 52000 nos devuelve CB20, que es la posición en memoria de Mons3. Si convertimos 34464, la dirección del primer &lt;code&gt;POKE&lt;/code&gt;, nos devuelve 86A0.&lt;/p&gt;

&lt;p&gt;Con 'M', y un valor en memoria hexadecimal, nos pasamos a esa dirección en memoria. En lugar de utilizar directamente 86A0, utilizaremos 869B, así, con &lt;code&gt;M', 869B y&lt;/code&gt;Ctrl`+ 3, obtendremos un listado como el siguiente:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;plaintext&lt;br&gt;
869V 1102A7 LD DE, #A702&lt;br&gt;
869E     96 SUB (HL)&lt;br&gt;
869F     5F LD E, A&lt;br&gt;
86A0     9D SBC A, L            ; este es el valor a cambiar&lt;br&gt;
86A1     93 SUB E&lt;br&gt;
86A2     AA XOR D&lt;br&gt;
96A3     ...&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;En la primera columna aparece la dirección en memoria en hexadecimal. A continuación, los valores en hexadecimal para la instrucción. Hay que tener en cuenta que hay instrucciones que ocupan varios bytes. Por ejemplo, la primera en 869V es 1102A7. El valor 11 es el de la instrucción LD, concretamente LD DE, cargar en el registro DE el valor A702, que como vemos aparece como 02A7, ya que el Z80 codifica los valores como LSB (&lt;em&gt;Least Significan Byte&lt;/em&gt;), es decir, coloca primero el byte menos significativo de un valor en 16 bits. El registro DE es el formado por el par de registros de 8 bits D y E, para conformar un registro de 16 bits. En cambio, en la dirección 86A0 tenemos 9D, una instrucción que ocupa un solo byte y que significa que se debe restar el contenido del registro L + el bit de acarreo, del contenido del registro A. El resultado se guarda en A.&lt;/p&gt;

&lt;p&gt;Si en esta posición ponemos en cambio el byte B7, entonces estaremos haciendo un OR del valor del registro A con el valor del registro A. La operación OR comprueba un valor en binario con otro, y pone a 1 aquellos pares de valores que contengan 0 y 1, o 1 y 1. Por ejemplo, si tomamos un valor en binario como 0110, que es 6 en binario, con 1100, que es 12, obtendremos 1110, que es 14. Sí, ¡se puede utilizar para sumar! ¿Pero, qué pasa si hacemos un OR de un valor consigo mismo? Pues nada. El valor se queda como estaba. Y eso es lo que quiere conseguir el &lt;strong&gt;POKE&lt;/strong&gt;: eliminar la resta para que no se reste una vida. Pero, a la vez, deja el registro A y el acarreo como tiene que estar para poder continuar la ejecución sin que esta se vea afectada.&lt;/p&gt;

&lt;p&gt;De acuerdo. La dirección en memoria 36780 (8FAC), contiene una instrucción que debemos poner a 0 para que el tiempo sea infinito. El opcode 0 es NOP, es decir, no hacer nada. Si nos fijamos, en esa posición hay otro SBC, otra resta teniendo en cuenta el acarreo. Si la ponemos a 0, simplemente no se hace. En este caso, no es necesario dejar el registro A y el acarreo de ninguna manera especial para que la ejecución continúe correctamente.&lt;/p&gt;

&lt;p&gt;Y bueno, este es el proceso que seguiría un &lt;em&gt;hacker&lt;/em&gt; de 8 bits para encontrar los &lt;strong&gt;POKE&lt;/strong&gt;s del juego. Buscaríamos por ejemplo el valor 3, descartando todos los valores hasta encontrar el número de vidas inicial en una dirección de memoria concreta. Después buscar restas de esa posición en memoria, buscando por el opcode SUB o SBC hasta encontrar la instrucción que resta la vida, y encontrar el valor adecuado que consigue que se haga la resta mientras a la vez consigue que continúe la ejecución sin errores. Y cada error, supone cargar el &lt;strong&gt;Mons3&lt;/strong&gt; desde cinta, y a continuación el juego desde cinta. Tiene mérito, ¿eh?&lt;/p&gt;

&lt;p&gt;Y ahora es necesario crear el cargador del juego. Es decir, la parte BASIC que carga el juego. Nos habíamos quedado con esto:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bbcbasic&lt;br&gt;
20 load "StopExpr2" screen$: load "StopExpr3" code: rem randomize usr 48096&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Vamos a pasarlo a lo siguiente. Tenemos que cambiar los valores después de cargar el juego, y antes de ejecutarlo. Podemos hacerlo como aparece a continuación, creando el archivo &lt;code&gt;cargador.bas&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bbcbasic&lt;br&gt;
10 load "StopExpr2" screen$&lt;br&gt;
20 load "StopExpr3" code&lt;br&gt;
30 cls:print "Stop the Express cracked"&lt;br&gt;
40 input "Vidas infinitas (s/n):";v$&lt;br&gt;
50 if v$(1)&amp;lt;&amp;gt;"n" then poke 34464, 183:poke 34926, 183:poke 35257,183&lt;br&gt;
60 input "Tiempo infinito (s/n):";t$&lt;br&gt;
70 if t$(1)&amp;lt;&amp;gt;"n" then poke 35780, 0: poke 39549, 0&lt;br&gt;
100 randomize usr 48096&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fap4obwe305l6bg9ljgmh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fap4obwe305l6bg9ljgmh.png" alt="Cargador en BasinC"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nos podemos descargar &lt;a href="https://github.com/ref-xx/basinc" rel="noopener noreferrer"&gt;&lt;strong&gt;BasinC&lt;/strong&gt;&lt;/a&gt;, y ejecutarlo (en linux, necesitaremos &lt;a href="https://www.winehq.org/" rel="noopener noreferrer"&gt;Wine&lt;/a&gt;). Cargamos el archivo &lt;code&gt;cargador.bas&lt;/code&gt; en BasinC, y seleccionamos &lt;strong&gt;File&lt;/strong&gt; &amp;gt;&amp;gt; &lt;strong&gt;Export as tap&lt;/strong&gt;, guardándolo como &lt;code&gt;cargador.tap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofy7bw9nlmk5etflqv72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofy7bw9nlmk5etflqv72.png" alt="Cargador ya en el Speccy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ya solo queda volver &lt;strong&gt;FBZX&lt;/strong&gt;, y pulsar F3 para seleccionar una cinta, escoger &lt;code&gt;cargador.tap&lt;/code&gt;, pulsar ESC e introducir &lt;code&gt;SPECTRUM&lt;/code&gt;, y después pulsar &lt;code&gt;J&lt;/code&gt;, &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;P&lt;/code&gt; dos veces y ENTER para ejecutar &lt;code&gt;load ""&lt;/code&gt;, pulsando entonces F6. Al terminar la carga, pulsamos &lt;code&gt;R&lt;/code&gt; y ENTER para ejecutar el programa. Seleccionamos la cinta del juego original con F3 y 1, y al pulsar ESC y F6, el juego se cargará saltándose el BASIC original, y preguntándonos si queremos vidas y tiempo infinito. Al terminar las preguntas, el juego se ejecutará modificado.&lt;/p&gt;

&lt;p&gt;Enhorabuena, ¡eres un &lt;strong&gt;hacker&lt;/strong&gt;!&lt;/p&gt;

</description>
      <category>sinclair</category>
      <category>spanish</category>
      <category>hack</category>
      <category>games</category>
    </item>
    <item>
      <title>Retro-imprimiendo (y II)</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Tue, 03 Mar 2026 12:11:16 +0000</pubDate>
      <link>https://dev.to/baltasarq/retro-imprimiendo-y-ii-l9</link>
      <guid>https://dev.to/baltasarq/retro-imprimiendo-y-ii-l9</guid>
      <description>&lt;p&gt;En la década de los 80 y 90 del siglo pasado (el siglo XX), era muy típico imprimir utilizando interfaces de tipo paralelo, o serie. En aquella época, el estándar &lt;a href="https://es.wikipedia.org/wiki/Universal_Serial_Bus" rel="noopener noreferrer"&gt;USB&lt;/a&gt; no existía, y, en cualquier caso, la impresión era muy, muy distinta a como es hoy en día, que básicamente se basa en imprimir una imagen, incluso cuando lo que se está imprimiendo es texto puro.&lt;/p&gt;

&lt;p&gt;Pero no nos desviemos. Las impresoras de aquella época imprimían en verdadero modo texto. Es decir, les mandabas un texto, y los caracteres (no sus mapas de bits), viajaban por el cable entre el ordenador y la impresora, imprimiéndose directamente. Lo que controlaba el aspecto del texto (lo que hoy conocemos como &lt;em&gt;font&lt;/em&gt;, y traducimos como fuente), eran unos &lt;em&gt;dips&lt;/em&gt; o palanquitas de configuración de la impresora. Así, y según lo completa que fuera la impresora, podrías elegir entre &lt;em&gt;Times New Roman&lt;/em&gt; o &lt;em&gt;Helvetia&lt;/em&gt;, por poner un ejemplo. Si es que existían en aquella época, claro. También se utilizaban para establecer la página de códigos para el idioma utilizado, como por ejemplo Latin-1 para Español.&lt;/p&gt;

&lt;p&gt;Una vez que nos poníamos a imprimir, el texto podía controlarse mediante códigos de impresión. Algunos eran estándar ASCII, pero había otros más elaborados que veremos a continuación.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Código&lt;/th&gt;
&lt;th&gt;Significado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;BS - Back Space, borrado hacia atrás&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;HT - Horizontal Tab, tabulador&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;LF - Line Feed, salto de línea&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;FF - Form Feed, salto de página&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;CR - Carriage return, retorno de carro&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Como comentábamos en la anterior entrega, realmente en estas impresoras (de ellas las más conocidas eran las matriciales), tenían un carro que era el que se movía para imprimir por la página, de ahí la diferencia entre CR y LF.&lt;/p&gt;

&lt;p&gt;También como vimos, podemos imprimir directamente con &lt;a href="https://github.com/Baltasarq/print/" rel="noopener noreferrer"&gt;&lt;code&gt;print.py&lt;/code&gt;&lt;/a&gt; desde línea de comando con:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python print.py &lt;span class="nt"&gt;--send&lt;/span&gt; &lt;span class="s2"&gt;"¡Hola, mundo!^v"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El código &lt;code&gt;^v&lt;/code&gt; es entendido por el programa como el carácter número 12, por lo que se imprimirá el mensaje de saludo, y después saldrá la página de la impresora. Esto código 12 al principio era innecesario, pues el usuario podía manipular directamente el rodillo de alimentación de papel (sí, se parecía mucho a una máquina de escribir). Pero se fue haciendo particularmente útil con las impresoras modernas, que tienen un &lt;em&gt;buffer&lt;/em&gt; de impresión que, si no se llena (y tampoco se alcanza el final de página), aparentemente no pasa nada, de manera frustrante.&lt;/p&gt;

&lt;p&gt;Pero la impresora manejaba más que estos códigos, y seguía haciéndolo utilizando la manera estándar que proporcionan los códigos ASCII por debajo de 32: utilizando el código 27. Efectivamente, también es el código de la tecla de escape. La idea es que, anteponiendo ESC a la secuencia de códigos, se pueden definir las secuencias de código de control que se desee. El fabricante EPSON creó las secuencias de códigos de control de impresión &lt;a href="https://en.wikipedia.org/wiki/ESC/P" rel="noopener noreferrer"&gt;ESC/P&lt;/a&gt;, es decir, &lt;em&gt;Epson Standard Code for Printers&lt;/em&gt;, que se hicieron muy, muy populares. Por supuesto, tenía que haber otro estándar (estándares &lt;em&gt;de facto&lt;/em&gt;, claro), apareciendo la competencia: las secuencias de &lt;a href="https://en.wikipedia.org/wiki/IBM_Machine_Code_Printer_Control_Characters" rel="noopener noreferrer"&gt;códigos de control de impresión de IBM&lt;/a&gt;. Estos códigos de control estaban sobre todo dedicados a las impresoras de los grandes ordenadores o &lt;em&gt;mainframes&lt;/em&gt;, siendo ESC/P el estándar más popular para el IBM PC y compatibles.&lt;/p&gt;

&lt;p&gt;El sistema de secuencias de control ESC/P se configuraba a partir del código ESC. En el programa anterior &lt;code&gt;print.py&lt;/code&gt;, ESC se representa como &lt;code&gt;^]&lt;/code&gt;, algo muy habitual en la época. Así, a continuación podemos ver una tabla con los códigos más habituales.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Código&lt;/th&gt;
&lt;th&gt;Enviar&lt;/th&gt;
&lt;th&gt;Significado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ESC E&lt;/td&gt;
&lt;td&gt;^]E&lt;/td&gt;
&lt;td&gt;Comienzo del texto en negrita.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC F&lt;/td&gt;
&lt;td&gt;^]F&lt;/td&gt;
&lt;td&gt;Fin del texto en negrita.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC 4&lt;/td&gt;
&lt;td&gt;^]4&lt;/td&gt;
&lt;td&gt;Comienzo del texto en itálica.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC 5&lt;/td&gt;
&lt;td&gt;^]5&lt;/td&gt;
&lt;td&gt;Fin del texto en itálica.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC -&lt;/td&gt;
&lt;td&gt;^]-&lt;/td&gt;
&lt;td&gt;Comienzo o fin de subrayado.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC W 0&lt;/td&gt;
&lt;td&gt;^]W0&lt;/td&gt;
&lt;td&gt;Comienzo de caracteres de doble ancho.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC W 1&lt;/td&gt;
&lt;td&gt;^]W1&lt;/td&gt;
&lt;td&gt;Fin de caracteres de doble ancho.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC SI&lt;/td&gt;
&lt;td&gt;^]SI&lt;/td&gt;
&lt;td&gt;Comienzo de caracteres comprimidos.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DC2&lt;/td&gt;
&lt;td&gt;^DC2&lt;/td&gt;
&lt;td&gt;Fin de los caracteres comprimidos.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Efectivamente, podíamos especificar caracteres con el doble de ancho (permitiendo hasta 40 caracteres por línea), o caracteres comprimidos (alcanzando las 120 columnas, un modo muy popular para informes).&lt;/p&gt;

&lt;p&gt;Así que, si ejecutamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python print.py &lt;span class="nt"&gt;--send&lt;/span&gt; &lt;span class="s2"&gt;"¡Hola, ^]EMundo^]F!^V"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿Obtendremos en el papel: "¡Hola, &lt;strong&gt;mundo&lt;/strong&gt;!"?&lt;/p&gt;

&lt;p&gt;Por desgracia, no. Las impresoras modernas han eliminado de sus &lt;em&gt;firmwares&lt;/em&gt; el soporte para ESC/P. En su mayoría, las impresoras que lo soportan hoy en día son impresoras de tickets. Las impresoras modernas "normales", a veces lo soportan configurándolas previamente como en modo de línea o modo texto. También hay que recordar que las impresoras láser nacieron soportando PostScript, por lo que esos modelos nunca han tenido la necesidad de soportar ESC/P.&lt;/p&gt;

&lt;p&gt;Así que, si quieres practicar retro-impresión, solo puedes hacerlo adquiriendo una impresora de tickets que indique que es compatible con ESC/POS (la variante moderna de ESC/P, especializada en POS, &lt;em&gt;Point Of Sale&lt;/em&gt; o punto de venta). ESC/POS tiene muchos códigos nuevos como abrir el monedero, por ejemplo, pero los básicos de la tabla anterior siguen siendo soportados.&lt;/p&gt;

&lt;p&gt;La mejor forma es adquirir una impresora matricial propiamente. Puede ser una impresora &lt;strong&gt;retro&lt;/strong&gt; de los 80 o 90, adquirida a través de  aplicaciones especializadas en productos de segunda mano como &lt;strong&gt;eBay&lt;/strong&gt; o &lt;strong&gt;Wallapop&lt;/strong&gt;. Pero todavía las hay modernas, tanto de &lt;em&gt;tickets&lt;/em&gt; como de tamaño folio (DIN A4). Por ejemplo, en el momento de escribir este texto, la &lt;a href="https://www.epson.es/es_ES/productos/impresoras/dot-matrix/epson-lx-350/p/11848" rel="noopener noreferrer"&gt;Epson LX-350&lt;/a&gt;, o la &lt;a href="https://www.oki.com/es/printing/support/user-manual/dotmatrix/01308201/" rel="noopener noreferrer"&gt;OKI 3320ECO&lt;/a&gt; son de tamaño folio y soportan ESC/P.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>printing</category>
      <category>python</category>
      <category>retro</category>
    </item>
    <item>
      <title>IA: una historia real</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Thu, 26 Feb 2026 15:52:26 +0000</pubDate>
      <link>https://dev.to/baltasarq/ia-una-historia-real-1n19</link>
      <guid>https://dev.to/baltasarq/ia-una-historia-real-1n19</guid>
      <description>&lt;p&gt;La IA generativa ha estado constantemente (y errónameante), &lt;em&gt;entronada&lt;/em&gt; como la sustituta de los programadores. Ya he publicado algún comentario en este medio sobre las experiencias (casi siempre, decepcionantes) que he tenido con la IA (&lt;a href="https://dev.to/baltasarq/que-nos-ensena-el-fiasco-de-replit-4gbe"&gt;1&lt;/a&gt; &lt;a href="https://dev.to/baltasarq/breve-repaso-a-la-investigacion-en-inteligencia-artificial-2h36"&gt;2&lt;/a&gt; &lt;a href="https://dev.to/baltasarq/escapando-de-intellij-1804"&gt;3&lt;/a&gt; &lt;a href="https://dev.to/baltasarq/las-sugerencias-de-codigo-consideradas-daninas-3hn3"&gt;4&lt;/a&gt;). Esto no quiere decir que la IA no sirva: es una herramienta más, como trataré de describir aquí.&lt;/p&gt;

&lt;p&gt;Hace algunos días, estaba trabajando con &lt;strong&gt;Java&lt;/strong&gt;, su &lt;em&gt;toolkit&lt;/em&gt; gráfico &lt;strong&gt;Swing&lt;/strong&gt;, que estaba utilizando para mostrar el contenido de &lt;a href="https://github.com/Baltasarq/NottakApp/tree/main" rel="noopener noreferrer"&gt;notas creadas por el usuario&lt;/a&gt;. Una de las posibilidades contempladas es la de crear cajas de verificiación como listas de tareas. Por ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] - Comprar pan.
[X] - Crear el programa para la mañana.
[ ] - Reunión de las 11h.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estas cajas en &lt;em&gt;Mark Down&lt;/em&gt; se interpretarían como HTML, concretamente como un &lt;strong&gt;check box&lt;/strong&gt;. El único componente que puede interpretar HTML es un &lt;a href="https://docs.oracle.com/javase/8/docs/api/javax/swing/JEditorPane.html" rel="noopener noreferrer"&gt;&lt;strong&gt;JEditorPane&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La forma de representar un &lt;em&gt;check box&lt;/em&gt; en HTML 5 es la siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="checkbox"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si el &lt;em&gt;check box&lt;/em&gt; está marcado, entonces aparecería con el atributo &lt;code&gt;checked&lt;/code&gt;. Este atributo no se asigna a ningún valor, sino que su mera existencia indica el marcado o no (algo que, por cierto, no me gusta nada... ¿era demasiado tener un atributo como &lt;code&gt;cheched="1"&lt;/code&gt; o similar?).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="checkbox" checked&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pues nada, hago mis pruebas, las notas con casillas se convierten a HTML con estos &lt;em&gt;check boxes&lt;/em&gt;, y después vuelven a guardarse como &lt;em&gt;MarkDown&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Pero entonces, me encuentro con algo sorprendente, un error extraño: daba igual si marcabas o no la casilla, &lt;strong&gt;nunca&lt;/strong&gt; se generaba el atributo &lt;code&gt;checked&lt;/code&gt;... ¿qué estaba pasando?&lt;/p&gt;

&lt;p&gt;Las búsquedas mediante los buscadores habituales enseguida devolvían respuestas relacionadas con &lt;em&gt;JavaScript&lt;/em&gt;, lo que no era demasiado útil. Decidí irme a la IA. Elegí &lt;a href="http://deepseek.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Deep Seek&lt;/strong&gt;&lt;/a&gt;. Sobre todo, porque me permite usarlo de manera gratuita, más que nada.&lt;/p&gt;

&lt;p&gt;Le pregunté a la IA la razón de por qué &lt;em&gt;me pasaba lo que me pasaba&lt;/em&gt;, y... sí, me entendió a la primera. Es decir, no tuve que refinar mi pregunta descartando posibles problemas y soluciones orientadas al navegador con JavaScript. Esto es un buen punto para la IA.&lt;/p&gt;

&lt;p&gt;Su respuesta me sorprendió: &lt;code&gt;This is a known issue with HTMLEditorKit - when you call getText(), it serializes the current document state and resets all input values to their default values (as defined in the HTML).&lt;/code&gt; Traducido, este es un problema conocido en &lt;strong&gt;JEditorPane&lt;/strong&gt; empleando un &lt;strong&gt;HTMLEditorKit&lt;/strong&gt;, o sea, trabajando con HTML. El problema es que los señores de &lt;strong&gt;Sun Microsystems&lt;/strong&gt; decidieron no "conectar" los valores de entrada de este tipo de campos &lt;code&gt;input&lt;/code&gt;, según parece, debido a que &lt;strong&gt;JEditorPane&lt;/strong&gt; no es un navegador. De acuerdo, pero entonces... ¿por qué los &lt;code&gt;input&lt;/code&gt; de tipo &lt;code&gt;text&lt;/code&gt; sí se respetan, de modo que los valores de entrada sí se reflejan en el DOM HTML del editor? Mi personal interpretación es que se cansaron a mitad de trabajo, probablemente pensando algo así como: "total, esto lo no lo va a usar nadie..."&lt;/p&gt;

&lt;p&gt;Bueno, el caso. La cuestión es que me da varias soluciones. Una de ellas es captar, (1) mediante un código en &lt;strong&gt;JavaScript&lt;/strong&gt; los valores de las &lt;em&gt;check boxes&lt;/em&gt; y meterlas en los elementos del DOM HTML del editor. Otra es (2) crear una versión propia de &lt;strong&gt;HTMLEditorKit&lt;/strong&gt; quer genere el código correctamente, y otra es (3) tomar el atributo &lt;code&gt;checked&lt;/code&gt;del DOM HTML del editor y almacenarlo en una estructura de datos.&lt;/p&gt;

&lt;p&gt;Hay varios problemas con estas soluciones. La (1), utilizando &lt;strong&gt;JavaScript&lt;/strong&gt; es excesiva, en mi opinión. Tras examinar la (2), resulta que o bien no existe una manera elegante de recorrer los nodos, o bien la IA no la conoce y no tengo tiempo de investigarlo, y  en contraste, la tercera es la que parece más interesante. Así que me la leo, la entiendo, elimino todo el código redundante, y la incorporo a mi código. Pero no funciona.&lt;/p&gt;

&lt;p&gt;Y es que, en realidad, ninguna de las soluciones funcionan, porque todas tienen que ver con el HTML DOM que mantiene el editor. Y tiene todo el sentido, porque si volvemos a leer el origen del problema, la cuestión es que la parte visual no está conectada con el DOM HTML. Así, podemos "trastear" con el HTML DOM lo que queramos. Nos pongamos como nos pongamos,no tendremos los &lt;code&gt;checked&lt;/code&gt; aunque los &lt;em&gt;check boxes&lt;/em&gt; están marcados.&lt;/p&gt;

&lt;p&gt;Para mi, esto supone un problema con la IA. Me ha propuesto varias soluciones que seguramente fueron ensayadas por alguien, pero que fueron solo meros intentos, pues no solucionan el problema. Además, no le molesta proponer una solución basada en ejecutar &lt;strong&gt;JavaScript&lt;/strong&gt; dentro del editor, lo que me parece especialmente subóptimo. Por último, es necesario "pulir" la respuesta: hay mucho código redundante, que no aporta nada a la solución.&lt;/p&gt;

&lt;p&gt;El caso es que le respondo a la IA que la solución propuesta no es válida. Su respuesta es:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You're right to be skeptical! This is actually a known limitation of HTMLEditorKit - checkbox states are not stored in the document attributes the way we might expect. The checked state is maintained in the visual representation/View, but not in the underlying Document model's attributes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Es decir, que al no estar conectada la parte visual del HTML DOM, no tiene sentido manejar el DOM.&lt;/p&gt;

&lt;p&gt;No puedo evitar pegar un respingo cuando la leo. No tiene sentido que me propongas las soluciones anteriores "sabiendo" esto. De hecho, debería haberme dado cuenta, pero he confiado en que la IA me propondría soluciones válidas.&lt;/p&gt;

&lt;p&gt;Las soluciones propuestas son (1) tomar las marcas directamente de la vista del documento (no del HTML DOM), o (2) usar el &lt;strong&gt;ElementIterator&lt;/strong&gt; de &lt;strong&gt;HTMLDocument&lt;/strong&gt; . La segunda solución tiene un código kilométrico, y visto lo visto, no me fio de adoptarlo sin más. Además, lo que hace básicamente es crear un &lt;em&gt;listener&lt;/em&gt; que, en caso de marcar un &lt;em&gt;check box&lt;/em&gt;, pasa un booleano a una estructura de datos aparte... esta estructura de datos es la misma que utiliza la primera solución, mucho más corta, así que me centro en esta.&lt;/p&gt;

&lt;p&gt;Leo el código. Básicamente, lo que hace es recorrer los "nodos" de la vista, y busca objetos &lt;strong&gt;JChecbBox&lt;/strong&gt;, asociados a un objeto &lt;strong&gt;ParagraphView&lt;/strong&gt;, clase derivada de &lt;strong&gt;ComponentView&lt;/strong&gt; (que se corresponde con un elemento de HTML DOM &lt;code&gt;&amp;lt;input type="checbox"&amp;gt;&lt;/code&gt;). Cuando se encuentra uno, accede a su marca. El algoritmo es el siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;traverseViewForCheckboxes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;states&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="n"&gt;javax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;swing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ParagraphView&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Check if this view contains a checkbox&lt;/span&gt;
            &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;findComponentInView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;JCheckBox&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;JCheckBox&lt;/span&gt; &lt;span class="n"&gt;checkBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JCheckBox&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checkBox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;states&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;checkBox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isSelected&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Recursively traverse child views&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getViewCount&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;traverseViewForCheckboxes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;states&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3udtg0afjg1k015afy9x.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3udtg0afjg1k015afy9x.jpg" alt="La división entre el HTML DOM y la vista sigue el patrón Bridge." width="474" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La división entre el HTML DOM y la vista sigue el patrón &lt;strong&gt;Bridge&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Primero se busca en la vista los objetos &lt;strong&gt;ParagraphView&lt;/strong&gt;. Entonces se comprueba con su método &lt;code&gt;getComponent()&lt;/code&gt; si el componente visual equivalente es un &lt;strong&gt;JCheckBox&lt;/strong&gt;, accede a su marca. Y entonces me fijo en el método &lt;code&gt;findComponentInView( view )&lt;/code&gt;. Está justo debajo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="nf"&gt;findComponentInView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// This is a simplified approach - in reality, you might need to&lt;/span&gt;
        &lt;span class="c1"&gt;// access the ComponentView's component&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="n"&gt;javax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;swing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ComponentView&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;getComponentMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
                    &lt;span class="nc"&gt;ComponentView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"getComponent"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;getComponentMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAccessible&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;getComponentMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Reflection failed, try alternative approach&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¡Está utilizando reflexión para acceder al método &lt;code&gt;View::getComponent&lt;/code&gt;, y retornarlo. Me resulta realmente extraño este código. Supongo que será parte de algún código de prueba de alguien, pero... no tiene sentido. No tiene sentido porque &lt;code&gt;View::getElement&lt;/code&gt; es un método totalmente accesible.&lt;/p&gt;

&lt;p&gt;Dicho de otra forma, la llamada al método propuesto &lt;code&gt;findComponentInView( view )&lt;/code&gt;, especialmente subóptimo pues emplea reflexión...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;findComponentInView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se puede sustituir por una línea de código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getComponent&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cuando le señalo este extremo a la IA, reconoce que sí, que &lt;code&gt;View::getComponent()&lt;/code&gt;, se puede llamar directamente (?). No hay explicación, pero si no te das cuenta, pues te comes el código.&lt;/p&gt;

&lt;p&gt;Podemos resumir el proceso anterior en unos puntos fuertes y débiles de esta sesión con IA como sigue:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cuestión&lt;/th&gt;
&lt;th&gt;Punto fuerte de la IA&lt;/th&gt;
&lt;th&gt;Punto debil de la IA&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Búsqueda de problemas&lt;/td&gt;
&lt;td&gt;La IA encuentra el problema específico, mientras con un buscador necesitas mucho más esfuerzo.&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resolución de problemas&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;La IA puede generar soluciones que no son correctas.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;No le importa generar soluciones que suponen una elevada carga, al resultar extremadamente subóptima (ejecutar JavaScript).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Genera un código excesivo, que hay que pulir y sobre todo, recortar.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Al final, analizar las posibles soluciones propuestas, encuentras una que es prometedora, lo que evita de nuevo costosas y esforzadas búsquedas.&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;En general, crea código subóptimo; de nuevo, es necesaria una revisión detallada (llamada mediante reflexión).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Si leemos detalladamente este resumen, y damos un paso atrás, entendemos, efectivamente, cómo funciona la IA: proporciona texto con una alta probabilidad de aparecer junto al texto de entrada. Si tenemos esto último en cuenta, es obvio el por qué es necesario leer, entender, analizar, y pulir tanto las posibles soluciones como el código que proporciona. No hay otra.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>spanish</category>
      <category>java</category>
      <category>swing</category>
    </item>
    <item>
      <title>The Spanish ZX Spectrum + 128K by Investrónica</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Wed, 18 Feb 2026 17:23:05 +0000</pubDate>
      <link>https://dev.to/baltasarq/the-spanish-zx-spectrum-128k-by-investronica-1c7k</link>
      <guid>https://dev.to/baltasarq/the-spanish-zx-spectrum-128k-by-investronica-1c7k</guid>
      <description>&lt;p&gt;&lt;a href="https://www.zonadepruebas.com/viewtopic.php?t=1826" rel="noopener noreferrer"&gt;This post was previously published in Spanish, in ZonaDePruebas&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This computer was designed and released in 1985 by &lt;strong&gt;Investrónica&lt;/strong&gt;, a subsidiary company in the &lt;a href="http://www.elcorteingles.es" rel="noopener noreferrer"&gt;&lt;em&gt;El Corte Inglés&lt;/em&gt;&lt;/a&gt; group at the time, holding the distribtion rights for the Sinclair products in Spain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo311sg2grm420i85ofq7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo311sg2grm420i85ofq7.png" alt="Boot screen of Spanish ZX Spectrum 128k" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Due to the Spanish law, the engineers of &lt;strong&gt;Investrónica&lt;/strong&gt; couldn't release these Sinclair computers without support for the Spanish language. This especially included the 'ñ' character, as well as translated system messages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n7xio9txgi7sy5eq4p8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n7xio9txgi7sy5eq4p8.png" alt="Character set of the Spanish Spectrum 128k" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the experience gained after the development of the 128k, they would later release a Spanish ZX Spectrum +, translating all system messages and including support for the 'ñ' character as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Investrónica&lt;/strong&gt; always tried to convert, or at least show the Spectrum as a bussiness machine. Thus, this microcomputer came with a &lt;em&gt;keypad&lt;/em&gt; included (also known as &lt;em&gt;independent numeric keypad&lt;/em&gt;), which made program edition more comfortable, since it allowed advanced editing (word-by-word skipping, for instance).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5rimekw28l48qqx4kwt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5rimekw28l48qqx4kwt.png" alt="Main work screen of the Spanish Spectrum 128k" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This Spanish computer's final shape probably didn't convince the engineers at Sinclair UK, since they finally discarded the &lt;em&gt;keypad&lt;/em&gt;, removed the text editor, the BASIC editor advanced capabilities, but added screen menus. Those menus made the computer more pleasant at first glance, and a completely different aspect in contrast to the Spanish Spectrum 128k. A year later the English Spectrum + 128k was finally out, selling the &lt;em&gt;keypad&lt;/em&gt; separately, and completely diverging from the path opened by &lt;strong&gt;Investrónica&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm0f3wl8q6w9nilf4pg0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm0f3wl8q6w9nilf4pg0.png" alt="Boot screen of the English Spectrum 128k" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the pass of time, the Spanish 128k almost fell into oblivion, ditched as a rarity in a local (the Spanish), market. Especially in regard to its differences with the UK computer, its advanced possibilities became forgotten.&lt;/p&gt;

&lt;h2&gt;
  
  
  A text editor embedded in ROM
&lt;/h2&gt;

&lt;p&gt;The Spanish Spectrum 128k had an embedded text editor. In order to enter it, you only had to use the command &lt;code&gt;edit&lt;/code&gt;, followed by the name of a string variable. All the text typed inside the editor was stored inside that variable, which could handle many pages, almost up until filling the Speccy's memory. For instance, typing &lt;code&gt;edit e$&lt;/code&gt; from the main screen, you would enter in the text editor mode with the current contents of the &lt;code&gt;e$&lt;/code&gt; variable. All changes were stored inside it upon exit, of course.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd99lchfqcqxqgpr2e04v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd99lchfqcqxqgpr2e04v.png" alt="Entering in the text editor of the Spanish Spectrum 128k" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spanish Spectrum 128k memory
&lt;/h2&gt;

&lt;p&gt;The amount of available memory was around thirty-some kilobutes. Where was then that extra memory (up to 128k) to be found? It was only accessible using some special commands, such as &lt;code&gt;save ! ""&lt;/code&gt; and &lt;code&gt;load ! ""&lt;/code&gt;.  In order to list its contents, you could type &lt;code&gt;cat !&lt;/code&gt;. Thus, that extra RAM was made available as a &lt;a href="https://en.wikipedia.org/wiki/RAM_drive" rel="noopener noreferrer"&gt;RAM drive&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All this survived in the UK model, and it was indeed called RAM Disk, and identified as "m:". The extended commands using '!' would be removed, and drive selectors would be supported in file names, such as "a:', "b:" and "m:". You could save screens (&lt;code&gt;screen$&lt;/code&gt;), machine code (&lt;code&gt;code&lt;/code&gt;), and arrays (&lt;code&gt;data&lt;/code&gt;), as well as regular BASIC programs, that is.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REM storing in the RAM disk
save ! "pant.scr" screen$
save ! "gamestat" data pos
cat !
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The text editor capabilities
&lt;/h2&gt;

&lt;p&gt;The text editor included many functions present in other professional editors (such as &lt;strong&gt;Tasword&lt;/strong&gt;, for instance), though it was really lacking, so it could hardly could be called professional itself. It's true that this was more related to the Speccy's internals than anything else.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhgx8s98n3ojo146c334.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhgx8s98n3ojo146c334.png" alt="The text editor of the Spanish Spectrum 128k" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The text editor supported word wrapping, insertion and overwriting, and, using the &lt;em&gt;keypad&lt;/em&gt;, word skipping, text's home and end by line, and other cursor movements unknown in a Speccy.&lt;/p&gt;

&lt;p&gt;The limitations of the editor, were severe, though. In the first place, the output was of 32 columns, only as many as the Speccy was able to show. This made it possible to print the text correctly only in a &lt;strong&gt;ZX Printer&lt;/strong&gt;, using the command &lt;code&gt;lrpint e$&lt;/code&gt;. From the perspective that gives the pass of time, I think they should have tried to double the columns as &lt;strong&gt;Tasword&lt;/strong&gt; did (using 4-pixels-wide characters). Maybe the space in ROM was too limited for that, I don't know.&lt;/p&gt;

&lt;p&gt;The problem was that the &lt;strong&gt;ZX Printer&lt;/strong&gt; was rubbish (though probably a smart invention), and nobody would have thought of delivering a document on the mini-paper used by this device. It was a special thermal paper, more similar, both in quality, technology, and size, to a modern supermarket ticket printer.&lt;/p&gt;

&lt;p&gt;The official way to plug a &lt;em&gt;ZX Printer&lt;/em&gt; to a Speccy (or any other printer, by the way), was to use the &lt;a href="https://es.wikipedia.org/wiki/ZX_Interface_1" rel="noopener noreferrer"&gt;&lt;em&gt;Interface 1&lt;/em&gt;&lt;/a&gt;. This interface was incompatible with the ZX Spectrum 128k, however. For starters, the 48k mode was forced, and all extra capabilities present in the Spectrum 128k were therefore gone, such as the RS-232 socket, the advanced editing capabilities, and of course, making the access to text editor in ROM impossible.&lt;/p&gt;

&lt;p&gt;Using the RS-232C output (the physical inlet was the same one as the &lt;em&gt;keypad&lt;/em&gt;), plus a serial to centronics converter available for the &lt;a href="https://es.wikipedia.org/wiki/Sinclair_QL" rel="noopener noreferrer"&gt;&lt;strong&gt;Sinclair QL&lt;/strong&gt;&lt;/a&gt;, you could connect an actual printer to your Spectrum 128k. The result, however, was disappointing. As one could expect, the text would only reach column #32 (instead of using the whole 80 columns), almost wasting the 60% of the available space of a DIN A4 piece of paper.&lt;/p&gt;

&lt;p&gt;You could &lt;a href="https://dev.to/baltasarq/mi-propio-procesador-de-textos-en-zx-sinclair-basic-2ln4"&gt;print your documents in the Spanish ZX Spectrum 128k&lt;/a&gt;, but without using the text editor in ROM.&lt;/p&gt;

&lt;p&gt;Thus, the actual utility of this text editor was very limited in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Editing BASIC programs
&lt;/h2&gt;

&lt;p&gt;The capabilities of the text editor were also used for the &lt;a href="https://dev.to/baltasarq/cadenas-de-caracteres-en-el-basic-del-zx-spectrum-25mc"&gt;Sinclair BASIC&lt;/a&gt; editor, widely improved in contrast to the Spectrum +. These were, for some reason, discarded by Sinclair UK for their Spectrum 128k. Maybe this was due to incompatibilities, though the Spectrum 128k was quite compatible with the 48k software library, and you even could type &lt;code&gt;SPECTRUM&lt;/code&gt; in order to force a 48k 100% compatibility mode. The notion of a whole-screen editor was adopted, anyway.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikripfmujetwdao58gc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikripfmujetwdao58gc3.png" alt="Sinclair BASIC in the Spanish Spectrum 128k" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Spanish Spectrum 128k presented your programs in a more cleaner way than any other Spectrum, including the later ones such as the +2, +2A, +3B and +3. This is shown in the previous image of a small BASIC program, as well as in the next image with the listing of the typical &lt;code&gt;Hello, world!&lt;/code&gt; program.&lt;/p&gt;

&lt;p&gt;The source code can be edited using the whole screen, or over the status bar (provided it fits), by means of the &lt;code&gt;edit &amp;lt;line_number&amp;gt;&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frks7z4hztkimg477zad3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frks7z4hztkimg477zad3.png" alt="Hello, world! in the Spanish Spectrum 128k" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apart from this, the Spanish Speccy 128k supported a few extra useful commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;RENUM: It renumbers all the lines in a program. It does not only change the line numbers, but it also keeps them in sync with all jumps (GO TO's and GO SUB's). This possibility survived in the UK Spectrum 128k, though widely limited. RENUM could be feed with three parameters, of which all were optional: the starting current line number, the new starting line number, and the increment between lines. For instance, &lt;code&gt;RENUM&lt;/code&gt; renumbered all lines starting with the new line number 10, and using an increment of 10 between lines. &lt;code&gt;RENUM 1000, 5000, 5&lt;/code&gt;, would renumber from line 1000 on, using 5000 as the starting line number, and 5 as increment, so the current line 1000 would become 5000, and the current line, say, 1010, would become 5005, and so forth.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DELETE: You could remove all lines in a given range (thus, it's dangerous). The parameters were indeed the starting line and the ending line, such as in &lt;code&gt;DELETE 100, 200&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3jvxgryesolfbvve5to.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3jvxgryesolfbvve5to.png" alt="Translated system messages in the Spanish Spectrum 128k" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, as it was commented above, the whole system messages set were translated into Spanish, and the keyboard included &lt;code&gt;ñ&lt;/code&gt; and &lt;code&gt;ü&lt;/code&gt;. Instead of the UK Pound symbol, the Spanish Peseta &lt;code&gt;Pt&lt;/code&gt; was included as a single character instead. Amusingly, the accented vowels were not supported, you could only show them using OVER 1 with the regular vowels.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print at 1, 1; "a"
print at 1, 1; over 1; "'"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A calculator
&lt;/h2&gt;

&lt;p&gt;The calculator survived in the UK Spectrum 128k, though it seems to me to be more elegant in the Spanish Spectrum 128k. It was not necessary to enter any special mode, nor choose any special option, in order to access the calculator. Just entering a numeric calculation in the status bar or in any blank line of the screen would do (you could just press ENTER to make space below the current line).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ka917ht8ooc4metnzsa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ka917ht8ooc4metnzsa.png" alt="The Spanish Spectrum 128k calculator" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this possibility was used with the &lt;em&gt;keypad&lt;/em&gt; the result was quite useful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz09d04oufdlgs9o4o4vi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz09d04oufdlgs9o4o4vi.png" alt="Partial calculation in the Spanish Spectrum 128k" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Spectrum&lt;/strong&gt; will always store the last result, so you could easily chain calculations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyojhy79vctkjx3hhil8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyojhy79vctkjx3hhil8.png" alt="Finishing the calculation in the Spanish Spectrum 128k" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Links to ads of the Spanish Spectrum 128k
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://microhobby.speccy.cz/mhf/046/MH046_02.jpg" rel="noopener noreferrer"&gt;Add appearing in the Microhobby magazine #46 (MicroHobby Forever)&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://microhobby.speccy.cz/mhf/049/MH049_35.jpg" rel="noopener noreferrer"&gt;Add appearing in the Microhobby magazine #49 (MicroHobby Forever)&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Acknowledgements
&lt;/h2&gt;

&lt;p&gt;All screens above were captured using the &lt;a href="https://www.rastersoft.com/programas/fbzx.html" rel="noopener noreferrer"&gt;FBZX emulator by RasterSoft&lt;/a&gt;, downloading the &lt;a href="https://sites.google.com/view/rodolfoguerra" rel="noopener noreferrer"&gt;Spanish ROMS from the website of Rodolfo Guerra&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>retro</category>
      <category>sinclair</category>
      <category>spectrum</category>
    </item>
    <item>
      <title>El ZX Spectrum + 128K de Investrónica</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Mon, 16 Feb 2026 10:47:47 +0000</pubDate>
      <link>https://dev.to/baltasarq/el-zx-spectrum-128k-de-investronica-332k</link>
      <guid>https://dev.to/baltasarq/el-zx-spectrum-128k-de-investronica-332k</guid>
      <description>&lt;p&gt;&lt;a href="https://www.zonadepruebas.com/viewtopic.php?t=1826" rel="noopener noreferrer"&gt;Este post lo publiqué previamente en ZonaDePruebas&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este ordenador fue diseñado y comercializado en 1985 por &lt;strong&gt;Investrónica&lt;/strong&gt;, en aquel momento una filial de &lt;em&gt;El Corte Inglés&lt;/em&gt; que tenía los derechos de distribución de los productos de Sinclair en España.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo311sg2grm420i85ofq7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo311sg2grm420i85ofq7.png" alt="Arranque del ZX Spectrum 128k español" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Debido a la legislación española, los señores de &lt;strong&gt;Investrónica&lt;/strong&gt; se verían obligados a sacar a la venta este ordenador con soporte en español, es decir, mensajes traducidos, carácter 'ñ' , etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n7xio9txgi7sy5eq4p8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n7xio9txgi7sy5eq4p8.png" alt="Juego de caracteres del Spectrum 128k español" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con la experiencia acumulada tras el desarrollo del 128, castellanizaron el ZX Spectrum + (traduciendo mensajes de error e incorporando la 'ñ') en 1986.&lt;/p&gt;

&lt;p&gt;En Investrónica, siempre intentaron convertir o hacer ver al Spectrum como un ordenador de gestión. Así, el micro venía de serie con un &lt;em&gt;keypad&lt;/em&gt; o teclado numérico independiente, que hacía mucho más cómoda la edición de programas, ya que se podía avanzar, por ejemplo, de palabra en palabra.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5rimekw28l48qqx4kwt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5rimekw28l48qqx4kwt.png" alt="Pantalla principal de trabajo" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El ordenador no debió convencer a los señores de Sinclair UK, ya que finalmente descartaron prácticamente el teclado numérico independiente (sólo se podía adquirir aparte), eliminaron el editor de textos, y crearon unos menús que hacían al ordenador más agradable a primera vista. Eliminaron también el editor de programas BASIC mejorado. Así salió al mercado, un año más tarde, el ZX Spectrum 128 inglés, sin el keypad, y obviamente diferente al español.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm0f3wl8q6w9nilf4pg0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm0f3wl8q6w9nilf4pg0.png" alt="Pantalla principal de Spectrum 128k inglés" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con el tiempo, el 128k español cayó prácticamente en el olvido, sobre todo en cuanto a sus diferencias con el inglés y sus posibilidades mejoradas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Un editor de textos integrado en ROM
&lt;/h2&gt;

&lt;p&gt;El Spectrum 128 español venía de serie con un editor de textos integrado en ROM. Para acceder a él, bastaba utilizar el comando &lt;code&gt;edit&lt;/code&gt;, seguido del nombre de una variable de cadena. De esta forma, todo el texto creado mediante el editor pasaba a estar almacenado en dicha variable, que podía conservar páginas y páginas hasta completar la memoria del Spectrum. Por ejemplo, tecleando desde la pantalla principal: &lt;code&gt;edit e$&lt;/code&gt;, se entraba en el modo de editor de textos con el contenido de esa variable &lt;code&gt;e$&lt;/code&gt;. Y al salir, la variable conservaba los cambios, claro.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd99lchfqcqxqgpr2e04v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd99lchfqcqxqgpr2e04v.png" alt="Entrando en el editor de textos del Spectrum 128k español" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  La memoria del Spectrum 128k
&lt;/h2&gt;

&lt;p&gt;La memoria disponible era de unos treinta y pico kilobytes libres, ya que la memoria extra sólo era accesible empleando unos comandos especiales, &lt;code&gt;save ! ""&lt;/code&gt; y &lt;code&gt;load ! ""&lt;/code&gt;, que permitían acceder a ella. Para listar su contenido, se empleaba el comando &lt;code&gt;cat !&lt;/code&gt;. Es decir, solo se podía utilizar como &lt;a href="https://es.wikipedia.org/wiki/Disco_RAM" rel="noopener noreferrer"&gt;RAMDisk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Todo esto sí sobrevivió en el modelo inglés, llamándosele, de hecho, unidad de disco en memoria, y posteriormente, eliminando las extensiones a &lt;code&gt;load&lt;/code&gt; y &lt;code&gt;save&lt;/code&gt; con el símbolo de admiración, y creando los selectores de unidad en los nombres de archivo &lt;code&gt;a:&lt;/code&gt;, &lt;code&gt;b:&lt;/code&gt;, y &lt;code&gt;m:&lt;/code&gt;. Era posible salvaguardar pantallas (&lt;code&gt;screen$&lt;/code&gt;), código máquina (&lt;code&gt;code&lt;/code&gt;) y matrices (&lt;code&gt;data&lt;/code&gt;), así como programas completos en BASIC, claro está.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REM guardando en el disco RAM
save ! "pant.scr" screen$
save ! "ramjuego" data pos
cat !
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Posibilidades del editor de textos
&lt;/h2&gt;

&lt;p&gt;El editor de textos incorporaba muchas funciones presentes en otros editores (como &lt;strong&gt;Tasword&lt;/strong&gt;, por ejemplo), aunque desde luego le faltaba bastante para llegar a un nivel profesional.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhgx8s98n3ojo146c334.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhgx8s98n3ojo146c334.png" alt="El editor de textos del Spectrum 128k español" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El editor de textos permitía el enrollado de palabra o &lt;em&gt;Word wrap&lt;/em&gt; (que la palabras no se cortasen al llegar al borde del papel), inserción o sobreescritura y, utilizando el teclado numérico independiente, se podía pasar de palabra en palabra y borrar una palabra entera o hasta el final de la línea, así como movimientos varios de ese tipo, desconocidos en un Spectrum.&lt;/p&gt;

&lt;p&gt;Las limitaciones del editor, sin embargo, eran severas. En primer lugar, la salida era de 32 columnas, tantas como mostraba el &lt;em&gt;Speccy&lt;/em&gt; en pantalla. Eso hacía posible imprimir el texto adecuadamente solamente en una &lt;strong&gt;ZX Printer&lt;/strong&gt;, mediante la ejecución del comando &lt;code&gt;lprint e$&lt;/code&gt;. Con la perspectiva del paso del tiempo, creo que deberían haber soportado 64 columnas, como hacía &lt;strong&gt;Tasword&lt;/strong&gt; (con caracteres de 4 píxeles de ancho). Quizás el espacio en la ROM era demasiado limitado para eso, no lo sé.&lt;/p&gt;

&lt;p&gt;El problema era que la &lt;strong&gt;ZX Printer&lt;/strong&gt; era una porquería (por ingeniosa que fuera), y nadie se hubiera planteado entregar un documento de trabajo con el mini-papel que empleaba ese dispositivo (era un papel térmico especial). Se parecía más, tanto en tamaño, como en tecnología o calidad de impresión, a una moderna impresora de tickets del supermercado.&lt;/p&gt;

&lt;p&gt;La forma "oficial" de enchufar una &lt;em&gt;ZX Printer&lt;/em&gt; al Spectrum (o cualquier otra impresora), era utilizar el &lt;a href="https://es.wikipedia.org/wiki/ZX_Interface_1" rel="noopener noreferrer"&gt;&lt;em&gt;Interface 1&lt;/em&gt;&lt;/a&gt;. Esta interfaz no era compatible con el Spectrum 128k. Ya para empezar, forzaba el modo 48k, y todas las posibilidades &lt;em&gt;extra&lt;/em&gt; del Spectrum quedaban deshabilitadas, por ejemplo, el conector RS-232 del que disponía el Spectrum. El editor de textos, por descontado, era inaccesible.&lt;/p&gt;

&lt;p&gt;Utilizando la salida RS-232C del Spectrum 128k español (el enchufe físico era el mismo que el del teclado numérico independiente), más un conversor de serie a paralelo (disponible para el &lt;a href="https://es.wikipedia.org/wiki/Sinclair_QL" rel="noopener noreferrer"&gt;&lt;strong&gt;Sinclair QL&lt;/strong&gt;&lt;/a&gt;), se podía enchufar una impresora de verdad al Spectrum. El resultado, sin embargo, era decepcionante; como era de esperar, el texto llegaba hasta la columna 32 y no aprovechaba las 80 columnas.&lt;/p&gt;

&lt;p&gt;Podías &lt;a href="https://dev.to/baltasarq/mi-propio-procesador-de-textos-en-zx-sinclair-basic-2ln4"&gt;imprimir tus documentos en el ZX Spectrum 128k español&lt;/a&gt;, pero sin utilizar el editor de textos incorporado.&lt;/p&gt;

&lt;p&gt;Así, la utilidad real de este editor de textos era muy limitada en la práctica.&lt;/p&gt;

&lt;h2&gt;
  
  
  El editor de programas BASIC
&lt;/h2&gt;

&lt;p&gt;Las posibilidades del editor de textos también se aprovechaban para el editor de &lt;a href="https://dev.to/baltasarq/cadenas-de-caracteres-en-el-basic-del-zx-spectrum-25mc"&gt;Sinclair BASIC&lt;/a&gt;, ampliamente mejorado con respecto al modelo &lt;strong&gt;Spectrum +&lt;/strong&gt;, y que fue, por alguna razón (quizás por incompatibilidades) descartado por Sinclair para llevarlo incorporado de serie en su propio 128 (el inglés). Eso sí, del 128 español tomaron la idea de poder moverse a pantalla completa editando código.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikripfmujetwdao58gc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikripfmujetwdao58gc3.png" alt="Sinclair BASIC en el Spectrum 128k español" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El Spectrum 128 presenta los programas de una manera más limpia y ordenada que cualquier otro modelo de Spectrum, incluyendo todos los posteriores como el +2, +2A, +2B, y +3. Se aprecia en la siguiente imagen el listado del típico ¡Hola, mundo!&lt;/p&gt;

&lt;p&gt;El código puede editarse a pantalla completa o sobre la barra de estado (siempre que quepa), mediante el comando &lt;code&gt;EDIT &amp;lt;numLinea&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frks7z4hztkimg477zad3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frks7z4hztkimg477zad3.png" alt="¡Hola, mundo! en el spectrum 128 español" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Además, el &lt;strong&gt;Spectrum&lt;/strong&gt; español admitía un par de comandos extras muy útiles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;RENUM: Permite renumerar un programa, pero no sólo renumera los números de línea, sino que mantiene sincronizados los números de línea en los saltos &lt;code&gt;GOTO s&lt;/code&gt; y &lt;code&gt;GOSUB s&lt;/code&gt;. Esta posibilidad sobrevivió, si bien muy recortada. RENUM admitía tres parámetros; la línea de comienzo, el número de línea nuevo para esa línea, y el intervalo que se deseaba que hubiera entre esa línea y las siguientes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DELETE: Permitía borrar las líneas comprendidas entre dos números de línea dados, que se pasaban como parámetros.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3jvxgryesolfbvve5to.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3jvxgryesolfbvve5to.png" alt="Mensajes de error traducidos en el Spectrum 128k  español" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Además, como ya se ha comentado, los mensajes de error estaban traducidos al español, y el teclado contenía la &lt;code&gt;ñ&lt;/code&gt;, y la &lt;code&gt;u&lt;/code&gt; con diéresis (&lt;code&gt;ü&lt;/code&gt;). Eso sí, sorprendentemente, las vocales acentuadas no estaban disponibles. Solo se podían mostrar con &lt;code&gt;OVER 1&lt;/code&gt; y el apóstrofe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print at 1, 1; "a"
print at 1, 1; over 1; "'"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  La calculadora
&lt;/h2&gt;

&lt;p&gt;La calculadora sí sobrevivió en el 128k inglés, aunque a mi parecer era mucho más elegante en el 128k español. No era necesario seleccionar ninguna opción, ni realizar ninguna acción especial, para hacer cualquier cálculo en cualquier momento. Bastaba con mover el cursor a la barra de estdo, o pulsar ENTER para hacer un hueco en el listado BASIC.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ka917ht8ooc4metnzsa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ka917ht8ooc4metnzsa.png" alt="La calculador del Spectrum 128k español" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si esta posibilidad se empleaba en conjunción con el teclado numérico independiente, el resultado era bastante útil.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz09d04oufdlgs9o4o4vi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz09d04oufdlgs9o4o4vi.png" alt="Cálculo parcial en el Spectrum 128k español" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El &lt;strong&gt;Spectrum&lt;/strong&gt; siempre guarda el último resultado, obteniendo la posibilidad de encadenar operaciones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyojhy79vctkjx3hhil8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyojhy79vctkjx3hhil8.png" alt="Terminando el cálculo en el Spectrum 128k español" width="320" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enlaces a publicidad del Spectrum 128 español
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://microhobby.speccy.cz/mhf/046/MH046_02.jpg" rel="noopener noreferrer"&gt;Anuncio aparecido en la revista MicroHobby Nº 46 (MicroHobby Forever)&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://microhobby.speccy.cz/mhf/049/MH049_35.jpg" rel="noopener noreferrer"&gt;Anuncio aparecido en la revista MicroHobby Nº 49 (MicroHobby Forever)&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Agradecimientos
&lt;/h2&gt;

&lt;p&gt;Estas imágenes han sido capturadas con el &lt;a href="https://www.rastersoft.com/programas/fbzx.html" rel="noopener noreferrer"&gt;emulador FBZX de RasterSoft&lt;/a&gt;, bajando &lt;a href="https://sites.google.com/view/rodolfoguerra" rel="noopener noreferrer"&gt;las ROMS españolas de la web de Rodolfo Guerra&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>retro</category>
      <category>sinclair</category>
      <category>spectrum</category>
    </item>
    <item>
      <title>C, ¿el lenguaje de programación de los chamanes?</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Mon, 09 Feb 2026 08:42:22 +0000</pubDate>
      <link>https://dev.to/baltasarq/c-el-lenguaje-de-programacion-de-los-chamanes-pp4</link>
      <guid>https://dev.to/baltasarq/c-el-lenguaje-de-programacion-de-los-chamanes-pp4</guid>
      <description>&lt;p&gt;Cada vez más, los estudiantes de informática se forman con lenguajes de programación de verdadero alto nivel, como el típico Java, C#, Python... Todos ellos tienen algo en común: cuando te manejas con arrays, o matrices: te avisan cuando no aciertas a acceder dentro del array (por ejemplo, a la posición 90 en un vector de 10 posiciones).&lt;/p&gt;

&lt;p&gt;Por ejemplo: el siguiente código lanza la excepción: &lt;strong&gt;IndexError&lt;/strong&gt;, ya que obviamente no existe esa posición.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Python
&lt;/span&gt;
&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Salida:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v[55]
~^^^^
IndexError: list index out of range
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hay diferentes versiones para esto mismo en C# y Java. En C# se lanza la excepción &lt;strong&gt;IndexOutOfRangeException&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// C#&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Salida:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En Java, se lanza la excepción &lt;strong&gt;ArrayIndexOutOfBoundsException&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Java&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]{&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="o"&gt;};&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Salida&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 90 out of bounds for length 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por cierto, un pequeño detalle que me gustaría explorar en otro &lt;em&gt;post&lt;/em&gt;: ¿por qué es necesario renombrar todos los conceptos cuando se crea un lenguaje de programación nuevo? Python y Java fueron diseñados más o menos al mismo tiempo, así que tienen su excusa, pero... ¿por qué Java y C# tienen nombres distintos para las excepciones, o para las clases y métodos de acceso a la consola? Más aún cuando muchos programas en Java pueden compilarse sin modificaciones en C#.&lt;/p&gt;

&lt;p&gt;Volviendo al tema entre manos, está claro que, especialmente con la forma de enseñar programación en la gran mayoría de las facultades de informática, todos los estudiantes asumen que este es el comportamiento "normal". Dicho de otra forma, todos los lenguajes de programación "normales" se comportan de esta manera. No es "culpa" de nadie, así es como son las cosas, punto.&lt;/p&gt;

&lt;p&gt;La pregunta surgió en clases cuando llegamos al punto de los índices negativos en Python. ¡Sí! Python permite la siguiente transformación:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | #&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: #&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | #&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Salida:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#i=0: v[i]=11 | #(i + 1)=1: #(len(v) - (i + 1))=4: v[(len(v) - (i + 1))]=15 | #-(i + 1)=-1: v[-(i + 1)]=15
#i=1: v[i]=12 | #(i + 1)=2: #(len(v) - (i + 1))=3: v[(len(v) - (i + 1))]=14 | #-(i + 1)=-2: v[-(i + 1)]=14
#i=2: v[i]=13 | #(i + 1)=3: #(len(v) - (i + 1))=2: v[(len(v) - (i + 1))]=13 | #-(i + 1)=-3: v[-(i + 1)]=13
#i=3: v[i]=14 | #(i + 1)=4: #(len(v) - (i + 1))=1: v[(len(v) - (i + 1))]=12 | #-(i + 1)=-4: v[-(i + 1)]=12
#i=4: v[i]=15 | #(i + 1)=5: #(len(v) - (i + 1))=0: v[(len(v) - (i + 1))]=11 | #-(i + 1)=-5: v[-(i + 1)]=11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Efectivamente, &lt;code&gt;v[len(v) - 1]&lt;/code&gt;, que obtiene la última posición, es equivalente a &lt;code&gt;v[-1]&lt;/code&gt;. En realidad, no es que realmente Python acepte índices negativos, sino que es una más de las posibilidades expresivas de Python: los índices negativos se transforman, de manera que cuentan desde la longitud total del vector. Una forma alternativa de expresar esto mismo es la de C#, que permite &lt;code&gt;v[^1]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;¡Pero ningún lenguaje de programación "normal" permite índice negativos! ¿No?&lt;br&gt;
Bueno, con C sí puedes hacerlo.&lt;br&gt;
Y así es como desciendes por la madriguera del conejo hacia el mundo de las maravillas.&lt;/p&gt;

&lt;p&gt;El siguiente programa es válido en C, y también en C++:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;" #%d: %d |"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Salida:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; 0: 11 | 1: 12 | 2: 13 | 3: 14 | 4: 15 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La razón de que esto funcione es simple: en realidad, &lt;code&gt;v[ i ]&lt;/code&gt; (o &lt;code&gt;i[ v ]&lt;/code&gt;), no son más que azúcar sintáctico para &lt;code&gt;*(v + i)&lt;/code&gt; o &lt;code&gt;*(i + v)&lt;/code&gt;. Ya más tarde, cuando el compilador genera el código, esto se transforma en: &lt;code&gt;*(v + (sizeof(int) * i))&lt;/code&gt;, ya que los incrementos o decrementos reales siempre dependen del tamaño del tipo del puntero. Claro, es indiferente generar &lt;code&gt;*(v + i)&lt;/code&gt; desde &lt;code&gt;v[ i ]&lt;/code&gt;. o &lt;code&gt;*(i + v)&lt;/code&gt; desde &lt;code&gt;i[v]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;¿Qué tiene que ver esta peculiaridad de C con los índices negativos? Bueno, se trata de que nos hagamos a la idea de que el lenguaje de programación C es muy, muy antiguo y relativamente sencillo (de hecho, ya no se considera de forma pura un lenguaje de alto nivel). Hay que tener en cuenta que C es un lenguaje de programación de sistemas, por lo que es normal que su nivel de expresividad esté muy cercana al &lt;em&gt;hardware&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Así que... ¿se pueden indicar valores negativos en C? Por supuesto. Veámoslo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;" #%d: %d |"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Salida:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#-5: 1 | #-4: 0 | #-3: 0 | #-2: -2 | #-1: 5 | #0: 11 | #1: 12 | #2: 13 | #3: 14 | #4: 15 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En el caso de este programa, estamos recorriendo el espacio en memoria anterior a la posición de &lt;code&gt;v&lt;/code&gt;. En este caso, funciona, y nos devuelve el contenido de la memoria en esas posiciones. Por supuesto, esto entra dentro de lo que se conoce como &lt;em&gt;comportamiento indefinido&lt;/em&gt; (&lt;em&gt;undefined behaviour&lt;/em&gt;), ya que está recorriendo memoria que no se ha reservado previamente. De nuevo, en este caso, estamos explorando las posiciones previas a &lt;code&gt;v&lt;/code&gt; dentro de la pila de llamadas o &lt;em&gt;stack&lt;/em&gt;. Recordemos que, para cada función, se crea un marco dentro del &lt;em&gt;stack&lt;/em&gt; en el que se almacena la dirección de retorno y las variables locales.&lt;/p&gt;

&lt;p&gt;Podemos, de hecho, ver el contenido de &lt;code&gt;v1&lt;/code&gt; desde &lt;code&gt;v2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;    
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;v1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;" #%d: %d |"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;v2&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Salida:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#-10: -10 | #-9: 5 | #-8: 11 | #-7: 12 | #-6: 13 | #-5: 14 | #-4: 15 | #-3: 0 | #-2: 0 | #-1: 0 | #0: 21 | #1: 22 | #2: 23 | #3: 24 | #4: 25 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Efectivamente, dado que tanto &lt;code&gt;v1&lt;/code&gt; como &lt;code&gt;v2&lt;/code&gt; están creados dentro del &lt;code&gt;stack&lt;/code&gt;, y teniendo en cuenta que uno se crea antes que el otro, es probable que suceda que si recorremos las posiciones anteriores a &lt;code&gt;v2&lt;/code&gt; (interpretadas como &lt;code&gt;int&lt;/code&gt;), aparezcan los valores de &lt;code&gt;v1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ni qué decir tiene que esto vuelve a ser &lt;em&gt;comportamiento indefinido&lt;/em&gt;. No tiene sentido que se asuma que, por el hecho de que hayan sido definidos unos antes que otros, la posición de un vector en memoria puede adivinarse desde otro.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp95xsj2n1untu5j5u51o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp95xsj2n1untu5j5u51o.jpg" alt="Un puntero en acción" width="509" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Estas prácticas son conocidas como &lt;em&gt;aritmética de punteros&lt;/em&gt;. Esta característica tiene mucha utilidad... bien utilizada, claro.&lt;/p&gt;

&lt;p&gt;Sí, hay usos legítimos de la aritmética de punteros. Por ejemplo, teniendo en cuenta que C almacena las matrices por filas, podríamos utilizar la aritmética de punteros para recorrer una matriz por columnas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;

&lt;span class="cp"&gt;#define LEN 3
&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;m0&lt;/span&gt;&lt;span class="p"&gt;[][&lt;/span&gt;&lt;span class="n"&gt;LEN&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;}};&lt;/span&gt;    
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;m0&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Recorrido por columnas&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;LEN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;LEN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;" #%d, %d |"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;LEN&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;LEN&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Recorrido secuencial&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;LEN&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;LEN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;" %d "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Salida:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#0, 11 | #3, 21 | #6, 31 | #1, 12 | #4, 22 | #7, 32 | #2, 13 | #5, 23 | #8, 33 |
 11  12  13  21  22  23  31  32  33
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En la salida, podemos ver el recorrido por columnas en la primera línea, y el recorrido por filas, lineal, en la siguiente; a pesar de que la matriz está creada como un vector de vectores, o lo que es lo mismo, un vector de punteros a vectores (por cada una de las filas). Pero esto no es más que un artificio creado por C, como se puede ver en el siguiente esquema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ 0 ]   ---&amp;gt;   [11,
                12,
                13,
[ 1 ]   ---&amp;gt;    21,
                22,
                23,
[ 2 ]   ---&amp;gt;    31,
                32,
               [33]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En conclusión, C es un lenguaje de programación muy antiguo y relativamente sencillo, que crea muy pequeñas abstracciones por encima del &lt;em&gt;hardware&lt;/em&gt;. Esto proporciona a C una gran potencia, pero también provoca grandes errores potenciales de seguridad, casi siempre basados en escribir más allá del final de un vector, algo que puede aprovecharse para colocar código directamente para ser ejecutado tras el retorno de la función.&lt;/p&gt;

&lt;p&gt;Por otra parte, debido precisamente a la presencia potencial de errores de seguridad, C es hoy por hoy un lenguaje de programación que las nuevas generaciones de programadores desconoce, pues la enseñanza ha pasado a enfocarse en lenguajes de programación de mucho más alto nivel.&lt;/p&gt;

&lt;p&gt;Y es por eso que, hoy por hoy, para las nuevas generaciones de informáticos C, es poco más o menos que magia negra.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>c</category>
      <category>systems</category>
      <category>programming</category>
    </item>
    <item>
      <title>Retro-imprimiendo</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Wed, 04 Feb 2026 10:49:28 +0000</pubDate>
      <link>https://dev.to/baltasarq/retro-imprimiendo-5766</link>
      <guid>https://dev.to/baltasarq/retro-imprimiendo-5766</guid>
      <description>&lt;p&gt;Ya he escrito varias veces sobre mis (des)aventuras tratando de &lt;a href="https://dev.to/baltasarq/mi-propio-procesador-de-textos-en-zx-sinclair-basic-2ln4"&gt;utilizar una impresora con mi Sinclair Spectrum 128k&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Bien, pero... ¿cómo se imprimía en papel en aquella época? ¿Se puede seguir imprimiendo así? Bueno... Es una historia muy larga. ¿Alguna vez te has fijado en los códigos ASCII por debajo del espacio en blanco (el #32)?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;DEC&lt;/th&gt;
&lt;th&gt;HEX&lt;/th&gt;
&lt;th&gt;Símbolo&lt;/th&gt;
&lt;th&gt;Descripción&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;NUL&lt;/td&gt;
&lt;td&gt;Carácter Nulo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;SOH&lt;/td&gt;
&lt;td&gt;Inicio de Encabezado&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;STX&lt;/td&gt;
&lt;td&gt;Inicio de Texto&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;ETX&lt;/td&gt;
&lt;td&gt;Fin de Texto&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;EOT&lt;/td&gt;
&lt;td&gt;Fin de Transmisión&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;ENQ&lt;/td&gt;
&lt;td&gt;Consulta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;ACK&lt;/td&gt;
&lt;td&gt;Acuse de recibo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;BEL&lt;/td&gt;
&lt;td&gt;Timbre&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;BS&lt;/td&gt;
&lt;td&gt;Retroceso (borrar)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;HT&lt;/td&gt;
&lt;td&gt;Tabulación&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0A&lt;/td&gt;
&lt;td&gt;LF&lt;/td&gt;
&lt;td&gt;Salto de línea&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;0B&lt;/td&gt;
&lt;td&gt;VT&lt;/td&gt;
&lt;td&gt;Tabulación Vertical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;0C&lt;/td&gt;
&lt;td&gt;FF&lt;/td&gt;
&lt;td&gt;Avance de página&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;0D&lt;/td&gt;
&lt;td&gt;CR&lt;/td&gt;
&lt;td&gt;Retorno de carro&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;0E&lt;/td&gt;
&lt;td&gt;SO&lt;/td&gt;
&lt;td&gt;Desactivar mayúsculas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;0F&lt;/td&gt;
&lt;td&gt;SI&lt;/td&gt;
&lt;td&gt;Activar mayúsculas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;DLE&lt;/td&gt;
&lt;td&gt;Escape enlace datos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;DC1&lt;/td&gt;
&lt;td&gt;Ctrl. dispositivo 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;DC2&lt;/td&gt;
&lt;td&gt;Ctrl. dispositivo 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;DC3&lt;/td&gt;
&lt;td&gt;Ctrl. dispositivo 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;DC4&lt;/td&gt;
&lt;td&gt;Ctrl. dispositivo 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;NAK&lt;/td&gt;
&lt;td&gt;ACK negativo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;SYN&lt;/td&gt;
&lt;td&gt;Síncronía en espera&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;ETB&lt;/td&gt;
&lt;td&gt;Fin bloque&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;CAN&lt;/td&gt;
&lt;td&gt;Cancelar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Fin del medio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;1A&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Substitución&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;1B&lt;/td&gt;
&lt;td&gt;ESC&lt;/td&gt;
&lt;td&gt;Escape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;1C&lt;/td&gt;
&lt;td&gt;FS&lt;/td&gt;
&lt;td&gt;Separador de archivos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;td&gt;1D&lt;/td&gt;
&lt;td&gt;GS&lt;/td&gt;
&lt;td&gt;Separador de grupo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;1E&lt;/td&gt;
&lt;td&gt;RS&lt;/td&gt;
&lt;td&gt;Separador de registro&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;td&gt;1F&lt;/td&gt;
&lt;td&gt;US&lt;/td&gt;
&lt;td&gt;Separador de unidad&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Los primeros ordendores no tenían pantallas, sino que se comunicaban con el usuario a través de una impresora, que funcionaba como una especie de teletipo. La conexión se realizaba a través de la &lt;a href="https://es.wikipedia.org/wiki/RS-232" rel="noopener noreferrer"&gt;interfaz serie RS-232&lt;/a&gt;. Es cierto; no existía USB en aquella época. Esta conexión serie es la responsable de la necesidad de códigos de caracteres como #4 (fin de la transmisión), #6 (ACK o acuse de recibo).&lt;/p&gt;

&lt;p&gt;Para el manejo de la impresora son los códigos #10 (salto de línea), #13 (retorno de carro), o #7 (la campana). ¿En qué se inspiraron para estas impresoras? Pues en las máquinas de escribir de la época.&lt;/p&gt;

&lt;p&gt;Mención aparte merecen los códigos #13 y #10. Si vemos un archivo de texto en Windows o MS-DOS con un &lt;a href="https://apps.kde.org/okteta/" rel="noopener noreferrer"&gt;visor hexadecimal&lt;/a&gt;, veremos cada cambio de línea representado con los códigos 0A0D, es decir LF y CR. Y es que, aquellas impresoras funcionaban con un carro que llevaba una cabecera de matriz de puntos (de ahí que se las llamara impresoras matriciales o &lt;em&gt;dot matrix printers&lt;/em&gt;). Y, sí, en este tipo de impresoras no solo era necesario hacer avanzar el papel (cosa que se hacía con un rodillo, como en las máquinas de escribir, solo que automatizado con un motor), sino también llevar el carro hacia la izquierda. ¿Por qué no es así en UNIX/LINUX? Los desarrolladores decidieron que dedicar dos caracteres por cada cambio de línea era excesivo, una vez descartados aquellos teletipos y asumidos los &lt;a href="https://es.wikipedia.org/wiki/VT100" rel="noopener noreferrer"&gt;terminales&lt;/a&gt;, así que lo simplificaron a solo LF.&lt;/p&gt;

&lt;p&gt;Por cierto, es importante tener en cuenta que los terminales no eran ordenadores, sino solo proporcionaban una pantalla para ver la salida del ordenador, y un teclado integrado para introducir datos en él.&lt;/p&gt;

&lt;p&gt;Hoy por hoy, la necesidad de un protocolo serie ha sida eliminada de cuajo al tener USB, que permite conexiones y desconexiones en caliente, mucha más velocidad, y otras ventajas, como la autoconfiguración, también llamada &lt;a href="https://www.youtube.com/watch?v=yeUyxjLhAxU" rel="noopener noreferrer"&gt;&lt;em&gt;Plug  &amp;amp; Play&lt;/em&gt;&lt;/a&gt;. Además las impresoras ya no utilizan estos caracteres especiales para saber cómo imprimir texto, sino que utilizan &lt;a href="https://es.wikipedia.org/wiki/PostScript" rel="noopener noreferrer"&gt;PostScript&lt;/a&gt;, por lo que, hoy por hoy, estos  31 caracteres (con algunas excepciones, como el #27 (escape), o el #8 (borrado a la izquierda), no se utilizan.&lt;/p&gt;

&lt;p&gt;Así, imprimir un archivo podía hacerse tan fácil como volcar un archivo en un archivo "especial". Y es que, todos los sistemas operativos actuales siguen la &lt;a href="https://es.wikipedia.org/wiki/Todo_es_un_archivo" rel="noopener noreferrer"&gt;metáfora &lt;em&gt;todo es un archivo&lt;/em&gt;&lt;/a&gt;. Es decir, en lugar de tratar cada dispositivo como un caso especial, se trata de obtener datos de él haciendo como que se lee de un archivo, y enviarle datos haciendo como que se escribe en un archivo. Todos los programadores sabemos que, en un programa en C, los descriptores de archivo 0 y 1 se corresponden, respectivamente, con el teclado y la pantalla. Es decir, el archivo #0 es un archivo de solo lectura, y leyendo de él se obtiene la entrada del usuario. El archivo #1 es de solo escritura, y escribiendo en él se muestra texto en la pantalla del usuario.&lt;/p&gt;

&lt;p&gt;Muchos dispositivos requieren sin embargo un manejo más detallado, para lo que existe la llamada al sistema operativo &lt;a href="https://es.wikipedia.org/wiki/Ioctl" rel="noopener noreferrer"&gt;IOCTL&lt;/a&gt;, que es capaz de enviar códigos y datos de manera especial para acceder a características de bajo nivel.&lt;/p&gt;

&lt;p&gt;En cualquier caso, en Windows y en MS-DOS se puede imprimir un archivo de texto &lt;em&gt;archivo.txt&lt;/em&gt; en la impresora por defecto utilizando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;type &lt;/span&gt;archivo.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; prn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sí, &lt;strong&gt;PRN&lt;/strong&gt; es un archivo especial que representa a la impresora, y es la razón por la que no se puede crear un archivo de nombre &lt;em&gt;prn&lt;/em&gt; en MS-DOS o Windows.&lt;/p&gt;

&lt;p&gt;En UNIX/LINUX, el comando es ligeramente distinto, pero el resultado es el mismo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;archivo.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/lp0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El comando &lt;code&gt;cat&lt;/code&gt; vuelva el archivo, igual que &lt;code&gt;type&lt;/code&gt; en MS_DOS o Windows. El carácter &lt;code&gt;&amp;gt;&lt;/code&gt; indica que la salida del anterior comando se va a redirigir, de la pantalla a otro dispositivo. &lt;code&gt;PRN&lt;/code&gt; es el dispositivo de la impresora en MS_DOS/Windows, mientras que en UNIX solía ser &lt;code&gt;/dev/lp0&lt;/code&gt;, pero en tiempos modernos es &lt;code&gt;/dev/usb/lp0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;He escrito &lt;a href="https://github.com/Baltasarq/print/tree/main" rel="noopener noreferrer"&gt;&lt;code&gt;print.py&lt;/code&gt;, una pequeña utilidad que permite volcar datos en texto plano directamente a la impresora&lt;/a&gt; por defecto. Admite algunos códigos, como los siguientes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;^[  : chr(s) 27
^v  : chr(s) 12
^l  : chr(s) 10
^r  : chr(s) 13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si quieremos enviar un texto a la impresora, podemos hacer lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python print.py --send "hola!^v"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El comando anterior vuelca el mensaje hola en la impresora, que lo imprime, y a continuación manda el código ^v, que se corresponde con el carácter #12, y realiza un FF (&lt;em&gt;form feed&lt;/em&gt;), o alimentación de página, lo que hará que salga el papel.&lt;/p&gt;

&lt;p&gt;Si preferimos imprimir un archivo de texto, podemos hacerlo con:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python print.py --file datos.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿Cuál es el corazón del programa? Pues nada, abrir un archivo en modo texto y escribir en él.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Printer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# más cosas...
&lt;/span&gt;
    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;device&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dev&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Sends new data to the printer.
            :param data: the data to send to the printer, as str.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sendfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Sends a whole file to the printer.
            :param filename: the path of the file to print.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rstrip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;interpret_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^r^l&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="bp"&gt;...&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;interpret_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^v&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para terminar... ¿se puede comprar hoy en día una impresora matricial? La respuesta es sí: desde impresoras "normales" hasta impresoras de &lt;em&gt;tickets&lt;/em&gt; para comercios.&lt;/p&gt;

&lt;p&gt;Continuará.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>printing</category>
      <category>python</category>
      <category>retro</category>
    </item>
    <item>
      <title>qb64: un "retro" GW-BASIC, para ordenadores modernos</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Wed, 28 Jan 2026 15:20:41 +0000</pubDate>
      <link>https://dev.to/baltasarq/qb64-un-retro-gw-basic-para-ordenadores-modernos-33mi</link>
      <guid>https://dev.to/baltasarq/qb64-un-retro-gw-basic-para-ordenadores-modernos-33mi</guid>
      <description>&lt;p&gt;&lt;a href="http://qb64.com/" rel="noopener noreferrer"&gt;QB64&lt;/a&gt; es un entorno completo de programación que resulta ser un clon de aquel QBasic/&lt;a href="https://es.wikipedia.org/wiki/Quick_BASIC" rel="noopener noreferrer"&gt;QuickBasic&lt;/a&gt; de los años de &lt;a href="https://es.wikipedia.org/wiki/MS-DOS" rel="noopener noreferrer"&gt;MS-DOS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Si sabes de lo que estoy escribiendo, es que viviste aquella época de los 90, como yo. Si no, es que &lt;a href="https://www.microsiervos.com/archivo/ordenadores/winworld-museo-software-antiguo-programas-sistemas-descargar.html" rel="noopener noreferrer"&gt;te lo has perdido todo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcfpjgec3w0f3dyui83y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcfpjgec3w0f3dyui83y.png" alt="El IDE QB64" width="640" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;También en aquellos años (en los 90), existía QBasic, que era muy parecido a QuickBasic, pero sin la capacidad de compilar su código.&lt;/p&gt;

&lt;p&gt;Por cierto, en &lt;em&gt;Options &amp;gt;&amp;gt; Display&lt;/em&gt;, encontraremos la oportunidad de cambiar la visualización de 80x25 a 120x50, mucho más aconsejable.&lt;/p&gt;

&lt;p&gt;Si, sí. QB64 genera código ejecutable de 64 bits. Pero además, es portable a nivel de código fuente entre Mac, Windows y Linux.&lt;/p&gt;

&lt;p&gt;O dicho de otra forma: además de Free Pascal (para Pascal "retro"), puedes programar en BASIC "retro" y generar código sin que exista forma alguna de distinguirlo del código generado por gcc para C, por poner un ejemplo.&lt;/p&gt;

&lt;p&gt;Así, en modo texto (aunque existe un IDE gráfico llamado Phoenix), podemos teclear nuestros programas, que el IDE los compile, y ejecutarlos con solo pulsar F5.&lt;/p&gt;

&lt;p&gt;Como ejemplo, programé este cálculo de &lt;strong&gt;Fibonacci&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;' Secuencia de Fibonacci

For n = 1 To 25
    Print fibo(n);
Next


Function fibo (x)
    Dim n1 As Long
    Dim n2 As Long
    Dim aux As Long

    n1 = 1
    n2 = 1

    For n = 2 To x
        aux = n2
        n2 = n1 + n2
        n1 = aux
    Next

    fibo = n2
End Function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4xnyyh51a5vp9r00va4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4xnyyh51a5vp9r00va4.png" alt="Salida de Fibo" width="640" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con la salida, previsible, siguiente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 1 2 3 5 8 13 21 34 55 89 144 233 377...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para poder llegar a los resultados más altos, es necesario cambiar &lt;strong&gt;Integer&lt;/strong&gt;, el tipo que usaríamos normalmente, por &lt;strong&gt;Long&lt;/strong&gt;, un entero de 32 bits.&lt;/p&gt;

&lt;p&gt;Pero... ¿qué incorpora este ejecutable?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ldd fibo                                                                   
        linux-vdso.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc39f9000&lt;span class="o"&gt;)&lt;/span&gt;
        libGL.so.1 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libGL.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc394b000&lt;span class="o"&gt;)&lt;/span&gt;
        libGLU.so.1 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libGLU.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc38f4000&lt;span class="o"&gt;)&lt;/span&gt;
        libX11.so.6 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libX11.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc37b2000&lt;span class="o"&gt;)&lt;/span&gt;
        libstdc++.so.6 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libstdc++.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc3400000&lt;span class="o"&gt;)&lt;/span&gt;
        libm.so.6 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libm.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc36a4000&lt;span class="o"&gt;)&lt;/span&gt;
        libgcc_s.so.1 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libgcc_s.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc33d3000&lt;span class="o"&gt;)&lt;/span&gt;
        libc.so.6 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libc.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc3000000&lt;span class="o"&gt;)&lt;/span&gt;
        libGLdispatch.so.0 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libGLdispatch.so.0 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc335a000&lt;span class="o"&gt;)&lt;/span&gt;
        libGLX.so.0 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libGLX.so.0 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc3329000&lt;span class="o"&gt;)&lt;/span&gt;
        libOpenGL.so.0 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libOpenGL.so.0 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc3305000&lt;span class="o"&gt;)&lt;/span&gt;
        libxcb.so.1 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libxcb.so.1 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc32da000&lt;span class="o"&gt;)&lt;/span&gt;
        /lib64/ld-linux-x86-64.so.2 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib64/ld-linux-x86-64.so.2 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc39fb000&lt;span class="o"&gt;)&lt;/span&gt;
        libXau.so.6 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libXau.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc369b000&lt;span class="o"&gt;)&lt;/span&gt;
        libXdmcp.so.6 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /usr/lib/libXdmcp.so.6 &lt;span class="o"&gt;(&lt;/span&gt;0x00007f7cc32d2000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos ver cómo, además de incorporar las bibliotecas básicas del sistema operativo (esto cambiará en Windows o Mac), está claro que genera código C++, pues incluye la librería estándar de este lenguaje de programación. También podemos ver que proporciona capacidades gráficas, pues OpenGL está presente.&lt;/p&gt;

&lt;p&gt;¡Probemos! Sí que tenemos que hacer algo "raro" con respecto a GW-BASIC: crear una "pantalla" del ancho y alto que deseamos:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;screen _newImage(ancho, alto, profundidad_de_color)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Podemos dibujar una línea con &lt;code&gt;line&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;line (x1, y1) - (x2, y2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;¿Podemos dibujar un triángulo? Al margen de que haya otras maneras, si dibujamos "todas" las líneas desde un vértice superior hasta, primero, el vértice inferior izquierdo, y después al vértice inferior derecho, y todas las líneas intermedias, ya lo tendremos.&lt;/p&gt;

&lt;p&gt;La esquina superior izquierda es el origen de coordenadas, es decir, (0, 0). Podemos colocar el vértice superior en (maxX / 2, maxY / 2). El vértice inferior izquierdo sería (100, maxY), y el vértice inferior derecho, (maxX - 100, maxY).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;' Draw a triangle

Const maxX = 620
Const maxY = 450
Screen _NewImage(maxX, maxY, 32)


Call drawTriangle(maxX, maxY, maxY / 2)

Sub drawTriangle (maxX, maxY, length)
    ' The upper vertex is the center of the screen
    orgX = Int(maxX / 2)
    orgY = Int(maxY / 2)

    ' From the lower left to the lower right
    For x = 100 To maxX - 100
        Line (orgX, orgY)-(x, orgX + length)
    Next
End Sub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La salida es un triángulo, lo prometido.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftg5m04ujne4pvnxlb9qb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftg5m04ujne4pvnxlb9qb.png" alt="Triángulo dibujado en QB64" width="621" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mientras las funciones (que se crean con &lt;code&gt;FUNCTION... END FUNCTION&lt;/code&gt;) pueden ser invocadas directamente, tal y como estamos acostumbrados en lenguajes de programación modernos, los procedimientos tienen que ser invocados con &lt;code&gt;CALL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BASIC&lt;/strong&gt; es sin duda el lenguaje de programación retro. No puedo dejar de pensar en &lt;a href="https://boriel.com/pages/the-zx-basic-compiler.html" rel="noopener noreferrer"&gt;ZX BASIC de Boriel&lt;/a&gt;, el Basic del &lt;strong&gt;ZX Spectrum&lt;/strong&gt; pero mucho más moderno, capaz de compilar para el aparato de Sinclair o el &lt;strong&gt;ZX Spectrum Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;¿Y tú? ¿Cuáles son tus vivencias con BASIC?&lt;/p&gt;

</description>
      <category>basic</category>
      <category>spanish</category>
      <category>retro</category>
      <category>msdos</category>
    </item>
    <item>
      <title>El acertijo de Monty Hall</title>
      <dc:creator>Baltasar García Perez-Schofield</dc:creator>
      <pubDate>Wed, 21 Jan 2026 13:15:03 +0000</pubDate>
      <link>https://dev.to/baltasarq/el-acertijo-de-monty-hall-2c45</link>
      <guid>https://dev.to/baltasarq/el-acertijo-de-monty-hall-2c45</guid>
      <description>&lt;p&gt;El acertijo o Problema de Monty Hall ya es ampliamente conocido a estas alturas. De hecho, incluso &lt;a href="https://es.wikipedia.org/wiki/Monty_Hall#%22El_Problema_de_Monty_Hall%22" rel="noopener noreferrer"&gt;el problema de Monty Hall tiene su propia entrada en la Wikipedia&lt;/a&gt;. Pero no lo mires todavía, ¡vas a estropear la diversión! Más aún, si le planteas este problema a una IA, lo reconocerá sin dudar aunque no le indiques cuál es su nombre.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkezlaf0zdxtclz12a1u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkezlaf0zdxtclz12a1u.jpg" alt="El acertijo de Monty Hall con sus tres puertas." width="587" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recientemente, &lt;a href="https://www.youtube.com/watch?v=NYyzWuoxTVE" rel="noopener noreferrer"&gt;Raquel de la Morena y su equipo han dedicado un vídeo a explicar el problema de Monty Hall&lt;/a&gt;. ¿He dicho ya que si te lo ves ahora, vas a estropear la diversión?&lt;/p&gt;

&lt;p&gt;Todo proviene de un concurso presentado por Monty Hall (de ahí el nombre por el que es conocido). En este concurso se presentaban tres puertas, detrás de las cuales había dos cabras y un coche deportivo. El concurso consistía, claro, en acertar con la puerta que escondía el coche. Es posible que a alguno le gustase la posibilidad de llevarse a una cabra a casa, pero no tengo ni idea de si era posible o no. El caso es que, en este concurso, el presentador podía abrir una de las puertas donde él sabía que no estaba el coche. En estos casos, ¿era más ventajoso mantener la elección inicial de la puerta, o en cambio, elegir la que aún está cerrada?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0c5ir4elkjfdq8mbjz6c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0c5ir4elkjfdq8mbjz6c.jpg" alt="El concurso de Monty Hall, hay dos cabras detrás de dos de las tres puertas." width="587" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una mujer, reconocida como poseedora del índice de inteligencia mayor del mundo, Marilyn vos Savant, tenía una columna en un periódico para responder preguntas (se supone que especialmente difíciles, claro). Un lector le propuso la misma pregunta un poco más arriba. Su respuesta fue polémica: es mucho más recomendable cambiar de puerta.&lt;/p&gt;

&lt;p&gt;Si pensaste "da igual", estás, como yo, entre la gran mayoría de personas. Si pensaste lo mismo que Marilyn vos Savant, entonces estás entre los "escogidos", la gente excepcionalmente inteligente que no se deja engañar por las apariencias. Porque este problema se plantea como una paradoja, es decir, casi todo el mundo, independientemente de sus conocimientos o formación, se decanta por la primera opción, la mayoritaria. Mayoritaria e incorrecta.&lt;/p&gt;

&lt;p&gt;De hecho, buena parte de la polémica que se lió con aquella columna tomó la forma de miles de cartas, alrededor de diez mil. Más aún, de estas, mil provenían de matemáticos que estaban visceralmente en desacuerdo con esta mujer, lo que dejaron claro con una actitud claramente clasista, y también machista.&lt;/p&gt;

&lt;p&gt;¿Por qué la respuesta es la que no es intuitiva? Eso es lo que resolveremos mediante código Python, con el que simularemos, utilizando números pseudo-aleatorios (lo que vendría a ser un método Montecarlo), varias jugadas, a ver cuál estrategia (cambiar o no cambiar), es la que objetivamente resulta ser la mejor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;rnd&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_random_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;toret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;toret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;toret&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;generate_random_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)]))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;generate_random_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)]))&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto puede producir la siguiente salida:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3, 2, 2, 1, 3, 3, 3, 1, 2, 1
2, 1, 2, 2, 2, 3, 1, 2, 3, 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podríamos interpretarla de la manera siguiente: la fila superior es el número de puerta (de 1 a 3) en la que se sitúa el premio, mientras que la segunda fila es el número de puerta (también de 1 a 3) elegida por el concursante. Podemos maquillar un poco la salida:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0
-------------------------------------
1 | 1 | 3 | 2 | 3 | 1 | 1 | 3 | 1 | 3
3 | 1 | 3 | 2 | 2 | 1 | 2 | 2 | 3 | 1
-------------------------------------
Aciertos:  4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto lo obtenemos cambiando un poco el código, como se ve a continuación (no se incluye la función &lt;code&gt;generate_random_list()&lt;/code&gt;, que se mantiene tal cual).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;count_coincidences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;toret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l1&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;l1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;toret&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;toret&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;rnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;l_elecciones&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_random_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;l_premios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_random_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-------------------------------------&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; | &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;l_elecciones&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; | &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;l_premios&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-------------------------------------&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Aciertos: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;count_coincidences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l_elecciones&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l_premios&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;    
&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lo que estamos haciendo es utilizar &lt;a href="https://dev.to/baltasarq/arrays-paralelos-3ppj"&gt;listas paralelas&lt;/a&gt;. En la primera, colocamos las elecciones realizadas, mientras en la segunda colocamos las puertas con premios. Podemos compactarlo todo un poco si utilizamos una sola lista, pero de pares. Cada par está formado por la misma información. Es decir, si la puerta elegida fue la primera, y la puerta con premio la tercera, el par será (1, 3). Si hacemos una prueba con 10 puertas, como más arriba, tendremos una lista como [(1, 3, (1, 1), (3, 3), (2, 2), (3, 2), (1, 1), (1, 2), (3, 2), (1, 3), (3, 1)], mientras antes teníamos dos listas: [1, 1, 3, 2, 3, 1, 1, 3, 1, 3], y [3, 1, 3, 2, 2, 1, 2, 2, 3, 1].&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_random_list_door_pairs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_doors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;toret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;toret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;rnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_doors&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="n"&gt;rnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_doors&lt;/span&gt;&lt;span class="p"&gt;)]))&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;toret&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Además, podemos mover el código para visualizar los datos a su propia función. Ahora tenemos que tener en cuenta que recibimos una sola lista, de pares.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l_pairs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-------------------------------------&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; | &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt;
                                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;l_pairs&lt;/span&gt;&lt;span class="p"&gt;]]),&lt;/span&gt;
            &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; | &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt;
                                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;l_pairs&lt;/span&gt;&lt;span class="p"&gt;]]),&lt;/span&gt;
            &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-------------------------------------&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;num_correct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extract_coincidences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l_pairs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l_pairs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;percentage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_correct&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Correct: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;num_correct&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;percentage&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;5.2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finalmente, podemos extraer los pares con ambos valores iguales, en lugar de contarlos directamente. Tomando la longitud de esta lista de pares extraidos, tenemos el número de coincidencias. En lugar de utilizar un bucle, utilizaremos una comprensión de listas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_coincidences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l_pairs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;l_pairs&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos invocar el código con:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# more...
&lt;/span&gt;    &lt;span class="nb"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verbose&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="n"&gt;generated_pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_random_list_door_pairs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;generated_pairs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La salida sería como la siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0
-------------------------------------
3 | 1 | 3 | 1 | 3 | 3 | 2 | 1 | 3 | 2
1 | 3 | 1 | 3 | 1 | 1 | 2 | 3 | 2 | 2
-------------------------------------
Correct: 2/10 (20.00%)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claramente vemos que hay dos coincidencias, en la 7ª y 10ª (esto depende de la ejecución, en otras podemos llegar incluso al 50%). Podemos utilizar &lt;strong&gt;matplotlib&lt;/strong&gt; para crear una gráfica, un simple gráfico de barras sobre el porcentaje de aciertos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show_graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;percentage_correct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg_explain&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msg_explain&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;percentage_correct&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;green&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Monty Hall paradox&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Percentage (0-100%)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si invocamos todo esto con un número considerable de pruebas, es decir, si la lista de pares es de, pongamos, 10000, conseguiremos una estadística suficientemente fiable, respaldada por un número de casos considerable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# more...
&lt;/span&gt;    &lt;span class="nb"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verbose&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="n"&gt;generated_pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_random_list_door_pairs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct selections (no door change)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;correct_pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_coincidences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generated_pairs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;num_correct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;correct_pairs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;percentage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_correct&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;generated_pairs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="nf"&gt;show_graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;percentage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;percentage&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;5.2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La gráfica sería la siguiente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lzepigxvxrowg2s46kk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lzepigxvxrowg2s46kk.png" alt="Estrategia sin cambio de puerta, con 100,000 casos generados." width="376" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos ver cómo los casos con acierto de premio alcanzan un 33.2% del total.&lt;/p&gt;

&lt;p&gt;Esto tiene todo el sentido. Si no cambiamos de puerta, lo que estamos haciendo es confiar en que nuestra primera elección fue desde el principio la correcta, que esa es la puerta con premio. Dado que hay tres puertas, la probabilidad es de 1/3 o 33% sobre el total.&lt;/p&gt;

&lt;p&gt;Podemos ahora abordar la estrategia de cambiar de puerta. Para crear un par &lt;code&gt;(puerta_con_premio, puerta_elegida)&lt;/code&gt;, si cambiamos de puerta tras revelar otra (sin premio), podemos utilizar el siguiente código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_selection_changed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_doors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Initial choice
&lt;/span&gt;    &lt;span class="n"&gt;doors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_doors&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;treasure_door&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;chosen_door&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# One door not containing the treasure is revealed
&lt;/span&gt;    &lt;span class="c1"&gt;# Also it won't be the selected door
&lt;/span&gt;    &lt;span class="n"&gt;door_revealed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;door_revealed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;treasure_door&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;door_revealed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chosen_door&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;revealed_door&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;door_revealed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# Change your chosen door
&lt;/span&gt;    &lt;span class="n"&gt;available_doors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;available_doors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chosen_door&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;available_doors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;discard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;revealed_door&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;chosen_door2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;available_doors&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;treasure_door&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chosen_door2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La puerta elegida es &lt;code&gt;chosen_door&lt;/code&gt;, mientras que la prueba tras la que se esconde el premio es la &lt;code&gt;treasure_door&lt;/code&gt;. Creamos un conjunto &lt;strong&gt;set()&lt;/strong&gt; con las tres puertas (es decir, {1, 2, 3}), llamado &lt;code&gt;door_revealed&lt;/code&gt;. Si a este conjunto le quitamos la puerta premiada (nunca revelaremos la puerta premiada), y también la puerta elegida por el concursante (estas dos puertas pueden ser la misma), entonces nos quedan las puertas que pueden ser reveladas (en el caso de tres puertas, serán dos posibles puertas si el concursante ha elegido la puerta premiada, o una sola en otro caso).&lt;/p&gt;

&lt;p&gt;Así, empezamos con {1, 2, 3}, y tenemos en cuenta que la puerta premiada es la 1, y la elegida por el concursante es la 3. Así, la puerta a revelar es la 2. El concursante tiene la duda de mantenerse con la que eligió inicialmente (la 1), o cambiar (a otra que no sea ni la 1, ni la 2, una la elegida inicialmente, y la otra la revelada como que no tiene premio). Es decir, si tenemos {1, 2, 3}, eliminamos la 1 y la 2, y nos queda que la puerta elegida es la 3. Así, finalmente el par generado sería (3, 3).&lt;/p&gt;

&lt;p&gt;Si empezamos igual que antes, con {1, 2, 3} pero con la puerta premiada siendo la 3, y la puerta elegida siendo también la 3, entonces la puerta a revelar puede ser la 1 o la 2, lo cual se elige al azar. Para cambiar la puerta, eliminamos la puerta elegida inicialmente, la 3, y la puerta revelada (pongamos que la 1), entonces nos queda que la única posibilidad para poder cambiar es la 2. Por tanto, el par ahora sería (3, 2).&lt;/p&gt;

&lt;p&gt;Podemos crear fácilmente el número que deseemos de estos pares con la estrategia de cambio de puerta mediante la siguiente función:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_random_list_door_pairs_after_change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_doors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;selections_changed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;selections_changed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;create_selection_changed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_doors&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;selections_changed&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Solo tenemos que invocar el código de la forma siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# more...
&lt;/span&gt;    &lt;span class="nb"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verbose&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="n"&gt;generated_pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_random_list_door_pairs_after_change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct selections (door changed)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;correct_pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_coincidences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generated_pairs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;num_correct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;correct_pairs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;percentage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_correct&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;generated_pairs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="nf"&gt;show_graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;percentage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;percentage&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;5.2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y ya está. El &lt;a href="https://github.com/Baltasarq/monty-hall-paradox" rel="noopener noreferrer"&gt;código Python completo para esta paradoja de Monty Hall&lt;/a&gt; es un poco distinto porque permite seleccionar el cálculo de la estrategia con cambio, la estrategia sin cambio, o ambas para poder compararlas.&lt;/p&gt;

&lt;p&gt;Si creamos, de nuevo, una lista de casos de 100000 elementos, tendremos una base de casos suficiente como para respaldar una estadística fiable.&lt;/p&gt;

&lt;p&gt;Si lo invocamos, la salida será la siguiente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzixl43jfmv3au58wpe1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzixl43jfmv3au58wpe1.png" alt="Estrategia con cambio de puerta, con 100,000 casos generados." width="325" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora, lo que tenemos es una probabilidad de acierto... ¡de más del 66%!&lt;/p&gt;

&lt;p&gt;El software creado nos permite probar ambas estrategias, y compararlas en una gráfica común, como se puede ver a continuación.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fooedqddj2lpzhquyawhd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fooedqddj2lpzhquyawhd.png" alt="Ambas estrategias, comparadas con 100,000 casos." width="800" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pues resulta que hemos demostrado que, efectivamente, la estrategia que proporciona más probabilidad de acierto es el cambio de puerta. La clave resulta ser que la puerta revelada no lo es al azar, sino que el presentador la escoge entre las puertas que no tienen premio y que el concursante no ha elegido, lo que al final en lugar de 1/3 tenemos 2/3 de posibilidades de acertar. Es decir, más de un 66%.&lt;/p&gt;

&lt;p&gt;Supongamos que en lugar de tres, son diez puertas. El concursante escoge una de las puertas, con 1/10 de probabilidades de acertar, y por tanto, 9/10 de errar. El presentador le revela una puerta donde puede estar el premio o no, además de la elegida inicialmente. Y además, le dice que el resto de las puertas no tienen premios. Es decir, de 10 puertas el concursante escoge la 3. El presentador le revela que en la 9 puede haber o no premio, pero que en todas las restantes (1, 2, 4, 5, 6, 7, 8, 10), solo hay cabras.&lt;/p&gt;

&lt;p&gt;¿Es más probable que hayamos acertado en nuestra elección inicial (1/9 de posibilidades de acertar con la puerta del premio), o será mejor cambiar a esa puerta que estaba inicialmente entre el 9/10 restante?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Baltasarq/monty-hall-paradox" rel="noopener noreferrer"&gt;Código Python completo para simular la paradoja de Monty Hall&lt;/a&gt;&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>mathematics</category>
      <category>matplotlib</category>
      <category>python</category>
    </item>
  </channel>
</rss>
