Go練習問題3-☆3:ナインゲームを作ろう

記事内に商品プロモーションを含む場合があります

Go言語の初心者向け問題3-☆3:ナインゲームを作ろう

<<前の問題 問題集Top 次の問題>>

Go練習問題3-☆3:ナインゲームを作ろう




ナインゲームを作成しましょう。

ナインゲームは、プレイヤーとコンピュータが順番に牌(1から9の数字)を出し合い、どちらの牌が大きいかを比較して得点を競うゲームです。

9回戦行われ、より多くの得点を獲得した方が勝者となります。プレイヤーは自分の手札から牌を選び、コンピュータはランダムで牌を選択します。

この問題の要件

以下の要件に従ってコードを完成させてください。

  • プレイヤーとコンピュータの持ち牌は、1から9までの数字が入った配列で管理すること。
  • 各回戦ごとにプレイヤーは持ち牌の中から1枚を選び、コンピュータはランダムで1枚を選択すること。
  • 両者が出した牌を比較し、大きい方がその数値分の得点を獲得すること。同点の場合は両者にその数値分の得点が入ること。
  • 9回戦終了後、合計得点を表示し、勝者を発表すること。
  • プレイヤーが出した牌やコンピュータが出した牌は、次の回戦で使用できないようにすること。
  • Go言語の標準ライブラリを使用し、fmtパッケージで結果を表示すること。

ただし、以下のような実行結果となるコードを書くこと。

*****↓↓正解コードの実行結果の例↓↓*****

ナインゲームを開始します!

【第1回戦】
プレイヤーの得点 : 0点
コンピュータの得点: 0点
☆プレイヤーの持ち牌⇒【1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9】
コンピュータの持ち牌⇒【1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9】
持ち牌の中から出す牌を選択してください > 5
プレイヤーの打牌:5 > 3:コンピュータの打牌
プレイヤーは5点獲得

【第2回戦】
プレイヤーの得点 : 5点
コンピュータの得点: 0点
☆プレイヤーの持ち牌⇒【1 ,2 ,3 ,4 ,- ,6 ,7 ,8 ,9】
コンピュータの持ち牌⇒【1 ,2 ,- ,4 ,5 ,6 ,7 ,8 ,9】
持ち牌の中から出す牌を選択してください > 
...
ゲーム終了!
プレイヤーの得点 : 18点
コンピュータの得点: 15点
プレイヤーの勝利です!

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。

1.import文
 1-1. fmtパッケージのインポート
 1-2. math/randパッケージのインポート
 1-3. strconvパッケージのインポート
 1-4. timeパッケージのインポート

2.displayTiles関数の定義
 2-1. プレイヤーとコンピュータの持ち牌を表示するための関数
 2-2. プレイヤーの持ち牌を整形して表示する
 2-3. コンピュータの持ち牌を整形して表示する

3.formatTiles関数の定義
 3-1. 配列の要素を整形して文字列に変換する
 3-2. 配列の要素をカンマ区切りにして結合する

4.displayScores関数の定義
 4-1. プレイヤーの得点を表示する
 4-2. コンピュータの得点を表示する

5.compareTiles関数の定義
 5-1. プレイヤーとコンピュータの打牌を比較する
 5-2. プレイヤーの打牌がコンピュータより大きい場合、プレイヤーが得点を獲得
 5-3. プレイヤーの打牌がコンピュータより小さい場合、コンピュータが得点を獲得
 5-4. 両者の打牌が同じ場合、両者が同じ得点を獲得

6.main関数の定義
 6-1. 乱数のシードを設定する
 6-2. プレイヤーとコンピュータの持ち牌を配列で宣言する
 6-3. プレイヤーとコンピュータの初期得点を0に設定する
 6-4. ゲーム開始メッセージを表示する
 6-5. 9回のラウンドをforループで処理する
  6-5-1. 現在のラウンドを表示する
  6-5-2. 両者の得点を表示する
  6-5-3. プレイヤーの持ち牌を表示する
  6-5-4. プレイヤーが出す牌を入力させる
  6-5-5. 無効な入力の場合は再入力を促す
  6-5-6. コンピュータがランダムに出す牌を選択する
  6-5-7. プレイヤーとコンピュータの打牌を “-” に置き換える
  6-5-8. compareTiles関数を呼び出して得点を計算する
 6-6. ゲーム終了メッセージを表示する
 6-7. 最終得点を表示する
 6-8. 勝敗を判定し、勝者を表示する

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"time"
)

