Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update I1 and I2 to have interaction patterns #165

Open
wants to merge 10 commits into
base: gh-pages
Choose a base branch
from
130 changes: 108 additions & 22 deletions module1/projects/connect_four/iteration_1.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
layout: page
title: Iteration 1 - Game Board
title: Iteration 1 - Cell and Board Render
---

_[Back to Connect Four Home](./index)_
Expand All @@ -10,30 +10,116 @@ _[Back to Requirements](./requirements)_

In this iteration, you are required to use TDD to create your classes. Use the interaction pattern to determine what a method should do and write one or more tests to verify that expected behavior. Then you can implement the method. You should always write code with the purpose of making a test pass.

## Printing the Board
## Cell

When a user runs the command to start the game, they will see a welcome message, followed by an empty board. The board itself will represent empty spaces with periods and column names with a letter A-G.
A Cell object represents the space where a chip could be placed on the Connect 4 board. We will be able to read it's column letter and row number, as well as it's display value. It will also have behavior to fill in the cell with a new value.
abdulredd marked this conversation as resolved.
Show resolved Hide resolved

```
ABCDEFG
.......
.......
.......
.......
.......
.......
The Cell class should follow this interaction pattern:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The Cell class should follow this interaction pattern:
The `Cell` class should follow this interaction pattern:


```ruby
pry(main)> require './lib/cell'
# => true
pry(main)> a1 = Cell.new("A1")
# => #<Cell:0x000000014a232490 @column="A", @filled=false, @placement="A1", @row=1, @value=".">
pry(main)> b3 = Cell.new("B3")
# => #<Cell:0x000000014a29b080 @column="B", @filled=false, @placement="B3", @row=3, @value=".">
pry(main)> a1.placement
# => "A1"
pry(main)> a1.column
# => "A"
pry(main)> a1.row
# => 1
pry(main)> a1.value
# => "."
pry(main)> a1.filled?
# => false
pry(main)> a1.fill("X")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When calling Cell#fill are we expecting it to return the value or just perform the fill and we can get the value with a call to Cell#value? If it is the latter then the interaction pattern would need to be updated.

