Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified apps/api/lambda.zip
Binary file not shown.
43 changes: 32 additions & 11 deletions apps/api/src/lambda/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,33 @@ import {
import { z } from "zod";

/* ======================
* 入力(solveActionのデモ用)
* Chess Piece Types
* ====================== */
const SolveActionInputSchema = z.object({
from: z.string().regex(/^[a-h][1-8]$/, "from must be like a1-h8"),
to: z.string().regex(/^[a-h][1-8]$/, "to must be like a1-h8"),
order: z.string().min(1), // デモ。後で enum にしてもOK
const SixtyFourPositionSchema = z.object({
x: z.number().optional(),
y: z.number().optional(),
z: z.number().optional(),
});
type SolveActionInput = z.infer<typeof SolveActionInputSchema>;

const PieceSchema = z.object({
id: z.int().min(0).max(31),
exist: z.boolean().default(true),
type: z.enum(["pawn", "rook", "knight", "bishop", "queen", "king"]),
color: z.enum(["white", "black"]),
position: SixtyFourPositionSchema,
});

/* ======================
* 入力(ResolveAction)
* ====================== */
const ResolveActionInputSchema = z.object({
piece_id: z.int().min(0).max(31),
pieces: z.array(PieceSchema),
from: z.string().regex(/^[a-h][1-8]$/, "Must be a valid chess position (e.g., 'g4')"),
to: z.string().regex(/^[a-h][1-8]$/, "Must be a valid chess position (e.g., 'f6')"),
order: z.string(),
});
type ResolveActionInput = z.infer<typeof ResolveActionInputSchema>;

/* ======================
* 出力(あなたの契約)
Expand Down Expand Up @@ -86,20 +105,22 @@ export const handler = async (event: {
typeof event.body === "string" ? JSON.parse(event.body) : (event.body ?? {});

// 2) 入力検証(ここが壊れてたら 400)
const input: SolveActionInput = SolveActionInputSchema.parse(rawBody);
const input: ResolveActionInput = ResolveActionInputSchema.parse(rawBody);

// 3) デモ用指示文:構造化を最優先で強制
// 盤面が無いので「入力の from/to をそのまま返す」方針にして安定させる
// 盤面情報(pieces)を含めてBedrockに渡す
const userText = [
`You must call the tool "solve_action".`,
`Do NOT output any plain text.`,
`This is a demo. Use the provided from/to as-is.`,
`Analyze the current board state and the user's command.`,
`Return {from,to,attack,reason} as tool arguments.`,
`Current pieces: ${JSON.stringify(input.pieces)}`,
`piece_id: ${input.piece_id}`,
`order: ${input.order}`,
`from: ${input.from}`,
`to: ${input.to}`,
`attack: set true only if you think this move captures (best-effort).`,
`reason: short reason.`,
`attack: set true only if this move captures an opponent's piece.`,
`reason: short reason for this action.`,
].join("\n");

const request: ConverseCommandInput = {
Expand Down
15 changes: 4 additions & 11 deletions apps/api/src/lib/create-game.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import {
type initGame,
type initGameResponse,
initGameResponseSchema,
} from "@repo/schema";
import { type initGame, type initGameResponse, initGameResponseSchema } from "@repo/schema";
import { DrizzleD1Database } from "drizzle-orm/d1";
import { games, personalitys } from "../db/schema";

export async function createGame(
gameData: initGame,
db: DrizzleD1Database
db: DrizzleD1Database,
): Promise<initGameResponse> {
try {
const result = await db
Expand All @@ -32,8 +28,7 @@ export async function createGame(

const randomPersonalitys = [];
for (let i = 0; i < 32; i++) {
randomPersonalitys[i] =
allPersonalitys[Math.floor(Math.random() * allPersonalitys.length)];
randomPersonalitys[i] = allPersonalitys[Math.floor(Math.random() * allPersonalitys.length)];
}

const response = initGameResponseSchema.parse({
Expand All @@ -43,9 +38,7 @@ export async function createGame(
return response;
} catch (error) {
throw new Error(
`Failed to create game: ${
error instanceof Error ? error.message : String(error)
}`
`Failed to create game: ${error instanceof Error ? error.message : String(error)}`,
);
}
}
41 changes: 19 additions & 22 deletions apps/api/src/lib/resolve-action.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,35 @@
import type { AIResponse, ResolveActionInput } from "@repo/schema";

export async function resolveAction(input: ResolveActionInput): Promise<AIResponse> {
const { from, to } = input;

const randomAttack = Math.random() < 0.5;

console.log("=== AWS API Call Start ===");
console.log("Input:", JSON.stringify(input, null, 2));

const res = await fetch(
"https://ue2gz6ytek.execute-api.ap-northeast-1.amazonaws.com/dev/v1/ai/solve/action",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ prompt: "テスト" }),
body: JSON.stringify({
piece_id: input.piece_id,
pieces: input.pieces,
from: input.from,
to: input.to,
order: input.order,
}),
},
);

console.log("Status:", res.status, res.statusText);
const responseData = await res.json();

if (!res.ok) {
const errorText = await res.text();
console.error("API Error:", errorText);
throw new Error(`API request failed: ${res.status} ${res.statusText}`);
}

const responseData: AIResponse = await res.json();
console.log("Response:", JSON.stringify(responseData, null, 2));
console.log("=== AWS API Call End ===");

const reasons = [
"王を守るための移動",
"相手の駒を攻撃",
"中央を制圧する",
"戦術的な配置",
"防御的な手",
"攻撃的な展開",
];
const randomReason = reasons[Math.floor(Math.random() * reasons.length)];

return {
from,
to,
attack: randomAttack,
reason: randomReason,
};
return responseData;
}
45 changes: 27 additions & 18 deletions apps/frontend/src/features/chess/api/chess.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
import { client } from "@/client";
import { handleResponse } from "@/lib/api-client";
import type {UsersResponse, Piece, AIResponse, initGame, initGameResponse } from "@repo/schema";
import type { UsersResponse, Piece, AIResponse, initGame, initGameResponse } from "@repo/schema";

export async function fetch(): Promise<UsersResponse> {
const response = await client.users.$get({});
return handleResponse<UsersResponse>(response);
}
const response = await client.users.$get({});
return handleResponse<UsersResponse>(response);
}

export async function resolveAction(pieces: Piece[], from: string, to: string, order: string): Promise<AIResponse> {
const response = await client.v1.resolveAction.$post({json : {
pieces: pieces,
from: from,
to: to,
order: order
}})
return handleResponse<AIResponse>(response);
export async function resolveAction(
pieces: Piece[],
from: string,
to: string,
order: string,
): Promise<AIResponse> {
const response = await client.v1.resolveAction.$post({
json: {
pieces: pieces,
from: from,
to: to,
order: order,
},
});
return handleResponse<AIResponse>(response);
}

export async function initGame(initData: initGame): Promise<initGameResponse> {
const response = await client.v1.createGame.$post({json: {
player_id: initData.player_id,
enemy_id: initData.enemy_id,
first_player: initData.first_player
}})
return handleResponse<initGameResponse>(response);
const response = await client.v1.createGame.$post({
json: {
player_id: initData.player_id,
enemy_id: initData.enemy_id,
first_player: initData.first_player,
},
});
return handleResponse<initGameResponse>(response);
}
6 changes: 3 additions & 3 deletions apps/frontend/src/features/chess/compomemt/ChessPieces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ const vectors = new Map<string, Position>([

function LinkVoiceAndId(
pieces: Piece[],
command: VoiceInput | null
command: VoiceInput | null,
): [Piece["id"], Position | null] {
if (!command) return [-1, null];

Expand All @@ -158,7 +158,7 @@ function LinkVoiceAndId(
(p) =>
p.position.x === fromPosition.x &&
p.position.y === fromPosition.y &&
p.position.z === fromPosition.z
p.position.z === fromPosition.z,
);

if (!piece) {
Expand All @@ -172,7 +172,7 @@ function LinkVoiceAndId(
function MoveCommand(
pieces: Piece[],
command: VoiceInput | null,
startAnimation: (id: number, from: Position, to: Position) => void
startAnimation: (id: number, from: Position, to: Position) => void,
): Piece[] {
const [pieceID, toPosition] = LinkVoiceAndId(pieces, command);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ const ChooseFromSixPieces = ({ piece }: ChessPieceProps) => {
groupRef.current.position.set(
animatingPiece.from.x!,
animatingPiece.from.y!,
animatingPiece.from.z!
animatingPiece.from.z!,
);
}
}, [isAnimating, animatingPiece]);
Expand All @@ -205,11 +205,7 @@ const ChooseFromSixPieces = ({ piece }: ChessPieceProps) => {
if (!groupRef.current) return;

if (isAnimating && animatingPiece) {
const target = new Vector3(
animatingPiece.to.x,
animatingPiece.to.y,
animatingPiece.to.z
);
const target = new Vector3(animatingPiece.to.x, animatingPiece.to.y, animatingPiece.to.z);

// 滑らかに移動(lerpの係数を調整で速度変更可能)
groupRef.current.position.lerp(target, 0.02);
Expand Down
3 changes: 1 addition & 2 deletions apps/frontend/src/features/chess/compomemt/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ interface AnimationState {

export const useTurnStore = create<TurnState>((set) => ({
turn: "white",
change: () =>
set((state) => ({ turn: state.turn === "white" ? "black" : "white" })),
change: () => set((state) => ({ turn: state.turn === "white" ? "black" : "white" })),
}));

export const useAnimationStore = create<AnimationState>((set) => ({
Expand Down
11 changes: 6 additions & 5 deletions apps/frontend/src/features/users/api/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ export async function fetchUsers(): Promise<UsersResponse> {
}

export async function createUsers(name: string): Promise<UsersResponse> {
const response = await client.v1.users.$post({json : {
name: name
}
})
const response = await client.v1.users.$post({
json: {
name: name,
},
});
return handleResponse<UsersResponse>(response);
}
}
1 change: 1 addition & 0 deletions packages/schema/src/resolve-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { PieceSchema } from "./chess";
* Input: { from: "g4", to: "f6", order: "命令" }
*/
export const ResolveActionInputSchema = z.object({
piece_id: z.int().min(0).max(31),
pieces: z.array(PieceSchema),
from: z.string().regex(/^[a-h][1-8]$/, "Must be a valid chess position (e.g., 'g4')"),
to: z.string().regex(/^[a-h][1-8]$/, "Must be a valid chess position (e.g., 'f6')"),
Expand Down