avatarJason M. Pittman

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

10473

Abstract

/code> method follows a clear algorithm. We first check the health. Then, we decide to attack or heal based on that health. Last, we perform the chosen action. This method could be used in the game to automate the actions of the characters based on their current health.</p><p id="ea5c"><b>Data Representation and Processing:</b> Understanding how data is represented, stored, and processed is another key principle. This includes understanding data structures (like arrays, linked lists, trees), databases, and how data is stored and retrieved.</p><div id="d29d"><pre><span class="hljs-keyword">class</span> <span class="hljs-title class_">GameCharacter</span>: <span class="hljs-keyword">def</span> <span class="hljs-title function_">init</span>(<span class="hljs-params">self, health=<span class="hljs-number">100</span>, strength=<span class="hljs-number">10</span>, name=<span class="hljs-string">""</span></span>): self.health = health self.strength = strength self.name = name

<span class="hljs-keyword">def</span> <span class="hljs-title function_">attack</span>(<span class="hljs-params">self, other_character</span>):
    other_character.health -= self.strength
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{self.name}</span> attacked <span class="hljs-subst">{other_character.name}</span> for <span class="hljs-subst">{self.strength}</span> damage"</span>)

<span class="hljs-keyword">def</span> <span class="hljs-title function_">heal</span>(<span class="hljs-params">self, amount</span>):
    self.health += amount
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{self.name}</span> healed for <span class="hljs-subst">{amount}</span> health points"</span>)

<span class="hljs-keyword">def</span> <span class="hljs-title function_">check_health</span>(<span class="hljs-params">self</span>):
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{self.name}</span> current health: <span class="hljs-subst">{self.health}</span>"</span>)
    <span class="hljs-keyword">return</span> self.health

<span class="hljs-keyword">def</span> <span class="hljs-title function_">defend_and_heal</span>(<span class="hljs-params">self, other_character, health_threshold=<span class="hljs-number">30</span></span>):
    <span class="hljs-keyword">if</span> self.check_health() &gt; health_threshold:
        self.attack(other_character)
    <span class="hljs-keyword">else</span>:
        self.heal(self.strength)

<span class="hljs-keyword">class</span> <span class="hljs-title class_">Game</span>: <span class="hljs-keyword">def</span> <span class="hljs-title function_">init</span>(<span class="hljs-params">self</span>): self.characters = []

<span class="hljs-keyword">def</span> <span class="hljs-title function_">add_character</span>(<span class="hljs-params">self, character</span>):
    self.characters.append(character)