// プレイヤーとコンピュータが持っている牌を表示する関数
func displayTiles(playerTiles, computerTiles [9]string) {
	fmt.Printf("☆プレイヤーの持ち牌⇒【%s】\n", formatTiles(playerTiles))
	fmt.Printf("コンピュータの持ち牌⇒【%s】\n", formatTiles(computerTiles))
}

// 配列を表示用に整形する関数
func formatTiles(tiles [9]string) string {
	result := ""
	for i, tile := range tiles {
		if i > 0 {
			result += " ,"
		}
		result += tile
	}
	return result
}

// プレイヤーとコンピュータの得点を表示する関数
func displayScores(playerScore, computerScore int) {
	fmt.Printf("プレイヤーの得点 : %d点\n", playerScore)
	fmt.Printf("コンピュータの得点: %d点\n", computerScore)
}

// プレイヤーとコンピュータの打牌を比較し、得点を計算する関数
func compareTiles(playerTile, computerTile int) (int, int) {
	fmt.Printf("プレイヤーの打牌:%d ", playerTile)

	/* 【穴埋め問題1】 ここに、プレイヤーとコンピュータの牌の比較と得点を計算するコードを書いてください。 */
}

func main() {
	// 乱数のシードを設定
	rand.Seed(time.Now().UnixNano())

	// プレイヤーとコンピュータの持ち牌を配列で表現
	playerTiles := [9]string{"1", "2", "3", "4", "5", "6", "7", "8", "9"}
	computerTiles := [9]string{"1", "2", "3", "4", "5", "6", "7", "8", "9"}
	playerScore, computerScore := 0, 0

	fmt.Println("ナインゲームを開始します!")

	for round := 1; round <= 9; round++ {
		// 現在のラウンドを表示
		fmt.Printf("\n【第%d回戦】\n", round)

		// 両者の得点を表示
		displayScores(playerScore, computerScore)

		// 両者の持ち牌を表示
		displayTiles(playerTiles, computerTiles)

		// プレイヤーが出す牌を入力
		var playerChoiceStr string
		var playerChoice int

		/* 【穴埋め問題2】 ここに、プレイヤーの入力を受け取り正しい牌を選択するコードを書いてください。 */

		// コンピュータが出す牌をランダムに選択
		var computerChoice int
		for {
			computerChoice = rand.Intn(9) + 1
			if computerTiles[computerChoice-1] != "-" {
				break
			}
		}

		// 出した牌を "-" で表示
		playerTiles[playerChoice-1] = "-"
		computerTiles[computerChoice-1] = "-"

		// プレイヤーとコンピュータの得点を更新
		pScore, cScore := compareTiles(playerChoice, computerChoice)
		playerScore += pScore
		computerScore += cScore
	}

	// 最終的な得点を表示
	fmt.Println("\nゲーム終了!")
	displayScores(playerScore, computerScore)

	/* 【穴埋め問題3】 ここに、勝者を表示するコードを書いてください。 */
}

 

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

解答例と解説

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"time"
)

// プレイヤーとコンピュータが持っている牌を表示する関数
func displayTiles(playerTiles, computerTiles [9]string) {
	fmt.Printf("☆プレイヤーの持ち牌⇒【%s】\n", formatTiles(playerTiles))
	fmt.Printf("コンピュータの持ち牌⇒【%s】\n", formatTiles(computerTiles))
}

// 配列を表示用に整形する関数
func formatTiles(tiles [9]string) string {
	result := ""
	for i, tile := range tiles {
		if i > 0 {
			result += " ,"
		}
		result += tile
	}
	return result
}