# => "X"
pry(main)> a1.value
# => "X"
pry(main)> a1.filled?
# => true
pry(main)> b3.fill("O")
# => "O"
pry(main)> b3.value
# => "O"
pry(main)> b3.filled?
# => true
```

Player pieces will be represented by X's, while computer pieces will be represented by O's. A board later in the game might look something like the following:
## Board

```
ABCDEFG
.......
.......
O......
X.O...O
XXOX..X
XOOXOOX
```
The Board class is responsible for keeping track of each cell on the board and validating 4 in a row.

For Iteration 1, students should have a program that will print out a welcome message and an empty board.
Follow the interaction pattern below to build out the board's display:

### Board Display

```ruby
pry(main)> require './lib/cell'
# => true
pry(main)> require './lib/board'
# => true
pry(main)> a_cells = [Cell.new("A1"),Cell.new("A2"),Cell.new("A3"),Cell.new("A4"),Cell.new("A5"),Cell.new("A6")]
pry(main)> b_cells = [Cell.new("B1"),Cell.new("B2"),Cell.new("B3"),Cell.new("B4"),Cell.new("B5"),Cell.new("B6")]
pry(main)> c_cells = [Cell.new("C1"),Cell.new("C2"),Cell.new("C3"),Cell.new("C4"),Cell.new("C5"),Cell.new("C6")]
pry(main)> d_cells = [Cell.new("D1"),Cell.new("D2"),Cell.new("D3"),Cell.new("D4"),Cell.new("D5"),Cell.new("D6")]
pry(main)> e_cells = [Cell.new("E1"),Cell.new("E2"),Cell.new("E3"),Cell.new("E4"),Cell.new("E5"),Cell.new("E6")]
pry(main)> f_cells = [Cell.new("F1"),Cell.new("F2"),Cell.new("F3"),Cell.new("F4"),Cell.new("F5"),Cell.new("F6")]
pry(main)> g_cells = [Cell.new("G1"),Cell.new("G2"),Cell.new("G3"),Cell.new("G4"),Cell.new("G5"),Cell.new("G6")]
pry(main)> columns = {A: a_cells, B: b_cells, C: c_cells, D: d_cells, E: e_cells, F: f_cells, G: g_cells}
pry(main)> board = Board.new(columns)
# => #<Board:0x0000000138046418 @columns= {.....}>
pry(main)> board.columns
# => {:A=>
[#<Cell:0x000000012d347e38 @value=".", @filled=false, @column="A", @placement="A1", @row=1>,
#<Cell:0x000000012d347d70 @value=".", @filled=false, @column="A", @placement="A2", @row=2>,
#<Cell:0x000000012d347cd0 @value=".", @filled=false, @column="A", @placement="A3", @row=3>,
#<Cell:0x000000012d347c08 @value=".", @filled=false, @column="A", @placement="A4", @row=4>,
#<Cell:0x000000012d347b40 @value=".", @filled=false, @column="A", @placement="A5", @row=5>,
#<Cell:0x000000012d347a78 @value=".", @filled=false, @column="A", @placement="A6", @row=6>],
:B=>
[#<Cell:0x000000012d385940 @value=".", @filled=false, @column="B", @placement="B1", @row=1>,
#<Cell:0x000000012d385710 @value=".", @filled=false, @column="B", @placement="B2", @row=2>,
#<Cell:0x000000012d385558 @value=".", @filled=false, @column="B", @placement="B3", @row=3>,
#<Cell:0x000000012d3853f0 @value=".", @filled=false, @column="B", @placement="B4", @row=4>,
#<Cell:0x000000012d3851c0 @value=".", @filled=false, @column="B", @placement="B5", @row=5>,
#<Cell:0x000000012d3850f8 @value=".", @filled=false, @column="B", @placement="B6", @row=6>],
:C=>
[#<Cell:0x000000012d3a6eb0 @value=".", @filled=false, @column="C", @placement="C1", @row=1>,
#<Cell:0x000000012d3a6de8 @value=".", @filled=false, @column="C", @placement="C2", @row=2>,
#<Cell:0x000000012d3a6cf8 @value=".", @filled=false, @column="C", @placement="C3", @row=3>,
#<Cell:0x000000012d3a6c08 @value=".", @filled=false, @column="C", @placement="C4", @row=4>,
#<Cell:0x000000012d3a6b40 @value=".", @filled=false, @column="C", @placement="C5", @row=5>,
#<Cell:0x000000012d3a6aa0 @value=".", @filled=false, @column="C", @placement="C6", @row=6>],
:D=>
[#<Cell:0x000000012d0f95c8 @value=".", @filled=false, @column="D", @placement="D1", @row=1>,
#<Cell:0x000000012d0f8218 @value=".", @filled=false, @column="D", @placement="D2", @row=2>,
#<Cell:0x000000012d0f3b00 @value=".", @filled=false, @column="D", @placement="D3", @row=3>,
#<Cell:0x000000012d0f26d8 @value=".", @filled=false, @column="D", @placement="D4", @row=4>,
#<Cell:0x000000012d0f25c0 @value=".", @filled=false, @column="D", @placement="D5", @row=5>,
#<Cell:0x000000012d0f22c8 @value=".", @filled=false, @column="D", @placement="D6", @row=6>],
:E=>
[#<Cell:0x000000012d20c898 @value=".", @filled=false, @column="E", @placement="E1", @row=1>,
#<Cell:0x000000012d20c028 @value=".", @filled=false, @column="E", @placement="E2", @row=2>,
#<Cell:0x000000012d207e88 @value=".", @filled=false, @column="E", @placement="E3", @row=3>,
#<Cell:0x000000012d207ca8 @value=".", @filled=false, @column="E", @placement="E4", @row=4>,
#<Cell:0x000000012d207578 @value=".", @filled=false, @column="E", @placement="E5", @row=5>,
#<Cell:0x000000012d206790 @value=".", @filled=false, @column="E", @placement="E6", @row=6>],
:F=>
[#<Cell:0x000000012d275820 @value=".", @filled=false, @column="F", @placement="F1", @row=1>,
#<Cell:0x000000012d26ff38 @value=".", @filled=false, @column="F", @placement="F2", @row=2>,
#<Cell:0x000000012d26fd80 @value=".", @filled=false, @column="F", @placement="F3", @row=3>,
#<Cell:0x000000012d26f650 @value=".", @filled=false, @column="F", @placement="F4", @row=4>,
#<Cell:0x000000012d26ecf0 @value=".", @filled=false, @column="F", @placement="F5", @row=5>,
#<Cell:0x000000012d26e778 @value=".", @filled=false, @column="F", @placement="F6", @row=6>],
:G=>
[#<Cell:0x000000012d2cee20 @value=".", @filled=false, @column="G", @placement="G1", @row=1>,
#<Cell:0x000000012d2cec18 @value=".", @filled=false, @column="G", @placement="G2", @row=2>,
#<Cell:0x000000012d2ce970 @value=".", @filled=false, @column="G", @placement="G3", @row=3>,
#<Cell:0x000000012d2ce718 @value=".", @filled=false, @column="G", @placement="G4", @row=4>,
#<Cell:0x000000012d2ce010 @value=".", @filled=false, @column="G", @placement="G5", @row=5>,
#<Cell:0x000000012d2cda70 @value=".", @filled=false, @column="G", @placement="G6", @row=6>]}
pry(main)> board.render_board
# => "A B C D E F G\n. . . . . . .\n. . . . . . .\n. . . . . . .\n. . . . . . .\n. . . . . . .\n. . . . . . ."
```
152 changes: 138 additions & 14 deletions module1/projects/connect_four/iteration_2.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
layout: page
title: Iteration 2 - Placing Pieces
title: Iteration 2 - Placing Chips and Validating Four Across
---

_[Back to Connect Four Home](./index)_
Expand All @@ -10,24 +10,148 @@ _[Back to Requirements](./requirements)_

In this iteration, you are required to use TDD to create your classes. Use the interaction pattern to determine what a method should do and write one or more tests to verify that expected behavior. Then you can implement the method. You should always write code with the purpose of making a test pass.

## Placing Pieces
## Board

Update your program to request user input and allow them to place an individual piece.
The Board class is responsible for keeping track of each cell on the board and validating 4 in a row.

Your program should ask the user to enter a letter A-G.
Update the board to display the player's piece in the lowest available position of the selected column with an 'X'.
Follow the interaction pattern below to build out the functionality for placing a chip on the board:

The computer takes its turn by selecting one of the 7 columns at random. Update the board to display the computer's piece in the lowest available position of the selected column with an 'O'.

The player and computer should be able to repeat this sequence and continue taking turns.
### Place Chip On Board

### Invalid Column Selection
```ruby
pry(main)> require './lib/cell'
# => true
pry(main)> require './lib/board'
# => true
pry(main)> a_cells = [Cell.new("A1"),Cell.new("A2"),Cell.new("A3"),Cell.new("A4"),Cell.new("A5"),Cell.new("A6")]
pry(main)> b_cells = [Cell.new("B1"),Cell.new("B2"),Cell.new("B3"),Cell.new("B4"),Cell.new("B5"),Cell.new("B6")]
pry(main)> c_cells = [Cell.new("C1"),Cell.new("C2"),Cell.new("C3"),Cell.new("C4"),Cell.new("C5"),Cell.new("C6")]
pry(main)> d_cells = [Cell.new("D1"),Cell.new("D2"),Cell.new("D3"),Cell.new("D4"),Cell.new("D5"),Cell.new("D6")]
pry(main)> e_cells = [Cell.new("E1"),Cell.new("E2"),Cell.new("E3"),Cell.new("E4"),Cell.new("E5"),Cell.new("E6")]
pry(main)> f_cells = [Cell.new("F1"),Cell.new("F2"),Cell.new("F3"),Cell.new("F4"),Cell.new("F5"),Cell.new("F6")]
pry(main)> g_cells = [Cell.new("G1"),Cell.new("G2"),Cell.new("G3"),Cell.new("G4"),Cell.new("G5"),Cell.new("G6")]
pry(main)> columns = {A: a_cells, B: b_cells, C: c_cells, D: d_cells, E: e_cells, F: f_cells, G: g_cells}
pry(main)> board = Board.new(columns)
pry(main)> board.place_chip("A", "X")
pry(main)> board.render_board
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this and the following board.render_board calls are meant to be board.render to match I1.

# => "A B C D E F G\n. . . . . . .\n. . . . . . .\n. . . . . . .\n. . . . . . .\n. . . . . . .\nX . . . . . ."
pry(main)> board.place_chip("A", "O")
pry(main)> board.render_board
# => "A B C D E F G\n. . . . . . .\n. . . . . . .\n. . . . . . .\n. . . . . . .\nO . . . . . .\nX . . . . . ."
pry(main)> board.place_chip("D", "X")
pry(main)> board.render_board
# => "A B C D E F G\n. . . . . . .\n. . . . . . .\n. . . . . . .\n. . . . . . .\nO . . . . . .\nX . . X . . ."
pry(main)> board.place_chip("C", "O")
pry(main)> board.render_board
# => "A B C D E F G\n. . . . . . .\n. . . . . . .\n. . . . . . .\n. . . . . . .\nO . . . . . .\nX . O X . . ."

Neither the player nor computer should be able to play in an invalid column. An invalid column is defined as one of the following:
1. Outside the range A-G
1. Full, i.e. there is no available position in the column
```

If an invalid column is selected by the player, the program should display an error message and ask the player to select a valid column. The program should repeat this process until a valid column is selected.
* The one exception is when there are no valid columns available; i.e. the game board is full. In this case, the game is a draw, an endgame condition.

If an invalid column is selected by the computer, the program should repeat until a valid column is selected. No error message should display to the user when the computer selects an invalid column.
### Validate 4 Across

```ruby
pry(main)> require './lib/cell'
# => true
pry(main)> require './lib/board'
# => true
pry(main)> a_cells = [Cell.new("A1"),Cell.new("A2"),Cell.new("A3"),Cell.new("A4"),Cell.new("A5"),Cell.new("A6")]
pry(main)> b_cells = [Cell.new("B1"),Cell.new("B2"),Cell.new("B3"),Cell.new("B4"),Cell.new("B5"),Cell.new("B6")]
pry(main)> c_cells = [Cell.new("C1"),Cell.new("C2"),Cell.new("C3"),Cell.new("C4"),Cell.new("C5"),Cell.new("C6")]
pry(main)> d_cells = [Cell.new("D1"),Cell.new("D2"),Cell.new("D3"),Cell.new("D4"),Cell.new("D5"),Cell.new("D6")]
pry(main)> e_cells = [Cell.new("E1"),Cell.new("E2"),Cell.new("E3"),Cell.new("E4"),Cell.new("E5"),Cell.new("E6")]
pry(main)> f_cells = [Cell.new("F1"),Cell.new("F2"),Cell.new("F3"),Cell.new("F4"),Cell.new("F5"),Cell.new("F6")]
pry(main)> g_cells = [Cell.new("G1"),Cell.new("G2"),Cell.new("G3"),Cell.new("G4"),Cell.new("G5"),Cell.new("G6")]
pry(main)> columns = {A: a_cells, B: b_cells, C: c_cells, D: d_cells, E: e_cells, F: f_cells, G: g_cells}
pry(main)> board = Board.new(columns)
pry(main)> c3 = board.columns[:C][2]
pry(main)> e2 = board.columns[:E][1]
pry(main)> board.row_for(c3)
# => [#<Cell:0x0000000130333cc8 @column="A", @filled=false, @placement="A3", @row=3, @value=".">,
#<Cell:0x0000000130333bd8 @column="B", @filled=false, @placement="B3", @row=3, @value=".">,
#<Cell:0x0000000130333ae8 @column="C", @filled=false, @placement="C3", @row=3, @value=".">,
#<Cell:0x00000001303339f8 @column="D", @filled=false, @placement="D3", @row=3, @value=".">,
#<Cell:0x0000000130333908 @column="E", @filled=false, @placement="E3", @row=3, @value=".">,
#<Cell:0x0000000130333818 @column="F", @filled=false, @placement="F3", @row=3, @value=".">,
#<Cell:0x0000000130333728 @column="G", @filled=false, @placement="G3", @row=3, @value=".">]
pry(main)> board.row_for(e2)
# => [#<Cell:0x0000000130228e50 @column="A", @filled=false, @placement="A2", @row=2, @value=".">,
#<Cell:0x0000000130228b08 @column="B", @filled=false, @placement="B2", @row=2, @value=".">,
#<Cell:0x0000000130228518 @column="C", @filled=false, @placement="C2", @row=2, @value=".">,
#<Cell:0x0000000130228248 @column="D", @filled=false, @placement="D2", @row=2, @value=".">,
#<Cell:0x0000000130333f98 @column="E", @filled=false, @placement="E2", @row=2, @value=".">,
#<Cell:0x0000000130333ea8 @column="F", @filled=false, @placement="F2", @row=2, @value=".">,
#<Cell:0x0000000130333db8 @column="G", @filled=false, @placement="G2", @row=2, @value=".">]
pry(main)> board.column_for(c3)
# => [#<Cell:0x000000013022b100 @column="C", @filled=false, @placement="C1", @row=1, @value=".">,
#<Cell:0x0000000130228518 @column="C", @filled=false, @placement="C2", @row=2, @value=".">,
#<Cell:0x0000000130333ae8 @column="C", @filled=false, @placement="C3", @row=3, @value=".">,
#<Cell:0x0000000130333458 @column="C", @filled=false, @placement="C4", @row=4, @value=".">,
#<Cell:0x0000000130332dc8 @column="C", @filled=false, @placement="C5", @row=5, @value=".">,
#<Cell:0x0000000130332738 @column="C", @filled=false, @placement="C6", @row=6, @value=".">]
pry(main)> board.column_for(e2)
# => [#<Cell:0x000000013022a520 @column="E", @filled=false, @placement="E1", @row=1, @value=".">,
#<Cell:0x0000000130333f98 @column="E", @filled=false, @placement="E2", @row=2, @value=".">,
#<Cell:0x0000000130333908 @column="E", @filled=false, @placement="E3", @row=3, @value=".">,
#<Cell:0x0000000130333278 @column="E", @filled=false, @placement="E4", @row=4, @value=".">,
#<Cell:0x0000000130332be8 @column="E", @filled=false, @placement="E5", @row=5, @value=".">,
#<Cell:0x0000000130332558 @column="E", @filled=false, @placement="E6", @row=6, @value=".">]
pry(main)> board.diagonal_for(c3)
Copy link
Contributor

@abdulredd abdulredd Aug 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question about Board#diagonal_for ... is it only expected that this method returns diagonals from top left to bottom right and not bottom left to top right?

# => [#<Cell:0x0000000130328058 @column="A", @filled=false, @placement="A1", @row=1, @value=".">,
#<Cell:0x0000000130228b08 @column="B", @filled=false, @placement="B2", @row=2, @value=".">,
#<Cell:0x0000000130333ae8 @column="C", @filled=false, @placement="C3", @row=3, @value=".">,
#<Cell:0x0000000130333368 @column="D", @filled=false, @placement="D4", @row=4, @value=".">,
#<Cell:0x0000000130332be8 @column="E", @filled=false, @placement="E5", @row=5, @value=".">,
#<Cell:0x0000000130332468 @column="F", @filled=false, @placement="F6", @row=6, @value=".">]
pry(main)> board.diagonal_for(e2)
# => [#<Cell:0x000000013022a9f8 @column="D", @filled=false, @placement="D1", @row=1, @value=".">,
#<Cell:0x0000000130333f98 @column="E", @filled=false, @placement="E2", @row=2, @value=".">,
#<Cell:0x0000000130333818 @column="F", @filled=false, @placement="F3", @row=3, @value=".">,
#<Cell:0x0000000130333098 @column="G", @filled=false, @placement="G4", @row=4, @value=".">]


# Check for connect 4 in a column:
pry(main)> a1 = board.columns[:A][0]
pry(main)> a2 = board.columns[:A][1]
pry(main)> a3 = board.columns[:A][2]
pry(main)> a4 = board.columns[:A][3]
pry(main)> column_a = board.column_for(a1) # we could have also used any cell from column A here.
pry(main)> a1.fill("X")
pry(main)> a2.fill("X")
pry(main)> a3.fill("X")
pry(main)> board.check_for_four(column_a)
# => false
pry(main)> a4.fill("X")
pry(main)> board.check_for_four(column_a)
# => true

# Check for connect 4 in a row:
pry(main)> b1 = board.columns[:B][0]
pry(main)> c1 = board.columns[:C][0]
pry(main)> d1 = board.columns[:D][0]
pry(main)> e1 = board.columns[:E][0]
pry(main)> b1.fill("O")
pry(main)> c1.fill("O")
pry(main)> d1.fill("O")
pry(main)> row_1 = board.row_for(e1) # we could have also used any cell from row 1 here.
pry(main)> board.check_for_four(row_1)
# => false
pry(main)> e1.fill("O")
pry(main)> board.check_for_four(row_1)
# => true

# Check for connect 4 in a diagonal:
pry(main)> b2 = board.columns[:B][1]
pry(main)> c3 = board.columns[:C][2]
pry(main)> d4 = board.columns[:D][3]
pry(main)> b2.fill("X")
pry(main)> c3.fill("X")
pry(main)> diagonal = board.diagonal_for(d4) # we could have also used any cell that would have been on this diagonal.
pry(main)> board.check_for_four(diagonal)
# => false
pry(main)> d4.fill("X")
pry(main)> board.check_for_four(diagonal) #note: a1 was already filled in with "X" earlier in this interaction pattern
# => true
```

Loading