Skip to content

Commit

Permalink
word search
Browse files Browse the repository at this point in the history
  • Loading branch information
ZacharyPatten committed Dec 12, 2023
1 parent 18404e9 commit cfc78d1
Show file tree
Hide file tree
Showing 12 changed files with 902 additions and 259 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/Word Search Build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Word Search Build
on:
push:
paths:
- 'Projects/Word Search/**'
- '!**.md'
pull_request:
paths:
- 'Projects/Word Search/**'
- '!**.md'
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x
- run: dotnet build "Projects\Word Search\Word Search.csproj" --configuration Release
10 changes: 10 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,16 @@
"console": "externalTerminal",
"stopAtEntry": false,
},
{
"name": "Word Search",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build Word Search",
"program": "${workspaceFolder}/Projects/Word Search/bin/Debug/Word Search.dll",
"cwd": "${workspaceFolder}/Projects/Word Search/bin/Debug",
"console": "externalTerminal",
"stopAtEntry": false,
},
{
"name": "Pong",
"type": "coreclr",
Expand Down
13 changes: 13 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,19 @@
],
"problemMatcher": "$msCompile",
},
{
"label": "Build Word Search",
"command": "dotnet",
"type": "process",
"args":
[
"build",
"${workspaceFolder}/Projects/Word Search/Word Search.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
],
"problemMatcher": "$msCompile",
},
{
"label": "Build Solution",
"command": "dotnet",
Expand Down
225 changes: 225 additions & 0 deletions Projects/Website/Games/Word Search/Word Search.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Website.Games.Word_Search;

public class Word_Search
{
public readonly BlazorConsole Console = new();

public async Task Run()
{
char[,] board = new char[20, 20];
List<(int Left, int Top)> showWordSelections = [];
List<(int Left, int Top)> selections = [];

string[] wordArray = default!;
string currentWord = default!;
(int Left, int Top) cursor = (0, 0);

InitializeWords();
PlayAgain:
InitializeBoard();
await Console.Clear();
while (true)
{
await RenderBoard();
await Console.Write($"""
Highlight the word "{currentWord}" above.
Controls:
- arrow keys: move cursor
- enter: highlight characters
- backspace: clear highlighted characters
- home: new word search
- end: give up and show word
- escape: close game
""");
await Console.SetCursorPosition(2 * cursor.Left, cursor.Top);
Console.CursorVisible = true;
switch ((await Console.ReadKey(true)).Key)
{
case ConsoleKey.LeftArrow: cursor.Left = cursor.Left <= 0 ? board.GetLength(0) - 1 : cursor.Left - 1; break;
case ConsoleKey.RightArrow: cursor.Left = cursor.Left >= board.GetLength(0) - 1 ? 0 : cursor.Left + 1; break;
case ConsoleKey.UpArrow: cursor.Top = cursor.Top <= 0 ? board.GetLength(1) - 1 : cursor.Top - 1; break;
case ConsoleKey.DownArrow: cursor.Top = cursor.Top >= board.GetLength(1) - 1 ? 0 : cursor.Top + 1; break;
case ConsoleKey.Backspace: selections.Clear(); break;
case ConsoleKey.Home: goto PlayAgain;
case ConsoleKey.End:
selections.Clear();
selections.AddRange(showWordSelections);
await Console.Clear();
await RenderBoard();
await Console.Write($"""
Here is where "{currentWord}" was hiding.
Controls:
- enter/home: play again
- escape: close game
""");
while (true)
{
switch ((await Console.ReadKey(true)).Key)
{
case ConsoleKey.Enter or ConsoleKey.Home: goto PlayAgain;
case ConsoleKey.Escape: goto Close;
}
}
case ConsoleKey.Escape: goto Close;
case ConsoleKey.Enter:
if (!selections.Remove(cursor))
{
selections.Add(cursor);
selections.Sort();
if (UserFoundTheWord())
{
await Console.Clear();
await RenderBoard();
await Console.Write($"""
You found "{currentWord}"! You win!
Controls:
- enter/home: play again
- escape: close game
""");
while (true)
{
switch ((await Console.ReadKey(true)).Key)
{
case ConsoleKey.Enter or ConsoleKey.Home: goto PlayAgain;
case ConsoleKey.Escape: goto Close;
}
}
}
}
break;
}
}
Close:
await Console.Clear();
await Console.WriteLine("Word Search was closed.");
await Console.Refresh();

void InitializeWords()
{
wordArray = Resources.Words!.Select(word => word.ToUpper()).ToArray();
}

void InitializeBoard()
{
selections.Clear();

for (int i = 0; i < board.GetLength(1); i++)
{
for (int j = 0; j < board.GetLength(0); j++)
{
board[j, i] = (char)('A' + Random.Shared.Next(26));
}
}

currentWord = wordArray[Random.Shared.Next(wordArray.Length)];

// choose a random orientation for the word (down, right, left, up, down-right, down-left, up-right, or up-left)
bool r((int Left, int Top) location) => location.Left + currentWord.Length < board.GetLength(0);
bool d((int Left, int Top) location) => location.Top + currentWord.Length < board.GetLength(1);
bool l((int Left, int Top) location) => location.Left - currentWord.Length >= 0;
bool u((int Left, int Top) location) => location.Top - currentWord.Length >= 0;
bool dr((int Left, int Top) location) => d(location) && r(location);
bool dl((int Left, int Top) location) => d(location) && l(location);
bool ur((int Left, int Top) location) => u(location) && r(location);
bool ul((int Left, int Top) location) => u(location) && l(location);
(Func<(int Left, int Top), bool> Validator, (int Left, int Top) Adjustment) orientation = Random.Shared.Next(8) switch
{
0 => (d, (0, 1)),
1 => (r, (1, 0)),
2 => (u, (0, -1)),
3 => (l, (-1, 0)),
4 => (dr, (1, 1)),
5 => (dl, (-1, 1)),
6 => (ur, (1, -1)),
7 => (ul, (-1, -1)),
_ => throw new NotImplementedException(),
};

// choose a random starting location that is valid for the orientation
List<(int Left, int Top)> possibleLocations = [];
for (int i = 0; i < board.GetLength(1); i++)
{
for (int j = 0; j < board.GetLength(0); j++)
{
if (orientation.Validator((j, i)))
{
possibleLocations.Add((j, i));
}
}
}
(int Left, int Top) randomLocation = possibleLocations[Random.Shared.Next(possibleLocations.Count)];

showWordSelections.Clear();
for (int i = 0; i < currentWord.Length; i++)
{
showWordSelections.Add(randomLocation);
board[randomLocation.Left, randomLocation.Top] = currentWord[i];
randomLocation = (randomLocation.Left + orientation.Adjustment.Left, randomLocation.Top + orientation.Adjustment.Top);
}
}

async Task RenderBoard()
{
Console.CursorVisible = false;
await Console.SetCursorPosition(0, 0);
for (int i = 0; i < board.GetLength(1); i++)
{
for (int j = 0; j < board.GetLength(0); j++)
{
if (selections.Contains((j, i)))
{
(Console.ForegroundColor, Console.BackgroundColor) = (Console.BackgroundColor, Console.ForegroundColor);
}
await Console.Write(board[j, i]);
if (selections.Contains((j, i)))
{
(Console.ForegroundColor, Console.BackgroundColor) = (Console.BackgroundColor, Console.ForegroundColor);
}
if (j < board.GetLength(1) - 1)
{
await Console.Write(' ');
}
}
await Console.WriteLine();
}
}

bool UserFoundTheWord()
{
// make sure all the selections are in a straight line
if (selections.Count > 1)
{
(int Left, int Top) adjustment = (selections[1].Left - selections[0].Left, selections[1].Top - selections[0].Top);
if (adjustment.Left > 1 || adjustment.Left < -1 || adjustment.Top > 1 || adjustment.Top < -1)
{
return false;
}
for (int i = 2; i < selections.Count; i++)
{
if ((selections[i].Left - selections[i - 1].Left, selections[i].Top - selections[i - 1].Top) != adjustment)
{
return false;
}
}
}

char[] chars = selections.Select(location => board[location.Left, location.Top]).ToArray();
string charsString = new(chars);
Array.Reverse(chars);
string charsStringReverse = new(chars);
return charsString == currentWord || charsStringReverse == currentWord;
}

}
}
55 changes: 55 additions & 0 deletions Projects/Website/Pages/Word Search.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
@using System

@page "/Word Search"

<PageTitle>Word Search</PageTitle>

<h1>Wumpus&nbsp;World</h1>

<a href="https://github.com/dotnet/dotnet-console-games/tree/main/Projects/Word%20Search" alt="Go To Readme">
<img title="Go To Readme" alt="Go To Readme" src="https://raw.githubusercontent.com/dotnet/dotnet-console-games/main/.github/resources/readme-black.svg">
</a>

<div class="console-window text-center my-3" @onkeydown="@Console.OnKeyDown" tabindex="0">
<div class="d-inline-block bg-dark text-light border p-2 text-start shadow padding-0">
<pre class="console">
<code>@Console.State</code>
</pre>
</div>
<div>
<button class="btn btn-primary" @onclick="() => Console.EnqueueInput(ConsoleKey.UpArrow) ">↑</button>
<button class="btn btn-primary" @onclick="() => Console.EnqueueInput(ConsoleKey.DownArrow) ">↓</button>
<button class="btn btn-primary" @onclick="() => Console.EnqueueInput(ConsoleKey.LeftArrow) ">←</button>
<button class="btn btn-primary" @onclick="() => Console.EnqueueInput(ConsoleKey.RightArrow)">→</button>
<button class="btn btn-primary" @onclick="() => Console.EnqueueInput(ConsoleKey.Enter) ">enter</button>
<button class="btn btn-primary" @onclick="() => Console.EnqueueInput(ConsoleKey.Backspace) ">backspace</button>
<button class="btn btn-primary" @onclick="() => Console.EnqueueInput(ConsoleKey.Home) ">home</button>
<button class="btn btn-primary" @onclick="() => Console.EnqueueInput(ConsoleKey.End) ">end</button>
<button class="btn btn-primary" @onclick="() => Console.EnqueueInput(ConsoleKey.Escape) ">escape</button>
</div>
</div>

<div class="alert alert-secondary" role="alert">
&#9000; Keyboard input is supported if you <strong>click</strong> on the game.
</div>

<div class="alert alert-secondary" role="alert">
&#8635; You can restart the game by <strong>refreshing</strong> the page.
</div>

@code
{
Games.Word_Search.Word_Search Game;
BlazorConsole Console;

public Word_Search()
{
Game = new();
Console = Game.Console;
Console.WindowWidth = 60;
Console.WindowHeight = 31;
Console.TriggerRefresh = StateHasChanged;
}

protected override void OnInitialized() => InvokeAsync(Game.Run);
}
Loading

0 comments on commit cfc78d1

Please sign in to comment.