diff --git a/src/containers/ruby-tab/koshien-snippets.json b/src/containers/ruby-tab/koshien-snippets.json new file mode 100644 index 00000000000..13f63e9497b --- /dev/null +++ b/src/containers/ruby-tab/koshien-snippets.json @@ -0,0 +1,78 @@ +{ + "koshien.move_to": { + "snippet": "koshien.move_to([${1:0},${2:0}])", + "description": "x座標 (0) y座標 (0) に移動する" + }, + "koshien.get_map_area": { + "snippet": "koshien.get_map_area([${1:0},${2:0}])", + "description": "x座標 (0) y座標 (0) 付近のマップ情報を取得" + }, + "koshien.calc_route": { + "snippet": "koshien.calc_route(src:'${1:0:0}',dst:'${2:0:0}' except_cells:${3:1}])", + "description": "2点間の最短距離 始点 x座標 (0) y座標 (0) 終点 x座標 (0) y座標 (0) 通らない道 リスト (0)" + }, + "koshien.set_dynamite": { + "snippet": "koshien.set_dynamite([${1:0},${2:0}])", + "description": "ダイナマイトをx座標 (0) y座標 (0) に置く" + }, + "koshien.set_bomb": { + "snippet": "koshien.set_bomb([${1:0},${2:0}])", + "description": "爆弾をx座標 (0) y座標 (0) に置く" + }, + "koshien.map": { + "snippet": "koshien.map(${1:0},${2:0} on:${3:'map_1'})", + "description": "x座標 (0) y座標 (0) のマップ情報を('map_1')に保存" + }, + "koshien.map_all": { + "snippet": "koshien.map_all(save_as:${'map_1'})", + "description": "マップ情報を('map_1')に保存" + }, + "koshien.other_player_x": { + "snippet": "koshien.other_player_x", + "description": "対戦キャラクタの x座標" + }, + "koshien.other_player_y": { + "snippet": "koshien.other_player_y", + "description": "対戦キャラクタの y座標" + }, + "koshien.player_x": { + "snippet": "koshien.player_x", + "description": "プレイヤーの x座標" + }, + "koshien.player_y": { + "snippet": "koshien.player_y", + "description": "プレイヤーの y座標" + }, + "koshien.enemy_x": { + "snippet": "koshien.enemy_x", + "description": "妨害キャラクタの x座標" + }, + "koshien.enemy_y": { + "snippet": "koshien.enemy_y", + "description": "妨害キャラクタの y座標" + }, + "koshien.goal_x": { + "snippet": "koshien.goal_x", + "description": "ゴールの x座標" + }, + "koshien.goal_y": { + "snippet": "koshien.goal_y", + "description": "ゴールの y座標" + }, + "koshien.turn_over": { + "snippet": "koshien.turn_over", + "description": "ターンを終了する" + }, + "koshien.connect_game": { + "snippet": "koshien.connect_game(player_name:${1:'test'})", + "description": "プレイヤー名('test')ゲームに接続する" + }, + "koshien.position_x": { + "snippet": "koshien.position_x(${1:'0:0'})", + "description": "('0:0')のx座標" + }, + "koshien.position_y": { + "snippet": "koshien.position_y(${1:'0:0'})", + "description": "('0:0')のy座標" + } +} \ No newline at end of file diff --git a/src/containers/ruby-tab/snippets-completer.js b/src/containers/ruby-tab/snippets-completer.js index 4df893ea11e..506e4372f29 100644 --- a/src/containers/ruby-tab/snippets-completer.js +++ b/src/containers/ruby-tab/snippets-completer.js @@ -19,7 +19,7 @@ import MicrobitSnippets from './microbit-snippets.json'; import MeshSnippets from './mesh-snippets.json'; import SmalrubotS1Snippets from './smalrubot-s1-snippets.json'; import MicrobitMoreSnippets from './microbit-more-snippets.json'; - +import KoshienSnippets from './koshien-snippets.json'; class SnippetsCompleter extends BaseCompleter { #completions = []; @@ -45,7 +45,8 @@ class SnippetsCompleter extends BaseCompleter { MicrobitSnippets, MeshSnippets, SmalrubotS1Snippets, - MicrobitMoreSnippets + MicrobitMoreSnippets, + KoshienSnippets ]; snippetsList.forEach(snippets => { for (const [caption, item] of Object.entries(snippets)) { diff --git a/src/lib/libraries/extensions/index.jsx b/src/lib/libraries/extensions/index.jsx index 8b05eb7672a..9fbcbfc744f 100644 --- a/src/lib/libraries/extensions/index.jsx +++ b/src/lib/libraries/extensions/index.jsx @@ -396,6 +396,26 @@ const extensions = [ /> ), helpLink: 'https://github.com/smalruby/smalruby3-gui/wiki/SmalrubotS1' + }, + { + name: ( + + ), + extensionId: 'koshien', + iconURL: musicIconURL, + insetIconURL: musicInsetIconURL, + description: ( + + ), + featured: true } ]; diff --git a/src/lib/ruby-generator/index.js b/src/lib/ruby-generator/index.js index 8fd3689ad44..624394daefb 100644 --- a/src/lib/ruby-generator/index.js +++ b/src/lib/ruby-generator/index.js @@ -30,6 +30,7 @@ import WeDo2Blocks from './wedo2.js'; import GdxForBlocks from './gdx_for.js'; import MeshBlocks from './mesh.js'; import SmalrubotS1Blocks from './smalrubot_s1.js'; +import koshien from './koshien.js'; const SCALAR_TYPE = ''; const LIST_TYPE = 'list'; @@ -462,5 +463,6 @@ WeDo2Blocks(RubyGenerator); GdxForBlocks(RubyGenerator); MeshBlocks(RubyGenerator); SmalrubotS1Blocks(RubyGenerator); +koshien(RubyGenerator); export default RubyGenerator; diff --git a/src/lib/ruby-generator/koshien.js b/src/lib/ruby-generator/koshien.js new file mode 100644 index 00000000000..f9223037f15 --- /dev/null +++ b/src/lib/ruby-generator/koshien.js @@ -0,0 +1,70 @@ +/** + * Define Ruby code generator for Microbit More Blocks + * @param {RubyGenerator} Generator The RubyGenerator + * @return {RubyGenerator} same as param. + */ + +export default function (Generator) { + Generator.koshien_move_to = function (block) { + const x = Generator.valueToCode(block, 'X', Generator.ORDER_NONE) || 0; + const y = Generator.valueToCode(block, 'Y', Generator.ORDER_NONE) || 0; + return `koshien.move_to([${x},${y}])\n`; + }; + Generator.koshien_calc_route = function (block) { + const src_x = Generator.valueToCode(block, 'SRC_X', Generator.ORDER_NONE) || 0; + const src_y = Generator.valueToCode(block, 'SRC_Y', Generator.ORDER_NONE) || 0; + const dst_x = Generator.valueToCode(block, 'DST_X', Generator.ORDER_NONE) || 0; + const dst_y = Generator.valueToCode(block, 'DST_Y', Generator.ORDER_NONE) || 0; + const list = Generator.valueToCode(block, 'LIST', Generator.ORDER_NONE) || 0; + + return [`koshien.calc_route(src:"${src_x}:${src_y}",dst:"${dst_x}:${dst_y}",except_cells:${list})`]; + }; + Generator.koshien_get_map_area = function (block) { + const x = Generator.valueToCode(block, 'X', Generator.ORDER_NONE) || 0; + const y = Generator.valueToCode(block, 'Y', Generator.ORDER_NONE) || 0; + return `koshien.get_map_area([${x},${y}])\n`; + }; + Generator.koshien_set_item = function (block) { + const item = Generator.getFieldValue(block, 'ITEM') || null; + const x = Generator.valueToCode(block, 'X', Generator.ORDER_NONE) || 0; + const y = Generator.valueToCode(block, 'Y', Generator.ORDER_NONE) || 0; + return `koshien.set_${item}([${x},${y}])\n`; + }; + Generator.koshien_map = function (block) { + const x = Generator.valueToCode(block, 'X', Generator.ORDER_NONE) || 0; + const y = Generator.valueToCode(block, 'Y', Generator.ORDER_NONE) || 0; + const location = Generator.valueToCode(block, 'LOCATION', Generator.ORDER_NONE) || Generator.quote_('map_1'); + return [`koshien.map(${x},${y}, on: ${location})`]; + }; + Generator.koshien_map_all = function (block) { + const location = Generator.valueToCode(block, 'LOCATION', Generator.ORDER_NONE) || Generator.quote_('map_1'); + return [`koshien.map_all(save_as: ${location})`]; + }; + Generator.koshien_locate_objects = function (block) { + const x = Generator.valueToCode(block, 'X', Generator.ORDER_NONE) || 0; + const y = Generator.valueToCode(block, 'Y', Generator.ORDER_NONE) || 0; + const size = Generator.valueToCode(block, 'SIZE', Generator.ORDER_NONE) || 5; + const item = Generator.valueToCode(block, 'ITEM', Generator.ORDER_NONE) || Generator.quote_('["A","B","C","D"]'); + + return [`koshien.locate_objects(sq_size:${size},cent:"${x}:${y}",objects:${item})`]; + }; + Generator.koshien_target_coordinate = function (block) { + const target = Generator.getFieldValue(block, 'TARGET') || null; + const coordinate = Generator.getFieldValue(block, 'COORDINATE') || null; + return [`koshien.${target}_${coordinate}`]; + }; + Generator.koshien_turn_over = function () { + return `koshien.turn_over\n`; + }; + Generator.koshien_connect_game = function (block) { + const name = Generator.valueToCode(block, 'NAME', Generator.ORDER_NONE) || Generator.quote_('test'); + return `koshien.connect_game(player_name:${name})\n`; + }; + Generator.koshien_position_coordinate = function (block) { + const where = Generator.valueToCode(block, 'WHERE', Generator.ORDER_NONE) || Generator.quote_('0:0'); + const coordinate = Generator.getFieldValue(block, 'COORDINATE') || null; + return [`koshien.position_${coordinate}(${where})`]; + }; + + return Generator; +} diff --git a/src/lib/ruby-to-blocks-converter/index.js b/src/lib/ruby-to-blocks-converter/index.js index 6082d5a98e8..ae45c71a2f8 100644 --- a/src/lib/ruby-to-blocks-converter/index.js +++ b/src/lib/ruby-to-blocks-converter/index.js @@ -33,6 +33,7 @@ import TranslateConverter from './translate'; import MakeyMakeyConverter from './makeymakey'; import VideoConverter from './video'; import Text2SpeechConverter from './text2speech'; +import KoshienConverter from './koshien'; const messages = defineMessages({ couldNotConvertPrimitive: { @@ -113,7 +114,8 @@ class RubyToBlocksConverter { Text2SpeechConverter, Wedo2Converter, MicrobitMoreConverter, - MeshConverter + MeshConverter, + KoshienConverter ].forEach(x => x.register(this)); } diff --git a/src/lib/ruby-to-blocks-converter/koshien.js b/src/lib/ruby-to-blocks-converter/koshien.js new file mode 100644 index 00000000000..1af4fa0704c --- /dev/null +++ b/src/lib/ruby-to-blocks-converter/koshien.js @@ -0,0 +1,215 @@ +import {a} from 'bowser'; + +const Koshien = 'koshien'; + +const KoshienConverter = { + register: function (converter) { + converter.registerCallMethod('self', Koshien, 0, params => { + const {node} = params; + + return converter.createRubyExpressionBlock(Koshien, node); + }); + + converter.registerCallMethod(Koshien, 'move_to', 1, params => { + const {receiver, args} = params; + + if (!converter.isNumberOrBlock(args[0].value[0])) return null; + if (!converter.isNumberOrBlock(args[0].value[1])) return null; + + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_move_to', 'statement'); + converter.addNumberInput(block, 'X', 'math_number', args[0].value[0], 0); + converter.addNumberInput(block, 'Y', 'math_number', args[0].value[1], 0); + return block; + }); + converter.registerCallMethod(Koshien, 'calc_route', 1, params => { + const {receiver, args} = params; + + if (!converter.isStringOrBlock(args[0].get('sym:src').value)) return null; + if (!converter.isStringOrBlock(args[0].get('sym:dst').value)) return null; + if (!converter.isNumberOrBlock(args[0].get('sym:except_cells').value)) return null; + + const src = args[0].get('sym:src').value.split(':'); + const dst = args[0].get('sym:dst').value.split(':'); + + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_calc_route', 'value'); + converter.addNumberInput(block, 'SRC_X', 'math_number', Number(src[0]), 0); + converter.addNumberInput(block, 'SRC_Y', 'math_number', Number(src[1]), 0); + converter.addNumberInput(block, 'DST_X', 'math_number', Number(dst[0]), 0); + converter.addNumberInput(block, 'DST_Y', 'math_number', Number(dst[1]), 0); + converter.addNumberInput(block, 'LIST', 'math_number', Number(args[0].get('sym:except_cells')), 0); + return block; + }); + converter.registerCallMethod(Koshien, 'get_map_area', 1, params => { + const {receiver, args} = params; + + if (!converter.isNumberOrBlock(args[0].value[0])) return null; + if (!converter.isNumberOrBlock(args[0].value[1])) return null; + + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_get_map_area', 'statement'); + converter.addNumberInput(block, 'X', 'math_number', args[0].value[0], 0); + converter.addNumberInput(block, 'Y', 'math_number', args[0].value[1], 0); + return block; + }); + converter.registerCallMethod(Koshien, 'set_dynamite', 1, params => { + const {receiver, args} = params; + + if (!converter.isNumberOrBlock(args[0].value[0])) return null; + if (!converter.isNumberOrBlock(args[0].value[1])) return null; + + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_set_item', 'statement'); + converter.addField(block, 'ITEM', 'dynamite'); + converter.addNumberInput(block, 'X', 'math_number', args[0].value[0], 0); + converter.addNumberInput(block, 'Y', 'math_number', args[0].value[1], 0); + return block; + }); + converter.registerCallMethod(Koshien, 'set_bomb', 1, params => { + const {receiver, args} = params; + + if (!converter.isNumberOrBlock(args[0].value[0])) return null; + if (!converter.isNumberOrBlock(args[0].value[1])) return null; + + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_set_item', 'statement'); + converter.addField(block, 'ITEM', 'bomb'); + converter.addNumberInput(block, 'X', 'math_number', args[0].value[0], 0); + converter.addNumberInput(block, 'Y', 'math_number', args[0].value[1], 0); + return block; + }); + converter.registerCallMethod(Koshien, 'map', 3, params => { + const {receiver, args} = params; + + const location = args[2].get('sym:on').value; + + if (!converter.isNumberOrBlock(args[0])) return null; + if (!converter.isNumberOrBlock(args[1])) return null; + if (!converter.isStringOrBlock(location)) return null; + + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_map', 'value'); + converter.addNumberInput(block, 'X', 'math_number', args[0], 0); + converter.addNumberInput(block, 'Y', 'math_number', args[1], 0); + converter.addNumberInput(block, 'LOCATION', location, 0); + + return block; + }); + converter.registerCallMethod(Koshien, 'map_all', 1, params => { + const {receiver, args} = params; + + const location = args[0].get('sym:save_as').value; + if (!converter.isStringOrBlock(location)) return null; + + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_map_all', 'statement'); + converter.addTextInput(block, 'LOCATION', location, 'map_1'); + return block; + }); + converter.registerCallMethod(Koshien, 'locate_objects', 1, params => { + const {receiver, args} = params; + + const sq_size = args[0].get('sym:sq_size').value; + const cent = args[0].get('sym:cent').value; + const objects = args[0].get('sym:objects').value; + + if (!converter.isNumberOrBlock(sq_size)) return null; + if (!converter.isStringOrBlock(cent)) return null; + if (!converter.isStringOrBlock(objects)) return null; + + const cent_coordinate = cent.split(':'); + + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_locate_objects', 'value'); + converter.addNumberInput(block, 'SIZE', 'math_number', sq_size, 0); + converter.addNumberInput(block, 'X', 'math_number', Number(cent_coordinate[0]), 0); + converter.addNumberInput(block, 'Y', 'math_number', Number(cent_coordinate[1]), 0); + converter.addTextInput(block, 'ITEM', objects, '0'); + return block; + }); + converter.registerCallMethod(Koshien, 'other_player_x', 0, params => { + const {receiver} = params; + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_target_coordinate', 'value'); + converter.addField(block, 'TARGET', 'other_player'); + converter.addField(block, 'COORDINATE', 'x'); + return block; + }); + converter.registerCallMethod(Koshien, 'other_player_y', 0, params => { + const {receiver} = params; + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_target_coordinate', 'value'); + converter.addField(block, 'TARGET', 'other_player'); + converter.addField(block, 'COORDINATE', 'y'); + return block; + }); + converter.registerCallMethod(Koshien, 'enemy_x', 0, params => { + const {receiver} = params; + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_target_coordinate', 'value'); + converter.addField(block, 'TARGET', 'enemy'); + converter.addField(block, 'COORDINATE', 'x'); + return block; + }); + converter.registerCallMethod(Koshien, 'enemy_y', 0, params => { + const {receiver} = params; + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_target_coordinate', 'value'); + converter.addField(block, 'TARGET', 'enemy'); + converter.addField(block, 'COORDINATE', 'y'); + return block; + }); + converter.registerCallMethod(Koshien, 'goal_x', 0, params => { + const {receiver} = params; + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_target_coordinate', 'value'); + converter.addField(block, 'TARGET', 'goal'); + converter.addField(block, 'COORDINATE', 'x'); + return block; + }); + converter.registerCallMethod(Koshien, 'goal_y', 0, params => { + const {receiver} = params; + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_target_coordinate', 'value'); + converter.addField(block, 'TARGET', 'goal'); + converter.addField(block, 'COORDINATE', 'y'); + return block; + }); + converter.registerCallMethod(Koshien, 'player_x', 0, params => { + const {receiver} = params; + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_target_coordinate', 'value'); + converter.addField(block, 'TARGET', 'player'); + converter.addField(block, 'COORDINATE', 'x'); + return block; + }); + converter.registerCallMethod(Koshien, 'player_y', 0, params => { + const {receiver} = params; + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_target_coordinate', 'value'); + converter.addField(block, 'TARGET', 'player'); + converter.addField(block, 'COORDINATE', 'y'); + return block; + }); + converter.registerCallMethod(Koshien, 'turn_over', 0, params => { + const {receiver} = params; + return converter.changeRubyExpressionBlock(receiver, 'koshien_turn_over', 'value'); + }); + converter.registerCallMethod(Koshien, 'connect_game', 1, params => { + const {receiver, args} = params; + + const name = args[0].get('sym:player_name').value; + if (!converter.isStringOrBlock(name)) return null; + + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_connect_game', 'statement'); + converter.addTextInput(block, 'NAME', name, 'test'); + return block; + }); + converter.registerCallMethod(Koshien, 'position_x', 1, params => { + const {receiver, args} = params; + + if (!converter.isStringOrBlock(args[0])) return null; + + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_position_coordinate', 'value'); + converter.addTextInput(block, 'WHERE', args[0], '4:3'); + converter.addField(block, 'COORDINATE', 'x'); + return block; + }); + converter.registerCallMethod(Koshien, 'position_y', 1, params => { + const {receiver, args} = params; + + if (!converter.isStringOrBlock(args[0])) return null; + + const block = converter.changeRubyExpressionBlock(receiver, 'koshien_position_coordinate', 'value'); + converter.addTextInput(block, 'WHERE', args[0], '0:0'); + converter.addField(block, 'COORDINATE', 'y'); + return block; + }); + } +}; +export default KoshienConverter;