PH:S\Computer Science\> ...

Design and decomposition

Top-down design and decomposition

Top-down design and decomposition is a simple and effective development strategy for projects of any size from a single algorithms to full applications. Start with the ultimate goal and keep breaking it down (decomposing it) into smaller problems until you can solve the small problems and combine them to complete the ultimate goal

  1. Clearly state the problem (or objective or project)
  2. Break the problem into the next largest logical pieces
    • This could be a list for simpler problems or a diagram for complex problems
    • When working in code, these should become comments, functions, objects, and classes
  3. Repeat for each of those pieces, and the next pieces, until the problems are small enough to code a solution
  4. Work your way back up completing each of the pieces

It's very much analagous to building something out of legos where you also get to design the pieces.

Below is an example of using this process to build a web-based War card game. War Card Game Repository on Github

War Card Game Example - 1st iteration of process

Task: A web-based War card game player vs. computer

Features and requirements (logical pieces)

War Card Game Example - 2nd iteration

Task: Game works and follows War rules (this is one of the first two pieces)

Requirements

At this point, I'm ready to move to coding. To do that, I will start by outlining these requirements with comments and naming functions to actually carry out the steps. These are just initial ideas and may need to change as the project progresses and I develop a better understanding of how it should work

/** War game */

// Simulate deck of shuffled cards
function shuffle() {

}

// Split deck into player and computer hands
function splitDeck() {

}

// Player plays a card
function playerPick() {

}

// Computer plays a card automatically after player
function computerPick() {

}

// Check who won the round
function getRoundWinner() {

}

// Add cards to the loser's deck
function giveCardsToLoser() {

}

// Add points to winner's score
function addPoints() {

}

// Determine winner of game
function getGameWinner() {

}
      
More [+]

War Card Game Example - 3rd iteration

Task: Simulate a deck of cards (seems like the most logical place to start)

Requirements

These are small enough that I can see how to solve them. I will use comments and try to give things descriptive names.

Solution to first two requirements

/** War game */

/*** Simulate deck of shuffled cards */
// Each card will be a string like "2H" for 2 of hearts
// A global array is a good way to store the shuffled deck
let deck = [];

// Rather than list all 52 cards, I will combine values from two arrays to make each card string
// card = values[i] + suits[j]
const suits = ["H", "C", "S", "D"];
const values = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"];

Solution to third requirement

After testing, I realized that this algorithm puts duplicate cards in the array so I put a TODO comment to remind me to fix that

// Shuffle deck
function shuffle() {
  // Generate 52 random cards and add to the deck
  for (let n = 0; n < 52; n++) {
    // Pick rand num from 0 to 3 for suit index and pick random suit
    let rand = Math.floor(Math.random() * 4);
    let suit = suits[rand];

    // Pick rand num from 0 to 13 for value index and pick random value
    rand = Math.floor(Math.random() * 13);
    value = values[rand];

    // Concatenate strings to make a card like "QD"
    let card = value + suit;

    // Add card to deck list
    deck.push(card); // TODO: check for duplicates, don't want two of the same card

    // repeat 52 times for full deck
  }
}

// Test by printing deck to console after calling shuffle()
shuffle();
console.log(deck);
More [+]

War Card Game - 4th iteration

Task: To fill deck with random cards without duplicates

// Shuffle deck
function shuffle() {
  // Generate 52 random cards and add to the deck
  // Clear the deck
  deck = [];
  for (let n = 0; n < 52; n++) {
    // Pick rand num from 0 to 3 for suit index and pick random suit
    let rand = Math.floor(Math.random() * 4);
    let suit = suits[rand];

    // Pick rand num from 0 to 13 for value index and pick random value
    rand = Math.floor(Math.random() * 13);
    value = values[rand];

    // Concatenate strings to make a card like "QD"
    let card = value + suit;

    // Add card to deck list
    // Only add card to deck if it isn't already there
    if (deck.indexOf(card) >= 0) {
      // Card is on the list already
      // Decrement n because the card shouldn't be counted
      n--;
    }
    else {
      deck.push(card);
    }

    // repeat 52 times for full deck
  }
}

// Test by printing deck to console after calling shuffle()
shuffle();
console.log(deck);
More [+]

War Card Game - 5th iteration

Tasks: 1. Simulate the player's hand, 2. Simulate computer's hand, 3. Simulate discard pile

Requirements

// Global arrays representing the different decks to hold the strings representing the cards
let playerHand = [];
let compHand = [];
let discardPile = [];

This algorithm to split the cards is equivalent to "cutting" the deck exactly in half