// プレイヤーとコンピュータの得点を表示する関数
func displayScores(playerScore, computerScore int) {
	fmt.Printf("プレイヤーの得点 : %d点\n", playerScore)
	fmt.Printf("コンピュータの得点: %d点\n", computerScore)
}

// プレイヤーとコンピュータの打牌を比較し、得点を計算する関数
func compareTiles(playerTile, computerTile int) (int, int) {
	fmt.Printf("プレイヤーの打牌:%d ", playerTile)
	if playerTile > computerTile {
		fmt.Printf("> %d:コンピュータの打牌\n", computerTile)
		fmt.Printf("プレイヤーは%d点獲得\n", playerTile)
		return playerTile, 0
	} else if playerTile < computerTile {
		fmt.Printf("< %d:コンピュータの打牌\n", computerTile)
		fmt.Printf("コンピュータは%d点獲得\n", computerTile)
		return 0, computerTile
	} else {
		fmt.Printf("= %d:コンピュータの打牌\n", computerTile)
		fmt.Printf("両者は%d点獲得\n", playerTile)
		return playerTile, computerTile
	}
}

func main() {
	// 乱数のシードを設定
	rand.Seed(time.Now().UnixNano())

	// プレイヤーとコンピュータの持ち牌を配列で表現
	playerTiles := [9]string{"1", "2", "3", "4", "5", "6", "7", "8", "9"}
	computerTiles := [9]string{"1", "2", "3", "4", "5", "6", "7", "8", "9"}
	playerScore, computerScore := 0, 0

	fmt.Println("ナインゲームを開始します!")

	for round := 1; round <= 9; round++ {
		// 現在のラウンドを表示
		fmt.Printf("\n【第%d回戦】\n", round)

		// 両者の得点を表示
		displayScores(playerScore, computerScore)

		// 両者の持ち牌を表示
		displayTiles(playerTiles, computerTiles)

		// プレイヤーが出す牌を入力
		var playerChoiceStr string
		var playerChoice int
		for {
			fmt.Print("持ち牌の中から出す牌を選択してください > ")
			fmt.Scan(&playerChoiceStr)
			playerChoice, _ = strconv.Atoi(playerChoiceStr)
			if playerChoice >= 1 && playerChoice <= 9 && playerTiles[playerChoice-1] != "-" {
				break
			}
			fmt.Println("無効な入力です。もう一度選択してください。")
		}

		// コンピュータが出す牌をランダムに選択
		var computerChoice int
		for {
			computerChoice = rand.Intn(9) + 1
			if computerTiles[computerChoice-1] != "-" {
				break
			}
		}

		// 出した牌を "-" で表示
		playerTiles[playerChoice-1] = "-"
		computerTiles[computerChoice-1] = "-"

		// プレイヤーとコンピュータの得点を更新
		pScore, cScore := compareTiles(playerChoice, computerChoice)
		playerScore += pScore
		computerScore += cScore
	}

	// 最終的な得点を表示
	fmt.Println("\nゲーム終了!")
	displayScores(playerScore, computerScore)

	// 勝者を表示
	if playerScore > computerScore {
		fmt.Println("プレイヤーの勝利です!")
	} else if playerScore < computerScore {
		fmt.Println("コンピュータの勝利です!")
	} else {
		fmt.Println("引き分けです!")
	}
}

正解コードの解説

ナインゲームのGoコードを初心者向けに解説します。

このコードは、プレイヤーとコンピュータが9つの牌を使って得点を競うシンプルなゲームです。

コード内で使われている基本的な文法や構造をブロックごとに解説していきます。

import 文とパッケージ宣言

package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"time"
)

最初に、プログラムの実行のために必要なパッケージをインポートしています。

fmt は標準出力に文字列や変数の内容を表示するため、math/rand はランダムな数値を生成するため、strconv は文字列を整数に変換するために使います。

time パッケージはランダムな数値を生成する際に乱数のシードとして使用します。

displayTiles 関数