<span class="hljs-keyword">def</span> <span class="hljs-title function_">start_fight</span>(<span class="hljs-params">self</span>):
    <span class="hljs-keyword">while</span> <span class="hljs-built_in">all</span>(character.check_health() &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">for</span> character <span class="hljs-keyword">in</span> self.characters):
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-built_in">len</span>(self.characters)):
            attacker = self.characters[i]
            defender = self.characters[(i+<span class="hljs-number">1</span>)%<span class="hljs-built_in">len</span>(self.characters)]  <span class="hljs-comment"># Attack the next character in the list</span>
            attacker.defend_and_heal(defender)

    <span class="hljs-comment"># Announce the game results</span>
    <span class="hljs-keyword">for</span> character <span class="hljs-keyword">in</span> self.characters:
        <span class="hljs-keyword">if</span> character.check_health() &gt; <span class="hljs-number">0</span>:
            <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{character.name}</span> is victorious!"</span>)

<span class="hljs-comment"># Create game characters</span> hero = GameCharacter(health=<span class="hljs-number">120</span>, strength=<span class="hljs-number">15</span>, name=<span class="hljs-string">"Hero"</span>) monster = GameCharacter(health=<span class="hljs-number">200</span>, strength=<span class="hljs-number">20</span>, name=<span class="hljs-string">"Monster"</span>)

<span class="hljs-comment"># Create a game</span> game = Game()

<span class="hljs-comment"># Add characters to the game</span> game.add_character(hero) game.add_character(monster)

<span class="hljs-comment"># Start the fight</span> game.start_fight()</pre></div><p id="6009">In this example, the <code>Game</code> class represents and manages the game data. There is a list of <code>GameCharacter</code> objects stored in the <code>characters</code> attribute. The <code>add_character</code> method allows us to add characters to the game, and the <code>start_fight</code> method processes this data by orchestrating a fight between the characters. This is a basic example of data representation (the <code>characters</code> list) and data processing (the <code>start_fight</code> method).</p><p id="5274"><b>Computational Thinking:</b> This is a way of solving problems, designing systems, and understanding human behavior that draws on concepts from computer science. It involves making use of algorithmic thinking, decomposition, abstraction, and debugging, as well as understanding the capabilities and limitations of computers. It is a general approach that produces specific outcomes.</p><div id="d9c4"><pre><span class="hljs-keyword">class</span> <span class="hljs-title class_">GameCharacter</span>: <span class="hljs-keyword">def</span> <span class="hljs-title function_">init</span>(<span class="hljs-params">self, health=<span class="hljs-number">100</span>, strength=<span class="hljs-number">10</span>, name=<span class="hljs-string">""</span></span>): self.health = health self.strength = strength self.name = name self.victory_count = <span class="hljs-number">0</span> self.level = <span class="hljs-number">1</span>

<span class="hljs-keyword">def</span> <span class="hljs-title function_">attack</span>(<span class="hljs-params">self, other_character</span>):
    other_character.health -= self.strength
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{self.name}</span> attacked <span class="hljs-subst">{other_character.name}</span> for <span class="hljs-subst">{self.strength}</span> damage"</span>)

<span class="hljs-keyword">def</span> <span class="hljs-title function_">heal</span>(<span class="hljs-params">self, amount</span>):
    self.health += amount
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{self.name}</span> healed for <span class="hljs-subst">{amount}</span> health points"</span>)

<span class="hljs-keyword">def</span> <span class="hljs-title function_">check_health</span>(<span class="hljs-params">self</span>):
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{self.name}</span> current health: <span class="hljs-subst">{self.health}</span>"</span>)
    <span class="hljs-keyword">return</span> self.health

<span class="hljs-keyword">def</span> <span class="hljs-title function_">defend_and_heal</span>(<span class="hljs-params">self, other_character, health_threshold=<span class="hljs-number">30</span></span>):
    <span class="hljs-keyword">if</span> self.check_health() &gt; health_threshold:
        self.attack(other_character)
    <span class="hljs-keyword">else</span>:
        self.heal(self.strength)

<span class="hljs-keyword">def</span> <span class="hljs-title function_">level_up</span>(<span class="hljs-params">self</span>):
    <span class="hljs-keyword">if</span> self.victory_count &gt;= <span class="hljs-number">3</span>:  <span class="hljs-comment"># Level up every 3 victories</span>
        self.level += <span class="hljs-number">1</span>
        self.strength += <span class="hljs-number">5</span>  <span class="hljs-comment"># Increase strength by 5 points each level</span>
        self.victory_count = <span class="hljs-number">0</span>  <span class="hljs-comment"># Reset victory count</span>
        <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{self.name}</span> leveled up! Now at level <span class="hljs-subst">{self.level}</span> with strength <span class="hljs-subst">{self.strength}</span>"</span>)

<span class="hljs-keyword">class</span> <span class="hljs-title class_">Game</span>: <span class="hljs-keyword">def</span> <span class="hljs-title function_">init</span>(<span class="hljs-params">self</span>): self.characters = []

<span class="hljs-keyword">def</span> <span class="hljs-title function_">add_character</span>(<span class="hljs-params">self, character</span>):
    self.characters.append(character)

<span class="hljs-keyword">def</span> <span class="hljs-title function_">start_fight</span>(<span class="hljs-params">self</span>):
    <span class="hljs-keyword">while</span> <span class="hljs-built_in">all</span>(character.check_health() &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">for</span> character <span class="hljs-keyword">in</span> self.characters):
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-built_in">len</span>(self.characters)):
            attacker = self.characters[i]
            defender = self.characters[(i+<span class="hljs-number">1</span>)%<span class="hljs-built_in">len</span>(self.characters)]  <span class="hljs-comment"># Attack the next character in the list</span>
            attacker.defend_and_heal(defender)

    <span 

Options

class="hljs-comment"># After the fight, update the game results</span> <span class="hljs-keyword">for</span> character <span class="hljs-keyword">in</span> self.characters: <span class="hljs-keyword">if</span> character.check_health() > <span class="hljs-number">0</span>: character.victory_count += <span class="hljs-number">1</span> character.level_up() <span class="hljs-built_in">print</span>(<span class="hljs-string">f"<span class="hljs-subst">{character.name}</span> is victorious!"</span>)

<span class="hljs-comment"># Create game characters</span> hero = GameCharacter(health=<span class="hljs-number">120</span>, strength=<span class="hljs-number">15</span>, name=<span class="hljs-string">"Hero"</span>) monster = GameCharacter(health=<span class="hljs-number">200</span>, strength=<span class="hljs-number">20</span>, name=<span class="hljs-string">"Monster"</span>)

<span class="hljs-comment"># Create a game</span> game = Game()

<span class="hljs-comment"># Add characters to the game</span> game.add_character(hero) game.add_character(monster)

<span class="hljs-comment"># Start the fight</span> game.start_fight()</pre></div><p id="b1ed">The computational thinking comes into play when we broke down the problem of leveling up into smaller problems (counting victories, checking for level up, updating level and strength). We used algorithmic thinking to solve these smaller problems. The <code>level_up</code> method encapsulates the logic for leveling up, making it easier to understand and modify if needed.</p><p id="a211"><b>Logic and Reasoning:</b> Logical reasoning is used to write programs, design algorithms, and understand how systems operate. This includes understanding concepts from discrete mathematics, such as propositional logic, set theory, and graph theory. We can pinpoint where in our running example logic and reasoning are employed.</p><ul><li><i>Algorithmic logic</i><b>:</b> The methods inside our <code>GameCharacter</code> class, such as <code>attack</code>, <code>heal</code>, <code>check_health</code>, and <code>defend_and_heal</code>, all use algorithmic logic. They define a series of steps and conditions that need to be executed or checked in order to perform their respective actions. For example, in <code>defend_and_heal</code>, there's a condition that checks if the character's health is above a certain threshold. If it is, the character attacks; otherwise, it heals. This is a simple form of logic and reasoning that's ubiquitous in programming.</li><li><i>Game loop logic</i><b>:</b> The <code>start_fight</code> method in the <code>Game</code> class contains the game loop, which is a common construct in game programming. This loop continues as long as all characters have health above 0. This uses logical reasoning to determine when the game should continue and when it should stop.</li><li><i>Level-up logic</i><b>:</b> The <code>level_up</code> method uses logical reasoning to check if a character's victory count has reached a certain threshold and, if so, increments the character's level, increases the character's strength, and resets the victory count.</li><li><i>Conditional logic and control flow</i><b>:</b> The <code>if</code> statements represent conditional logic. The actions taken by the program (whether to attack or heal, whether to level up or not) are determined by the logical conditions specified in these <code>if</code> statements.</li><li><i>Data logic</i><b>:</b> The structure and manipulation of data also involves logic. In our <code>Game</code> class, we logically group together related <code>GameCharacter</code> objects into a list. The <code>add_character</code> and <code>start_fight</code> methods involve logic for manipulating this data.</li></ul><p id="1c5a"><b>System Design and Architecture:</b> This involves understanding the basic building blocks of computers and systems, including understanding hardware (like CPUs, RAM, and hard drives), operating systems, networks, and more.</p><ul><li><i>Modularity</i><b>:</b> Our code is divided into two classes: <code>GameCharacter</code> and <code>Game</code>. This makes the code modular and organized, with each class having its own responsibilities. <code>GameCharacter</code> manages the properties and actions of individual characters, while <code>Game</code> manages the overall game state and controls the game loop.</li><li><i>Encapsulation</i><b>:</b> We’ve used encapsulation to bundle data and methods that operate on that data within our classes. For example, <code>GameCharacter</code> encapsulates data like <code>health</code>, <code>strength</code>, <code>name</code>, and <code>victory_count</code>, and methods like <code>attack</code>, <code>heal</code>, and <code>level_up</code> that operate on this data.</li><li><i>Abstraction</i><b>:</b> We’ve used abstraction to hide the complexity of certain operations. For example, a complex operation like a special attack that involves both attacking and healing is abstracted into a single method <code>defend_and_heal</code>.</li><li><i>Data Structure Design</i><b>:</b> The choice to represent a collection of <code>GameCharacter</code> objects as a list in the <code>Game</code> class is a design decision that affects how we structure and process our game data.</li><li><i>Responsibility Distribution</i><b>:</b> We’ve also made decisions about where different responsibilities should lie. For example, the logic for leveling up a character is placed in the <code>GameCharacter</code> class, since it's closely related to the internal state of a character.</li><li><i>Scalability</i><b>:</b> The design of this code allows for easy expansion and scalability. New actions, characters, or game mechanics can be added by extending the <code>GameCharacter</code> class, and the <code>Game</code> class can be extended to manage more complex game states or multiple rounds of fights.</li></ul><p id="1122"><b>Efficiency and Performance:</b> Understanding how to make software and hardware perform efficiently is crucial. This can involve algorithm design and analysis, understanding time and space complexity, and considering the physical constraints of the hardware. After all, we can intend to design and implement efficient, performant systems but without verification we actually would not know for certain. Enter the <i>unit test</i> framework.</p><div id="bc6c"><pre><span class="hljs-keyword">import</span> unittest

<span class="hljs-keyword">class</span> <span class="hljs-title class_">TestGameCharacter</span>(unittest.TestCase): <span class="hljs-keyword">def</span> <span class="hljs-title function_">setUp</span>(<span class="hljs-params">self</span>): self.hero = GameCharacter(health=<span class="hljs-number">120</span>, strength=<span class="hljs-number">15</span>, name=<span class="hljs-string">"Hero"</span>) self.monster = GameCharacter(health=<span class="hljs-number">200</span>, strength=<span class="hljs-number">20</span>, name=<span class="hljs-string">"Monster"</span>)

<span class="hljs-keyword">def</span> <span class="hljs-title function_">test_attack</span>(<span class="hljs-params">self</span>):
    self.hero.attack(self.monster)
    self.assertEqual(self.monster.health, <span class="hljs-number">185</span>)  <span class="hljs-comment"># Monster's health should be reduced by hero's strength</span>

<span class="hljs-keyword">def</span> <span class="hljs-title function_">test_heal</span>(<span class="hljs-params">self</span>):
    self.hero.health = <span class="hljs-number">50</span>
    self.hero.heal(<span class="hljs-number">30</span>)
    self.assertEqual(self.hero.health, <span class="hljs-number">80</span>)  <span class="hljs-comment"># Hero's health should be increased by 30</span>

<span class="hljs-keyword">def</span> <span class="hljs-title function_">test_level_up</span>(<span class="hljs-params">self</span>):
    <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>):
        self.hero.victory_count += <span class="hljs-number">1</span>
    self.hero.level_up()
    self.assertEqual(self.hero.level, <span class="hljs-number">2</span>)  <span class="hljs-comment"># Hero's level should be increased</span>
    self.assertEqual(self.hero.strength, <span class="hljs-number">20</span>)  <span class="hljs-comment"># Hero's strength should be increased by 5</span>
    self.assertEqual(self.hero.victory_count, <span class="hljs-number">0</span>)  <span class="hljs-comment"># Hero's victory count should be reset</span>

<span class="hljs-keyword">if</span> name == <span class="hljs-string">'main'</span>: unittest.main()</pre></div><p id="8c4f">This <code>TestGameCharacter</code> class extends the <code>unittest.TestCase</code> class, which provides a framework for creating and running tests. Each method in this class that starts with "test_" is a separate test. In the <code>setUp</code> method, we create the game characters that we will use in each test.</p><p id="6c6f">If we wanted to optimize our <code>GameCharacter</code> methods for better performance, we could run these tests before and after making our changes to ensure that the functionality of these methods remains the same. We can also run specific tests like I outlined <a href="https://readmedium.com/top-3-ways-to-implement-green-computing-evaluations-in-python-unit-testing-f58f0eb49f37">here</a>.</p><p id="1e52">These are the 8 core principles of computer science in my opinion. Now, what I like so much about these principles is all eight have both a theoretical and applied foundation. The examples I’ve used in this story straddle the line between theory and application. I admit the code is simple. Yet, each I say demonstrates the concept well enough for us to embark on deeper study. And study deeper we shall. Stay tuned to this space as we construct more advanced examples for each principle.</p><p id="f415">If you appreciate this story, here are three actions you can take right now to support my work:</p><p id="27a3">1. Give the story a CLAP 👏 and leave a COMMENT 📫 with your thoughts</p><p id="3ad1">2. FOLLOW me to get notified of new stories ⏰</p><p id="2d10">3. SHARE and recommend this story on your social media 🐦</p></article></body>

8 Core Principles of Computer Science

Photo by Max Duzij on Unsplash

Sometimes I wonder what computer science is and sometimes the answer is not obvious. Despite the years of studying and teaching, it can be easy to lose track of the core principles of the field. This story serves two purposes then. Foremost, to share what I believe to be the 8 core principles of computer science. Second, to serve as a reminder list. Of course, neither case is complete without applied examples. Let’s build out the 8 core principles using a video game character.

Abstraction: Abstraction is the process of reducing the complexity of a system by focusing on the high-level view and ignoring specific details. This allows us to manage and reason about complex systems. For example, when programming, we often use functions or methods to encapsulate tasks.

class GameCharacter:
    def __init__(self, health=100, strength=10):
        self.health = health
        self.strength = strength

    def attack(self, other_character):
        other_character.health -= self.strength
        print(f"Attacked other character for {self.strength} damage")

    def heal(self, amount):
        self.health += amount
        print(f"Healed for {amount} health points")

    def check_health(self):
        print(f"Current health: {self.health}")
        return self.health

# Create game characters
hero = GameCharacter(health=120, strength=15)
monster = GameCharacter(health=200, strength=20)

# Hero attacks monster
hero.attack(monster)

# Monster attacks hero
monster.attack(hero)

# Hero heals
hero.heal(30)

# Check health
hero.check_health()
monster.check_health()

In this example, GameCharacter is an abstraction of a character in a video game. The attributes health and strength define the state of the character, while the methods attack, heal, and check_health define the actions that a character can perform.

These methods hide the details of how the actions are performed, such as how the attack method reduces the other character's health, or how the heal method increases the character's own health. This encapsulation of details is a key aspect of abstraction. It allows the game characters to be manipulated at a high level, without needing to know the details of how the characters are implemented. It simplifies our mental model of the system, allowing us to focus on the important high-level behaviors rather than the low-level details.

Decomposition: This involves breaking down a complex problem or system into smaller, more manageable parts. Decomposition is used extensively in areas such as software engineering (breaking down a large software system into modules or components) and algorithm design (breaking down a problem into simpler sub-problems).

class GameCharacter:
    def __init__(self, health=100, strength=10):
        self.health = health
        self.strength = strength

    def attack(self, other_character):
        other_character.health -= self.strength
        print(f"Attacked other character for {self.strength} damage")

    def heal(self, amount):
        self.health += amount
        print(f"Healed for {amount} health points")

    def check_health(self):
        print(f"Current health: {self.health}")
        return self.health

    def special_attack(self, other_character):
        # Step 1: Perform a normal attack
        self.attack(other_character)

        # Step 2: Heal self by half the strength
        self.heal(self.strength / 2)

# Create game characters
hero = GameCharacter(health=120, strength=15)
monster = GameCharacter(health=200, strength=20)

# Hero performs special attack on monster
hero.special_attack(monster)

# Check health
hero.check_health()
monster.check_health()

In this example, the special_attack method represents a more complex operation, but it's been decomposed into two simpler operations: a regular attack followed by a heal. This decomposition makes the special_attack operation much easier to understand and implement.

Algorithmic Thinking: An algorithm is a step-by-step procedure for solving a problem or achieving a goal. The development and analysis of algorithms is a fundamental part of computer science, as it’s how we create effective and efficient software.

class GameCharacter:
    def __init__(self, health=100, strength=10):
        self.health = health
        self.strength = strength

    def attack(self, other_character):
        other_character.health -= self.strength
        print(f"Attacked other character for {self.strength} damage")

    def heal(self, amount):
        self.health += amount
        print(f"Healed for {amount} health points")

    def check_health(self):
        print(f"Current health: {self.health}")
        return self.health

    def defend_and_heal(self, other_character, health_threshold=30):
        # Step 1: Check current health
        if self.check_health() > health_threshold:
            # Step 2: If health is above threshold, attack
            self.attack(other_character)
        else:
            # Step 3: If health is below or equal to threshold, heal
            self.heal(self.strength)

# Create game characters
hero = GameCharacter(health=120, strength=15)
monster = GameCharacter(health=200, strength=20)

# Hero and monster fight
while hero.check_health() > 0 and monster.check_health() > 0:
    hero.defend_and_heal(monster)
    monster.defend_and_heal(hero)

# Check final health
hero.check_health()
monster.check_health()

In this code, the defend_and_heal method follows a clear algorithm. We first check the health. Then, we decide to attack or heal based on that health. Last, we perform the chosen action. This method could be used in the game to automate the actions of the characters based on their current health.

Data Representation and Processing: Understanding how data is represented, stored, and processed is another key principle. This includes understanding data structures (like arrays, linked lists, trees), databases, and how data is stored and retrieved.

class GameCharacter:
    def __init__(self, health=100, strength=10, name=""):
        self.health = health
        self.strength = strength
        self.name = name

    def attack(self, other_character):
        other_character.health -= self.strength
        print(f"{self.name} attacked {other_character.name} for {self.strength} damage")

    def heal(self, amount):
        self.health += amount
        print(f"{self.name} healed for {amount} health points")

    def check_health(self):
        print(f"{self.name} current health: {self.health}")
        return self.health

    def defend_and_heal(self, other_character, health_threshold=30):
        if self.check_health() > health_threshold:
            self.attack(other_character)
        else:
            self.heal(self.strength)

class Game:
    def __init__(self):
        self.characters = []

    def add_character(self, character):
        self.characters.append(character)

    def start_fight(self):
        while all(character.check_health() > 0 for character in self.characters):
            for i in range(len(self.characters)):
                attacker = self.characters[i]
                defender = self.characters[(i+1)%len(self.characters)]  # Attack the next character in the list
                attacker.defend_and_heal(defender)

        # Announce the game results
        for character in self.characters:
            if character.check_health() > 0:
                print(f"{character.name} is victorious!")

# Create game characters
hero = GameCharacter(health=120, strength=15, name="Hero")
monster = GameCharacter(health=200, strength=20, name="Monster")

# Create a game
game = Game()

# Add characters to the game
game.add_character(hero)
game.add_character(monster)

# Start the fight
game.start_fight()

In this example, the Game class represents and manages the game data. There is a list of GameCharacter objects stored in the characters attribute. The add_character method allows us to add characters to the game, and the start_fight method processes this data by orchestrating a fight between the characters. This is a basic example of data representation (the characters list) and data processing (the start_fight method).

Computational Thinking: This is a way of solving problems, designing systems, and understanding human behavior that draws on concepts from computer science. It involves making use of algorithmic thinking, decomposition, abstraction, and debugging, as well as understanding the capabilities and limitations of computers. It is a general approach that produces specific outcomes.

class GameCharacter:
    def __init__(self, health=100, strength=10, name=""):
        self.health = health
        self.strength = strength
        self.name = name
        self.victory_count = 0
        self.level = 1

    def attack(self, other_character):
        other_character.health -= self.strength
        print(f"{self.name} attacked {other_character.name} for {self.strength} damage")

    def heal(self, amount):
        self.health += amount
        print(f"{self.name} healed for {amount} health points")

    def check_health(self):
        print(f"{self.name} current health: {self.health}")
        return self.health

    def defend_and_heal(self, other_character, health_threshold=30):
        if self.check_health() > health_threshold:
            self.attack(other_character)
        else:
            self.heal(self.strength)

    def level_up(self):
        if self.victory_count >= 3:  # Level up every 3 victories
            self.level += 1
            self.strength += 5  # Increase strength by 5 points each level
            self.victory_count = 0  # Reset victory count
            print(f"{self.name} leveled up! Now at level {self.level} with strength {self.strength}")

class Game:
    def __init__(self):
        self.characters = []

    def add_character(self, character):
        self.characters.append(character)

    def start_fight(self):
        while all(character.check_health() > 0 for character in self.characters):
            for i in range(len(self.characters)):
                attacker = self.characters[i]
                defender = self.characters[(i+1)%len(self.characters)]  # Attack the next character in the list
                attacker.defend_and_heal(defender)

        # After the fight, update the game results
        for character in self.characters:
            if character.check_health() > 0:
                character.victory_count += 1
                character.level_up()
                print(f"{character.name} is victorious!")

# Create game characters
hero = GameCharacter(health=120, strength=15, name="Hero")
monster = GameCharacter(health=200, strength=20, name="Monster")

# Create a game
game = Game()

# Add characters to the game
game.add_character(hero)
game.add_character(monster)

# Start the fight
game.start_fight()

The computational thinking comes into play when we broke down the problem of leveling up into smaller problems (counting victories, checking for level up, updating level and strength). We used algorithmic thinking to solve these smaller problems. The level_up method encapsulates the logic for leveling up, making it easier to understand and modify if needed.

Logic and Reasoning: Logical reasoning is used to write programs, design algorithms, and understand how systems operate. This includes understanding concepts from discrete mathematics, such as propositional logic, set theory, and graph theory. We can pinpoint where in our running example logic and reasoning are employed.

  • Algorithmic logic: The methods inside our GameCharacter class, such as attack, heal, check_health, and defend_and_heal, all use algorithmic logic. They define a series of steps and conditions that need to be executed or checked in order to perform their respective actions. For example, in defend_and_heal, there's a condition that checks if the character's health is above a certain threshold. If it is, the character attacks; otherwise, it heals. This is a simple form of logic and reasoning that's ubiquitous in programming.
  • Game loop logic: The start_fight method in the Game class contains the game loop, which is a common construct in game programming. This loop continues as long as all characters have health above 0. This uses logical reasoning to determine when the game should continue and when it should stop.
  • Level-up logic: The level_up method uses logical reasoning to check if a character's victory count has reached a certain threshold and, if so, increments the character's level, increases the character's strength, and resets the victory count.
  • Conditional logic and control flow: The if statements represent conditional logic. The actions taken by the program (whether to attack or heal, whether to level up or not) are determined by the logical conditions specified in these if statements.
  • Data logic: The structure and manipulation of data also involves logic. In our Game class, we logically group together related GameCharacter objects into a list. The add_character and start_fight methods involve logic for manipulating this data.

System Design and Architecture: This involves understanding the basic building blocks of computers and systems, including understanding hardware (like CPUs, RAM, and hard drives), operating systems, networks, and more.

  • Modularity: Our code is divided into two classes: GameCharacter and Game. This makes the code modular and organized, with each class having its own responsibilities. GameCharacter manages the properties and actions of individual characters, while Game manages the overall game state and controls the game loop.
  • Encapsulation: We’ve used encapsulation to bundle data and methods that operate on that data within our classes. For example, GameCharacter encapsulates data like health, strength, name, and victory_count, and methods like attack, heal, and level_up that operate on this data.
  • Abstraction: We’ve used abstraction to hide the complexity of certain operations. For example, a complex operation like a special attack that involves both attacking and healing is abstracted into a single method defend_and_heal.
  • Data Structure Design: The choice to represent a collection of GameCharacter objects as a list in the Game class is a design decision that affects how we structure and process our game data.
  • Responsibility Distribution: We’ve also made decisions about where different responsibilities should lie. For example, the logic for leveling up a character is placed in the GameCharacter class, since it's closely related to the internal state of a character.
  • Scalability: The design of this code allows for easy expansion and scalability. New actions, characters, or game mechanics can be added by extending the GameCharacter class, and the Game class can be extended to manage more complex game states or multiple rounds of fights.

Efficiency and Performance: Understanding how to make software and hardware perform efficiently is crucial. This can involve algorithm design and analysis, understanding time and space complexity, and considering the physical constraints of the hardware. After all, we can intend to design and implement efficient, performant systems but without verification we actually would not know for certain. Enter the unit test framework.

import unittest

class TestGameCharacter(unittest.TestCase):
    def setUp(self):
        self.hero = GameCharacter(health=120, strength=15, name="Hero")
        self.monster = GameCharacter(health=200, strength=20, name="Monster")

    def test_attack(self):
        self.hero.attack(self.monster)
        self.assertEqual(self.monster.health, 185)  # Monster's health should be reduced by hero's strength

    def test_heal(self):
        self.hero.health = 50
        self.hero.heal(30)
        self.assertEqual(self.hero.health, 80)  # Hero's health should be increased by 30

    def test_level_up(self):
        for _ in range(3):
            self.hero.victory_count += 1
        self.hero.level_up()
        self.assertEqual(self.hero.level, 2)  # Hero's level should be increased
        self.assertEqual(self.hero.strength, 20)  # Hero's strength should be increased by 5
        self.assertEqual(self.hero.victory_count, 0)  # Hero's victory count should be reset

if __name__ == '__main__':
    unittest.main()

This TestGameCharacter class extends the unittest.TestCase class, which provides a framework for creating and running tests. Each method in this class that starts with "test_" is a separate test. In the setUp method, we create the game characters that we will use in each test.

If we wanted to optimize our GameCharacter methods for better performance, we could run these tests before and after making our changes to ensure that the functionality of these methods remains the same. We can also run specific tests like I outlined here.

These are the 8 core principles of computer science in my opinion. Now, what I like so much about these principles is all eight have both a theoretical and applied foundation. The examples I’ve used in this story straddle the line between theory and application. I admit the code is simple. Yet, each I say demonstrates the concept well enough for us to embark on deeper study. And study deeper we shall. Stay tuned to this space as we construct more advanced examples for each principle.

If you appreciate this story, here are three actions you can take right now to support my work:

1. Give the story a CLAP 👏 and leave a COMMENT 📫 with your thoughts

2. FOLLOW me to get notified of new stories ⏰

3. SHARE and recommend this story on your social media 🐦

Computer Science
Computer Science Theory
Software Engineering
Coding
Recommended from ReadMedium