// Split deck into player and computer hands
function splitDeck() {
  // Clear the player's hand to start clean
  playerHand = [];
  
  // Put the first half of the deck in the player's hand
  for (let i = 0; i < deck.length / 2; i++){
    playerHand.push(deck[i]);
  }

  // Clear the computer's hand
  compHand = [];

  // Put the second half in the computer's hand
  for (let i = deck.length / 2; i < deck.length; i++){
    compHand.push(deck[i]);
  }
}

// Test split deck
shuffle();
splitDeck();
console.log(playerHand);
console.log(compHand);
      
More [+]

War Card Game - 6th iteration

Task: Graphic UI
I am to the point in the script where the next logical step is to start putting together the user interface and developing the actual gameplay.

Requirements

Animations and messages needs to be broken down further, but I will create basic versions of the other requirements in this step and refine them later.

I used divs to represent the basic elements of the game and named each element I anticipate needing to find in JavaScript.

<body>
<header>
  <h1>War</h1>
  </header>

  <main>
    <div id="game-area">
      <div id="player-deck" onclick="playerPick()" class="card-back">
        + +<br>+ +
        </div>
      <div id="player-card" class="card-front">
        <h3 id="player-card-value">3</h3>
      </div>

      <div id="comp-card" class="card-front">
        <h3 id="comp-card-value">5</h3>
      </div>
      
      <div id="comp-deck" class="card-back">
        + +<br>+ +
      </div>

    </div>>
    <button id="new-button" class="card-back" onclick="start()">Deal</button>
  </main>
</body>

Some CSS styles to make it look somewhat like cards.

body {
  margin: 0px;
  background-color: green;
}

h1 {
  font-size: 60px;
  color: red;
  text-align: center;
}

#game-area {
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  padding: 20px;
}

#new-button {
  font-size: 60px;
  margin: 40px auto;
}

.card-front,
.card-back, .card-empty {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 200px;
  height: 300px;
  font-size: 100px;
  border: 1px solid black;
  border-radius: 10px;
}

.card-front {
  background-color: white;
}

.card-empty {
  background-color: inherit;
}

.card-back {
  background-color: darkblue;
  color: cornflowerblue;
}

#new-button:hover, #player-deck:hover {
  border: 2px solid cornflowerblue;
  cursor: pointer;
}

Screenshot of user interface

War card game UI screenshot
More [+]

War Card Game - 7th iteration

Task: Player can play their next card

Requirements

// Player picks a card - this will be triggered from an onclick event
function playerPick() {
  // Pick next card from player deck
  playerCard = playerHand.pop();

  // Update UI
  // Get card value and suit from string
  let value = "", suit = "";
  if (playerCard.length == 3) {
    // 10 cards take two characters for a total of 3 with the suit
    value = playerCard.substring(0, 2);
    suit = playerCard.substring(2, 3);
  }
  else {
    value = playerCard.substring(0, 1);
    suit = playerCard.substring(1, 2);
  }
  // Testing that value and suit values are correctly found
  console.log(value + " of " + suit);

  // Set properties on player card element
  let valueElement = document.getElementById("player-card-value");
  valueElement.innerHTML = value;
  if (suit == "H" || suit == "D") {
    valueElement.style.color = "red";
  } else {
    valueElement.style.color = "black";
  }

  // TODO: Set suit image

  // Trigger computer move
  computerPick();
}
      
More [+]

War Card Game - 8th iteration

Task: Computer automatically plays card

Requirements

Call the computerPick() function at the end of the playerPick() function

function playerPick() {
  /* other code not shown */

  // Trigger computer move
  computerPick();
}

Computer card pick algorithm is essentially the same as the algorithm for the playerPick() function.

// Computer picks a card
function computerPick() {
  // Pick next card from comp deck
  compCard = compHand.pop();

  // Update UI
  // Get card value and suit from string same algorithm as in playerPick()
  let value = "", suit = "";
  if (compCard.length == 3) {
    value = compCard.substring(0, 2);
    suit = compCard.substring(2, 3);
  }
  else {
    value = compCard.substring(0, 1);
    suit = compCard.substring(1, 2);
  }

  // Set properties on player card element
  let valueElement = document.getElementById("comp-card-value");
  valueElement.innerHTML = value;
  if (suit == "H" || suit == "D") {
    valueElement.style.color = "red";
  } else {
    valueElement.style.color = "black";
  }

  // TODO: Set suit image 
}
More [+]

War Card Game - 9th iteration

Task: Determine winner of round

Requirements

More [+]