func displayTiles(playerTiles, computerTiles [9]string) {
	fmt.Printf("☆プレイヤーの持ち牌⇒【%s】\n", formatTiles(playerTiles))
	fmt.Printf("コンピュータの持ち牌⇒【%s】\n", formatTiles(computerTiles))
}

この関数は、プレイヤーとコンピュータが持っている牌を表示する役割を持ちます。

[9]string は9つの文字列を持つ配列を表し、それをフォーマットして表示しています。

formatTiles 関数

func formatTiles(tiles [9]string) string {
	result := ""
	for i, tile := range tiles {
		if i > 0 {
			result += " ,"
		}
		result += tile
	}
	return result
}

formatTiles 関数は、配列の内容を表示用に整形します。配列の中の各要素を連結し、途中で「,」を挟むことで見やすく表示します。

displayScores 関数

func displayScores(playerScore, computerScore int) {
	fmt.Printf("プレイヤーの得点 : %d点\n", playerScore)
	fmt.Printf("コンピュータの得点: %d点\n", computerScore)
}

この関数は、プレイヤーとコンピュータの得点を表示します。%d は整数をフォーマットして表示するために使用します。

compareTiles 関数

func compareTiles(playerTile, computerTile int) (int, int) {
	// ...
}

この関数では、プレイヤーとコンピュータが出した牌を比較し、それに基づいて得点を計算します。

プレイヤーの牌が大きければプレイヤーに得点が入り、逆ならコンピュータに得点が入ります。同じ場合は両者に得点が加算されます。

main 関数

main 関数はGoプログラムのエントリーポイントです。ここでは、ゲームの進行全体を管理します。

rand.Seed(time.Now().UnixNano()) で乱数のシードを現在の時間で初期化し、ゲームでランダムな結果を生成できるようにしています。

プレイヤーとコンピュータの持ち牌の設定

playerTiles := [9]string{"1", "2", "3", "4", "5", "6", "7", "8", "9"}
computerTiles := [9]string{"1", "2", "3", "4", "5", "6", "7", "8", "9"}

プレイヤーとコンピュータの持ち牌を配列で設定します。それぞれ9つの牌(文字列)があり、ゲームを進めながらこの牌を使って得点を競います。

ラウンドのループ

for round := 1; round <= 9; round++ {
	// ...
}

ゲームは9回戦行われるため、このループは9回繰り返されます。各ラウンドではプレイヤーとコンピュータがそれぞれ1枚の牌を出します。

プレイヤーの入力処理

var playerChoiceStr string
var playerChoice int
for {
	fmt.Print("持ち牌の中から出す牌を選択してください > ")
	fmt.Scan(&playerChoiceStr)
	playerChoice, _ = strconv.Atoi(playerChoiceStr)
	if playerChoice >= 1 && playerChoice <= 9 && playerTiles[playerChoice-1] != "-" {
		break
	}
	fmt.Println("無効な入力です。もう一度選択してください。")
}

プレイヤーは牌を選択するため、キーボード入力で数字を入力します。strconv.Atoi で入力された文字列を整数に変換し、その入力が有効であるかをチェックします。

コンピュータのランダム選択

computerChoice = rand.Intn(9) + 1
if computerTiles[computerChoice-1] != "-" {
	break
}

コンピュータは乱数を使って牌をランダムに選びます。すでに使われた牌(”-” で表される)は選ばないようにしています。

得点の計算と表示

pScore, cScore := compareTiles(playerChoice, computerChoice)
playerScore += pScore
computerScore += cScore

各ラウンドごとにプレイヤーとコンピュータの得点が計算され、総得点に加算されます。

最終結果の表示

if playerScore > computerScore {
	fmt.Println("プレイヤーの勝利です!")
} else if playerScore < computerScore {
	fmt.Println("コンピュータの勝利です!")
} else {
	fmt.Println("引き分けです!")
}

ゲームが終了したら、最終的な得点に基づいて勝者を判定し、結果を表示します。

<<前の問題 問題集Top 次の問題>>

この問題への質問・コメント

この問題を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    Go練習問題集へ戻る
    トップページへ戻る